Skip to content

aes.c: extend GCM H-skip guard to cover WOLF_CRYPTO_CB_SETKEY#10580

Open
MarkAtwood wants to merge 1 commit into
wolfSSL:masterfrom
MarkAtwood:fix/aes-gcm-h-skip-wolf-crypto-cb-setkey
Open

aes.c: extend GCM H-skip guard to cover WOLF_CRYPTO_CB_SETKEY#10580
MarkAtwood wants to merge 1 commit into
wolfSSL:masterfrom
MarkAtwood:fix/aes-gcm-h-skip-wolf-crypto-cb-setkey

Conversation

@MarkAtwood
Copy link
Copy Markdown
Contributor

aes.c: extend GCM H-skip guard to cover WOLF_CRYPTO_CB_SETKEY

What

One-line fix at wolfcrypt/src/aes.c:7855: extend the existing
"SE owns key, skip H and M-table generation" guard from
#ifdef WOLF_CRYPTO_CB_AES_SETKEY to
#if defined(WOLF_CRYPTO_CB_AES_SETKEY) || defined(WOLF_CRYPTO_CB_SETKEY).

-#ifdef WOLF_CRYPTO_CB_AES_SETKEY
+#if defined(WOLF_CRYPTO_CB_AES_SETKEY) || defined(WOLF_CRYPTO_CB_SETKEY)
     if ((ret == 0) && (aes->devId != INVALID_DEVID && aes->devCtx != NULL)) {
         /* SE owns key - skip H and M table generation */
     }
     else
 #endif

Why

WOLF_CRYPTO_CB_AES_SETKEY is the older, AES-specific cryptocb
mechanism. WOLF_CRYPTO_CB_SETKEY is the newer generic SetKey
dispatch — a single hook handles AES, HMAC, ECC, and any future
algorithm via WC_SETKEY_AES, WC_SETKEY_HMAC, etc. tags
(cryptocb.c:2615, cryptocb.h::wc_SetKeyType).

For AES specifically, both mechanisms have identical semantics: when
the registered callback successfully imports the key into a secure
element, wc_AesSetKey returns 0 without populating the software key
schedule (aes->rounds, aes->keylen, expanded key bytes). The SE
owns the key; software state is intentionally left empty.

wc_AesGcmSetKey then needs to generate the GCM hash subkey H and
(when enabled) the M0 table. The existing path at aes.c:7861-7900
does this by calling wc_AesEncrypt(aes, iv_zeros, aes->gcm.H). But
wc_AesEncrypt checks the rounds count at aes.c:3148 and bails
with KEYUSAGE_E (-226) if aes->rounds == 0. The H/M-skip guard at
line 7855 exists precisely to avoid this dead-end.

The bug: that guard only checks the AES-specific macro. Any port using
the generic WOLF_CRYPTO_CB_SETKEY mechanism — the wolfSSL-recommended
direction for new ports — falls through to the broken path and gets
-226 on every wc_AesGcmSetKey call.

Discovery

I hit this while bringing up a Caliptra (CHIPS Alliance hardware Root
of Trust) cryptocb port that uses WOLF_CRYPTO_CB_SETKEY. The Caliptra
port is on a separate branch and PR; this one-line fix is the
prerequisite that should land first.

Compatibility

  • No behavior change for builds that don't define either macro.
  • No behavior change for builds that only define
    WOLF_CRYPTO_CB_AES_SETKEY (the existing condition still triggers
    via the left operand of the ||).
  • New behavior only when WOLF_CRYPTO_CB_SETKEY is defined AND a
    cryptocb is registered AND devId != INVALID_DEVID AND devCtx != NULL AND the callback returned success — i.e., exactly the case
    that's currently broken.

Testing

Three configurations verified, all 0 FAIL:

Config Result
./configure && make check 5 PASS, 4 SKIP, 0 FAIL
./configure --enable-cryptocb CFLAGS=-DWOLF_CRYPTO_CB_SETKEY && make check 5 PASS, 4 SKIP, 0 FAIL
./configure --enable-all && make check 17 PASS, 5 SKIP, 0 FAIL

The 4-5 SKIPs across configurations are all network/external-dep
(openssl interop, google.com TLS, etc.) — standard for offline CI.

A full end-to-end demonstration that this enables HW-offloaded GCM via
WOLF_CRYPTO_CB_SETKEY is in the Caliptra port branch (separate PR);
that branch with this fix applied passes 12 caliptra subtests
including AES-GCM round-trip, KAT, and authentication-failure
detection through the SetKey-dispatched path.

The existing guard in wc_AesGcmSetKey at aes.c:7855 says "if the SE
owns the key, skip software-side H subkey and M-table generation,"
gated on WOLF_CRYPTO_CB_AES_SETKEY.  Add WOLF_CRYPTO_CB_SETKEY to
the same guard so generic SetKey cryptocb users get the same
treatment.

Without this change, a port that registers a generic SetKey callback
(WOLF_CRYPTO_CB_SETKEY) and successfully imports an AES key into a
secure element returns success from wc_AesSetKey without populating
the software key schedule.  wc_AesGcmSetKey then calls
wc_AesEncrypt(aes, iv, aes->gcm.H) which checks 'r > 7 || r == 0'
on aes->rounds and bails with KEYUSAGE_E (-226).  Result: AES-GCM
cannot be offloaded via the generic SetKey cryptocb at all.

The WOLF_CRYPTO_CB_AES_SETKEY (AES-specific) path already handles
this case correctly.  WOLF_CRYPTO_CB_SETKEY is the newer generic
dispatch (single hook for AES, HMAC, ECC, and future algorithms);
any port adopting it hits the same condition for GCM and needs the
same skip behavior.

No behavior change for builds that don't define either macro, or for
builds that only define WOLF_CRYPTO_CB_AES_SETKEY.

Verified:
- ./configure && make && make check
  5 PASS, 4 SKIP, 0 FAIL
- ./configure --enable-cryptocb CFLAGS=-DWOLF_CRYPTO_CB_SETKEY &&
  make && make check
  5 PASS, 4 SKIP, 0 FAIL
- ./configure --enable-all && make && make check
  22 TOTAL, 17 PASS, 5 SKIP, 0 FAIL
Copilot AI review requested due to automatic review settings June 2, 2026 23:22
@MarkAtwood
Copy link
Copy Markdown
Contributor Author

Discovered while bringing up the Caliptra cryptocb port; that work is in draft PR #10579 (held until this lands).

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Extends the AES-GCM key-setup CryptoCB guard in wc_AesGcmSetKey() so that secure-element offload using the newer generic WOLF_CRYPTO_CB_SETKEY path skips software H/M-table generation (avoiding failure when the software key schedule is intentionally left unset).

Changes:

  • Expand the existing “SE owns key, skip H/M generation” preprocessor guard from WOLF_CRYPTO_CB_AES_SETKEY to also include WOLF_CRYPTO_CB_SETKEY.
Comments suppressed due to low confidence (1)

wolfcrypt/src/aes.c:7859

  • With WOLF_CRYPTO_CB_SETKEY builds where the SetKey callback offloads the key into a secure element (ret==0, devId valid, devCtx non-NULL), this new guard correctly skips software H/M-table generation. However, later in wc_AesGcmSetKey the raw key is still copied into aes->devKey unless WOLF_CRYPTO_CB_AES_SETKEY is defined, which leaves key material in process memory even though devCtx indicates the SE owns the key. Consider extending the later "SE owns key - don't copy to devKey" conditional to also cover WOLF_CRYPTO_CB_SETKEY so SE-owned keys aren’t persisted in aes->devKey.
#if defined(WOLF_CRYPTO_CB_AES_SETKEY) || defined(WOLF_CRYPTO_CB_SETKEY)
    if ((ret == 0) && (aes->devId != INVALID_DEVID && aes->devCtx != NULL)) {
        /* SE owns key - skip H and M table generation */
    }
    else

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread wolfcrypt/src/aes.c
Comment on lines +7855 to 7858
#if defined(WOLF_CRYPTO_CB_AES_SETKEY) || defined(WOLF_CRYPTO_CB_SETKEY)
if ((ret == 0) && (aes->devId != INVALID_DEVID && aes->devCtx != NULL)) {
/* SE owns key - skip H and M table generation */
}
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 3, 2026

MemBrowse Memory Report

No memory changes detected for:

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants