Skip to content

Boundary checks + zeroization improvements. Fix ed25519 and ECC dispatchers. Make PKCS7 padding checks CT.#7

Merged
dgarske merged 15 commits into
wolfSSL:masterfrom
danielinux:fixes-20260323
Mar 23, 2026
Merged

Boundary checks + zeroization improvements. Fix ed25519 and ECC dispatchers. Make PKCS7 padding checks CT.#7
dgarske merged 15 commits into
wolfSSL:masterfrom
danielinux:fixes-20260323

Conversation

@danielinux

Copy link
Copy Markdown
Member

F/1188 - Guard PKCS7 CBC decrypt length underflow (8affc91)
F/1189 - Fix EdDSA PSA dispatch order (6dd7db7)
F/1196 - zero cipher context before free (3ba730c)
F/1197 - zero import buffer before free (66a24e6)
F/1198 - zeroize MAC context on abort (996cc15)
F/1190 - Dispatch Edwards key generation correctly (24bbd81)
F/1191 - Route Twisted Edwards public key export (168dcec)
F/1199 - Make CBC PKCS7 padding check constant time (cf32ac0)
F/1200 - Zero AEAD buffers on abort (f0965c7)
F/1201 - check TLS13 PRF length narrowing (52b036a)
F/1202 - zero MAC stack buffer on exit (9a01ef3)
F/1203 - Zero MAC verify stack buffer (dc92685)

Copilot AI review requested due to automatic review settings March 23, 2026 07:49

Copilot AI 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.

Pull request overview

This PR hardens the PSA engine against boundary/length issues and improves secret-handling by adding zeroization on abort/error paths, while also fixing Twisted Edwards (Ed25519/Ed448) dispatching and making CBC-PKCS7 padding validation constant-time.

Changes:

  • Add constant-time CBC-PKCS7 padding validation and fix CBC multipart decrypt length underflow handling.
  • Improve zeroization of sensitive buffers/contexts in cipher, MAC, AEAD, and key import/generation flows.
  • Fix Twisted Edwards (Ed25519/Ed448) dispatch ordering for sign/verify, key generation, and public key export; add regression tests.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
test/psa_server/psa_api_test.c Adds regression tests for PKCS7 multipart CBC decrypt and Twisted Edwards message-signing / public-key export.
src/psa_tls_prf.c Adds size_t→word32 narrowing guards for TLS 1.3 PRF/HKDF inputs/outputs.
src/psa_mac.c Ensures stack buffers are zeroized on MAC finish/verify paths; zeroizes MAC context on abort.
src/psa_key_storage.c Zeroizes import buffer before free; routes Twisted Edwards keygen and public-key export via ED25519/ED448-specific implementations.
src/psa_cipher.c Prevents multipart underflow; implements constant-time CBC-PKCS7 padding checks; zeroizes cipher context on abort.
src/psa_asymmetric_api.c Fixes dispatch order so Twisted Edwards keys are handled before generic ECC sign/verify paths.
src/psa_aead.c Zeroizes AEAD AAD/input buffers before freeing on abort.
Comments suppressed due to low confidence (3)

src/psa_key_storage.c:1074

  • In psa_generate_key(), Twisted Edwards key generation is placed under #ifdef HAVE_ECC. This means ED25519/ED448 keypair generation will be unavailable (PSA_ERROR_NOT_SUPPORTED) in builds that enable HAVE_ED25519/HAVE_ED448 but not HAVE_ECC, even though EdDSA sign/verify paths are guarded only by HAVE_ED25519/HAVE_ED448 elsewhere. Consider loosening the compile-time guard to allow Twisted Edwards generation when the corresponding ED* feature macro is enabled (and returning NOT_SUPPORTED only when neither ECC nor ED* support is compiled in).
    if (PSA_KEY_TYPE_IS_ECC_KEY_PAIR(key_type)) {
#ifdef HAVE_ECC
        psa_ecc_family_t family = PSA_KEY_TYPE_ECC_GET_FAMILY(key_type);
        size_t priv_buf_size = PSA_KEY_EXPORT_ECC_KEY_PAIR_MAX_SIZE(key_bits);
        size_t pub_buf_size = PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(key_bits);
        size_t priv_len = 0;
        size_t pub_len = 0;
        uint8_t *pub_buf = NULL;

        key_data = (uint8_t *)XMALLOC(priv_buf_size, NULL,
                                      DYNAMIC_TYPE_TMP_BUFFER);
        if (key_data == NULL) {
            return PSA_ERROR_INSUFFICIENT_MEMORY;
        }
        pub_buf = (uint8_t *)XMALLOC(pub_buf_size, NULL,
                                     DYNAMIC_TYPE_TMP_BUFFER);
        if (pub_buf == NULL) {
            wc_ForceZero(key_data, priv_buf_size);
            XFREE(key_data, NULL, DYNAMIC_TYPE_TMP_BUFFER);
            return PSA_ERROR_INSUFFICIENT_MEMORY;
        }

        if (family == PSA_ECC_FAMILY_TWISTED_EDWARDS) {
#ifdef HAVE_ED25519
            if (key_bits == 255) {
                status = psa_asymmetric_generate_key_ed25519(key_type, key_bits,
                                                             key_data, priv_buf_size,
                                                             &priv_len,
                                                             pub_buf, pub_buf_size,
                                                             &pub_len);
            }
            else
#endif
#ifdef HAVE_ED448
            if (key_bits == 448) {
                status = psa_asymmetric_generate_key_ed448(key_type, key_bits,
                                                           key_data, priv_buf_size,
                                                           &priv_len,
                                                           pub_buf, pub_buf_size,
                                                           &pub_len);
            }
            else
#endif
            {
                status = PSA_ERROR_INVALID_ARGUMENT;
            }
        }
        else {
            status = psa_asymmetric_generate_key_ecc(key_type, key_bits,
                                                     key_data, priv_buf_size,
                                                     &priv_len,
                                                     pub_buf, pub_buf_size,
                                                     &pub_len);
        }
        XFREE(pub_buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
        if (status != PSA_SUCCESS) {
            wc_ForceZero(key_data, priv_buf_size);
            XFREE(key_data, NULL, DYNAMIC_TYPE_TMP_BUFFER);
            return status;
        }

        status = psa_import_key(attributes, key_data, priv_len, key_id);
        wc_ForceZero(key_data, priv_buf_size);
        XFREE(key_data, NULL, DYNAMIC_TYPE_TMP_BUFFER);
        return status;
#else
        return PSA_ERROR_NOT_SUPPORTED;
#endif

src/psa_key_storage.c:1478

  • psa_export_public_key()'s ECC handling is currently wrapped in #if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_EXPORT) && defined(HAVE_ECC_KEY_IMPORT), but the Twisted Edwards export path inside that block depends on HAVE_ED25519/HAVE_ED448, not on HAVE_ECC(_KEY_*). As written, ED25519/ED448 public key export will be compiled out (and return NOT_SUPPORTED) in configurations where EdDSA is enabled without ECC key import/export. Consider splitting the guard so Twisted Edwards public key export is enabled when HAVE_ED25519/HAVE_ED448 is set, and reserve the HAVE_ECC_KEY_* guard only for the Weierstrass ECC (x9.63) branch.
    #if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_EXPORT) && defined(HAVE_ECC_KEY_IMPORT)
        if (PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY(attributes.type)) {
            if (data_size < key_data_length) {
                status = PSA_ERROR_BUFFER_TOO_SMALL;
            }
            else {
                XMEMCPY(data, key_data, key_data_length);
                *data_length = key_data_length;
                status = PSA_SUCCESS;
            }
        }
        else {
            psa_ecc_family_t family = PSA_KEY_TYPE_ECC_GET_FAMILY(attributes.type);

            if (family == PSA_ECC_FAMILY_TWISTED_EDWARDS) {
            #ifdef HAVE_ED25519
                if (attributes.bits == 255) {
                    status = psa_asymmetric_export_public_key_ed25519(
                        attributes.type, attributes.bits, key_data,
                        key_data_length, data, data_size, data_length);
                }
                else
            #endif
            #ifdef HAVE_ED448
                if (attributes.bits == 448) {
                    status = psa_asymmetric_export_public_key_ed448(
                        attributes.type, attributes.bits, key_data,
                        key_data_length, data, data_size, data_length);
                }
                else
            #endif
                {
                    status = PSA_ERROR_NOT_SUPPORTED;
                }
            }
            else {
                ecc_key ecc;
                word32 out_len = (word32)data_size;
                int curve_id = wc_psa_get_ecc_curve_id(attributes.type,
                                                       attributes.bits);

                if (curve_id == ECC_CURVE_INVALID) {
                    status = PSA_ERROR_NOT_SUPPORTED;
                }
                else if (wc_ecc_init(&ecc) != 0) {
                    status = PSA_ERROR_INSUFFICIENT_MEMORY;
                }
                else {
                    ret = wc_ecc_import_private_key_ex(key_data,
                                                       (word32)key_data_length,
                                                       NULL, 0, &ecc, curve_id);
                    if (ret != 0) {
                        wc_ecc_free(&ecc);
                        status = psa_wc_error_to_psa_status(ret);
                    }
                    else {
                        ret = wc_ecc_make_pub_ex(&ecc, NULL, NULL);
                        if (ret != 0) {
                            wc_ecc_free(&ecc);
                            status = psa_wc_error_to_psa_status(ret);
                        }
                        else {
                            ret = wc_ecc_export_x963(&ecc, data, &out_len);
                            wc_ecc_free(&ecc);
                            if (ret != 0) {
                                status = psa_wc_error_to_psa_status(ret);
                            }
                            else {
                                *data_length = (size_t)out_len;
                                status = PSA_SUCCESS;
                            }
                        }
                    }
                }
            }
        }
    #else
        status = PSA_ERROR_NOT_SUPPORTED;
    #endif

src/psa_aead.c:856

  • psa_aead_abort() now zeroizes aad and input buffers before freeing, but the wolfpsa_aead_ctx_t itself (which contains the nonce and other operation state) is still freed without being scrubbed. For consistency with psa_cipher_abort() / psa_mac_abort() and to avoid leaving nonce/state in freed heap memory, wipe *ctx (and ideally clear operation->opaque) before XFREE(ctx, ...).
    if (ctx != NULL) {
        if (ctx->aad != NULL) {
            wc_ForceZero(ctx->aad, ctx->aad_length);
            XFREE(ctx->aad, NULL, DYNAMIC_TYPE_TMP_BUFFER);
        }
        if (ctx->input != NULL) {
            wc_ForceZero(ctx->input, ctx->input_length);
            XFREE(ctx->input, NULL, DYNAMIC_TYPE_TMP_BUFFER);
        }
        if (ctx->key != NULL) {
            wc_ForceZero(ctx->key, ctx->key_length);
            XFREE(ctx->key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
        }
        XFREE(ctx, NULL, DYNAMIC_TYPE_TMP_BUFFER);
        operation->opaque = (uintptr_t)NULL;
    }

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

Comment thread src/psa_cipher.c
Copilot AI review requested due to automatic review settings March 23, 2026 10:47

Copilot AI 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.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.


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

Comment thread src/psa_cipher.c Outdated
Comment thread src/psa_key_storage.c
Comment thread test/psa_server/psa_api_test.c
Comment thread src/psa_key_storage.c
@dgarske
dgarske merged commit cf25963 into wolfSSL:master Mar 23, 2026
4 checks passed
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.

3 participants