Skip to content

Xilinx asu ecc standalone - #11053

Open
night1rider wants to merge 1 commit into
wolfSSL:masterfrom
night1rider:Xilinx-ASU-ECC-standalone
Open

Xilinx asu ecc standalone#11053
night1rider wants to merge 1 commit into
wolfSSL:masterfrom
night1rider:Xilinx-ASU-ECC-standalone

Conversation

@night1rider

Copy link
Copy Markdown
Contributor

No description provided.

@night1rider night1rider self-assigned this Aug 4, 2026

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Fenrir Automated Review — PR #11053

Scan targets checked: wolfcrypt-port-bugs, wolfcrypt-rs-bugs, wolfssl-bugs, wolfssl-src

Findings: 2
2 finding(s) posted as inline comments (see file-level comments below)

This review was generated automatically by Fenrir. Findings are non-blocking.

Comment thread wolfcrypt/src/port/xilinx/versal_gen2_asu/asu_ecc.c
Comment thread wolfcrypt/src/port/xilinx/versal_gen2_asu/asu_ecc.c
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown

Comment thread wolfcrypt/src/port/xilinx/versal_gen2_asu/asu_ecc.c
Comment thread wolfcrypt/src/port/xilinx/versal_gen2_asu/asu_ecc.c
@night1rider
night1rider force-pushed the Xilinx-ASU-ECC-standalone branch from 2a34935 to db9d0e3 Compare August 11, 2026 19:26
Offload ECDSA/Ed25519/Ed448 sign/verify, ECDH, and ECIES (AES-GCM) to the
ASU via the wolfSSL crypto callback; add wc_ecc_ctx_get_mac_salt and the
ECC benchmark.

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Fenrir Automated Review — PR #11053

Scan targets checked: wolfcrypt-bugs, wolfcrypt-port-bugs, wolfcrypt-rs-bugs, wolfcrypt-src, wolfssl-bugs, wolfssl-src

Findings: 21
21 finding(s) posted as inline comments (see file-level comments below)

This review was generated automatically by Fenrir. Findings are non-blocking.

}

pubKeySz = 1U + (2U * (word32)keyLen); /* X9.63 uncompressed 0x04||Qx||Qy */
need = pubKeySz + (word32)WC_ASU_ECIES_NONCE_SZ + msgSz +

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔴 [High] ECIES offload hardcodes the WOLFSSL_ECIES_GEN_IV blob layout with no build guard · Missing/incorrect platform conditionals

The offload always embeds a 12-byte nonce between the ephemeral key and the ciphertext, but ecc_ecies_total_size() (ecc.c:15384) only includes the nonce when WOLFSSL_ECIES_GEN_IV is defined. In a default or WOLFSSL_ECIES_STATIC_GCM_NONCE build the hardware blob is 12 bytes longer than software's, and wc_AsuEciesDecrypt mis-slices software-produced blobs.

Fix: Add #ifndef WOLFSSL_ECIES_GEN_IV #error ... #endif (and reject WOLFSSL_ECIES_OLD) at the top of asu_ecies.c.

}

XMEMSET(req, 0, sizeof(*req));
if (mp_to_unsigned_bin_len(key->k, req->key, (int)keyLen) < 0) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟠 [Medium] ECDSA sign marshals the blinded private scalar key-k instead of ecc_get_k() · API contract violations

With WOLFSSL_ECC_BLIND_K, key->k holds k XOR kb (ecc.c:377-386) and the real scalar is only available via ecc_get_k()/wc_ecc_key_get_priv(), which every other port uses. The ASU is handed a masked scalar, so it silently produces invalid signatures; the mp_iszero(key->k) guard at line 236 is also meaningless under blinding.

Fix: Use wc_ecc_key_get_priv(key) in place of key->k for both the zero check and the export.


XMEMSET(req, 0, sizeof(*req));
/* Our private scalar d, and the peer public point Qx||Qy, each curve-width. */
if (mp_to_unsigned_bin_len(priv->k, req->privKey, (int)keyLen) < 0 ||

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟠 [Medium] ECDH marshals the blinded private scalar priv-k instead of ecc_get_k() · API contract violations

priv->k is the blinded scalar under WOLFSSL_ECC_BLIND_K (ecc.c:377-386), so the ASU computes the shared secret from a masked value and silently returns a secret that does not match the peer's.

Fix: Use wc_ecc_key_get_priv(priv) for both the mp_iszero/mp_unsigned_bin_size checks and the export.

XMEMSET(req, 0, sizeof(*req));

/* Our private scalar; the ephemeral public key comes straight from the blob. */
if (mp_to_unsigned_bin_len(privKey->k, req->rxKey, (int)keyLen) < 0) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟠 [Medium] ECIES decrypt marshals the blinded private scalar privKey-k instead of ecc_get_k() · API contract violations

privKey->k is the blinded scalar under WOLFSSL_ECC_BLIND_K (ecc.c:377-386), so the ASU derives the DEM key from a masked ECDH result and decryption fails for every message.

Fix: Use wc_ecc_key_get_priv(privKey) for both the mp_iszero check at line 389 and the export.


wc_AsuCacheInvalidate(out, ctLen);

if (status != XST_SUCCESS) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟠 [Medium] ECIES decrypt ignores the ASU AdditionalStatus tag verdict and leaves unauthenticated plaintext in out · Incorrect error handling

addl is collected from wc_AsuTransact but never inspected, unlike wc_AsuCipherGcm (asu_cipher.c:519-528) which requires addl == XASU_AES_TAG_MATCHED, zeroes out on mismatch, and returns AES_GCM_AUTH_E. A GCM tag failure here is either missed or reported as WC_HW_E, and the ASU-written plaintext stays in the caller's buffer.

Related known finding #6623 (similar but distinct): Both mishandle a hardware-operation result and can expose plaintext on failure, but this is ASU ECIES decrypt's ignored GCM tag verdict in wc_AsuEciesDecrypt, whereas #6623 is QAT's ignored synchronous perform-op status in IntelQaSymCipher. The faulting results, root checks, functions, and required patches differ.

Fix: Require the tag-matched AdditionalStatus alongside XST_SUCCESS, and on failure ForceZero out and return AES_GCM_AUTH_E.

/* WOLFSSL_BENCH_ECC_ALL: let a plain 'bench all' run sweep every
* compiled-in curve, not just P-256, so HW/SW compare across all. */
#ifdef WOLFSSL_BENCH_ECC_ALL
if ((bench_asym_algs & BENCH_ECC_ALL) || bench_all) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔵 [Low] WOLFSSL_BENCH_ECC_ALL drops all ECC benchmarks from a plain 'bench all' in FIPS builds · Logic errors

With WOLFSSL_BENCH_ECC_ALL defined, the default run (bench_all == 1, bench_asym_algs == 0) now enters the curve-sweep branch, which under HAVE_FIPS/HAVE_SELFTEST only prints "not supported in FIPS mode" and skips the else branch that used to benchmark P-256.

Fix: Gate the || bench_all term on !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST).

ret = WC_HW_E;
goto out;
}
XMEMCPY(req->txKey, msg + 1, 2U * (word32)keyLen);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔴 [High] ECIES decrypt offload skips validation of the attacker-supplied ephemeral public point · Cryptographic correctness

The ephemeral point is copied raw out of the ciphertext blob into req->txKey and handed to the ASU with no on-curve or point-at-infinity check. The software path it replaces validates the same point via wc_ecc_import_x963_ex (ecc.c:16104, "treat as untrusted"), so the offload exposes a static ECIES receiver key to invalid-curve and small-subgroup recovery using the GCM pass/fail oracle.

Fix: Import the ephemeral point with wc_ecc_import_x963_ex (or call wc_ecc_point_is_on_curve plus an infinity check) before submitting the request, declining on failure.

ret = 0;

out:
WC_FREE_VAR_EX(req, NULL, DYNAMIC_TYPE_TMP_BUFFER);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔵 [Low] ECDH private scalar and shared secret not scrubbed before free · Missing ForceZero

AsuEcdhReq holds the marshalled private scalar in req->privKey and the raw ECDH shared secret in req->secret. WC_FREE_VAR_EX is a plain XFREE (or a no-op on the stack variant), so both secrets survive in reusable memory; the PR's own wc_AsuEccSign scrubs its request with ForceZero first.

Related known finding #7437 (similar but distinct): Both free temporary private-key and shared-secret material without wiping it, but this is wc_AsuEcdh's ASU ECDH request object rather than IntelQaDhAgreeFree's QAT DH buffers. The operations, port-specific root paths, and required patches differ.

Fix: Add ForceZero(req, sizeof(*req)) before WC_FREE_VAR_EX at the out: label.

ret = 0;

out:
WC_FREE_VAR_EX(req, NULL, DYNAMIC_TYPE_TMP_BUFFER);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔵 [Low] ECIES decrypt leaves the ECC private scalar in freed memory · Missing ForceZero

privKey->k is marshalled into req->rxKey (line 445) and the request is released with WC_FREE_VAR_EX without zeroing, leaving the receiver's long-term ECC private key in reusable heap or stack memory on both the success and error paths.

Related known finding #4895 (similar but distinct): Both release a temporary buffer containing private-key material without zeroization, but this is marshalled ECIES receiver scalar data in wc_AsuEciesDecrypt rather than DER-decoded Falcon key bytes in wc_Falcon_PrivateKeyDecode. They have distinct operations, functions, and cleanup fixes.

Fix: Add ForceZero(req, sizeof(*req)) before WC_FREE_VAR_EX at the out: label.

}

pubKeySz = 1U + (2U * (word32)keyLen); /* X9.63 uncompressed 0x04||Qx||Qy */
need = pubKeySz + (word32)WC_ASU_ECIES_NONCE_SZ + msgSz +

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔵 [Low] ECIES offload hardcodes the GEN_IV blob layout, diverging from software in other IV modes · Cryptographic correctness

The offload always embeds and consumes a 12-byte GCM nonce in the blob. ecc_ecies_total_size (ecc.c:15384) includes the nonce only under WOLFSSL_ECIES_GEN_IV, so in a WOLFSSL_ECIES_STATIC_GCM_NONCE build an ASU-produced blob is undecryptable by wolfSSL software and vice versa, with no build-time guard rejecting the mismatch.

Fix: Gate the ECIES offload on WOLFSSL_ECIES_GEN_IV (returning CRYPTOCB_UNAVAILABLE otherwise) so the hardware and software wire formats always agree.

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