Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
30701ac
Add invalid signature verify coverage
danielinux Apr 22, 2026
bed6c06
Add ML-DSA invalid signature coverage
danielinux Apr 22, 2026
39956d1
Fix psa_copy_key type inheritance
danielinux Apr 22, 2026
141fdc2
Preserve volatile import store errors
danielinux Apr 22, 2026
98df05e
Abort failed persistent store writes
danielinux Apr 22, 2026
6019cd0
Reject invalid GCM AEAD tag lengths
danielinux Apr 22, 2026
9bbb382
Set HKDF default derivation capacity
danielinux Apr 22, 2026
f248c85
Reject 2-key 3DES imports
danielinux Apr 22, 2026
2a49b43
Test MAC verification failures
danielinux Apr 22, 2026
351ee43
Add usage policy negative PSA tests
danielinux Apr 22, 2026
7a8efee
Fix psa_key_agreement KDF dispatch
danielinux Apr 22, 2026
fbe5c8b
Support Montgomery PSA key operations
danielinux Apr 22, 2026
409226f
Fix RSA raw verify roundtrip buffer
danielinux Apr 22, 2026
7e9de67
Validate PBKDF2 int-sized arguments
danielinux Apr 22, 2026
6dd3343
Add ML-KEM word32 size guards
danielinux Apr 22, 2026
e83896d
Add EdDSA word32 size guards
danielinux Apr 22, 2026
03cc22e
Add raw key agreement size guards
danielinux Apr 22, 2026
daa919c
Enforce monotonic KDF capacity
danielinux Apr 22, 2026
f2ce25a
Require 12-byte GCM nonces
danielinux Apr 22, 2026
4366fe2
Test AEAD AES key type enforcement
danielinux Apr 22, 2026
e24cb2f
Test cipher AES key type enforcement
danielinux Apr 22, 2026
9c2a1fe
Accept longer at-least-length MACs
danielinux Apr 22, 2026
c2b66ca
Validate KDF verify length early
danielinux Apr 22, 2026
202f68e
Zero hash ctx on finish
danielinux Apr 22, 2026
3e19a3e
Reject unknown key usage bits on import
danielinux Apr 22, 2026
2b4a235
Handle zero-length KDF verify
danielinux Apr 22, 2026
456fe43
Fixed regressions in aes and mldsa tests
danielinux Apr 22, 2026
ea94250
Addressed copilot's comments
danielinux Apr 22, 2026
fddbc5a
Two test fixes: bad hardcoded AEAD nonce len, bad ed448 hash size
danielinux Apr 22, 2026
fd6e039
Addressed copilot's comment
danielinux Apr 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion src/psa_aead.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,14 @@ static size_t wolfpsa_aead_tag_length(psa_algorithm_t alg)
return PSA_ALG_AEAD_GET_TAG_LENGTH(alg);
}

#ifdef HAVE_AESGCM
static int wolfpsa_aead_gcm_check_tag_size(size_t tag_length)
{
return tag_length == 4 || tag_length == 8 ||
(tag_length >= 12 && tag_length <= WC_AES_BLOCK_SIZE);
}
#endif

static psa_status_t wolfpsa_aead_check_key(psa_key_id_t key,
psa_key_usage_t usage,
psa_algorithm_t alg,
Expand Down Expand Up @@ -262,6 +270,14 @@ static psa_status_t wolfpsa_aead_setup(psa_aead_operation_t *operation,
return PSA_ERROR_INVALID_ARGUMENT;
}
#endif
#ifdef HAVE_AESGCM
if (PSA_ALG_AEAD_EQUAL(alg, PSA_ALG_GCM) &&
!wolfpsa_aead_gcm_check_tag_size(ctx->tag_length)) {
wolfpsa_forcezero_free_key_data(key_data, key_data_length);
XFREE(ctx, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return PSA_ERROR_INVALID_ARGUMENT;
}
#endif

ctx->key = (uint8_t *)XMALLOC(key_data_length, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
Expand Down Expand Up @@ -333,7 +349,7 @@ psa_status_t psa_aead_set_nonce(psa_aead_operation_t *operation,
}

if (PSA_ALG_AEAD_EQUAL(ctx->alg, PSA_ALG_GCM)) {
if (nonce_length == 0 || nonce_length > PSA_AEAD_NONCE_MAX_SIZE) {
if (nonce_length < 12 || nonce_length > PSA_AEAD_NONCE_MAX_SIZE) {
return PSA_ERROR_INVALID_ARGUMENT;
}
}
Expand Down
20 changes: 20 additions & 0 deletions src/psa_asymmetric.c
Original file line number Diff line number Diff line change
Expand Up @@ -718,6 +718,26 @@ int wc_psa_get_ecc_curve_id(psa_key_type_t type, size_t bits)
default:
return ECC_CURVE_INVALID;
}

case PSA_ECC_FAMILY_MONTGOMERY:
switch (bits) {
case 255:
#ifdef HAVE_CURVE25519
return ECC_X25519;
#else
return ECC_CURVE_INVALID;
#endif

case 448:
#ifdef HAVE_CURVE448
return ECC_X448;
#else
return ECC_CURVE_INVALID;
#endif

default:
return ECC_CURVE_INVALID;
}

default:
return ECC_CURVE_INVALID;
Expand Down
84 changes: 83 additions & 1 deletion src/psa_asymmetric_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#if defined(WOLFSSL_PSA_ENGINE)

#include <psa/crypto.h>
#include "psa_size.h"
#include "psa_trace.h"
#include <wolfpsa/psa_engine.h>
#include <wolfpsa/psa_key_storage.h>
Expand All @@ -37,6 +38,29 @@

extern int wc_psa_get_ecc_curve_id(psa_key_type_t type, size_t bits);

#if defined(HAVE_CURVE25519) && defined(HAVE_CURVE25519_KEY_IMPORT) && \
defined(HAVE_CURVE25519_SHARED_SECRET)
psa_status_t psa_asymmetric_key_agreement_x25519(
const uint8_t *private_key,
size_t private_key_length,
const uint8_t *peer_key,
size_t peer_key_length,
uint8_t *output,
size_t output_size,
size_t *output_length);
#endif
#if defined(HAVE_CURVE448) && defined(HAVE_CURVE448_KEY_IMPORT) && \
defined(HAVE_CURVE448_SHARED_SECRET)
psa_status_t psa_asymmetric_key_agreement_x448(
const uint8_t *private_key,
size_t private_key_length,
const uint8_t *peer_key,
size_t peer_key_length,
uint8_t *output,
size_t output_size,
size_t *output_length);
#endif

psa_status_t psa_asymmetric_sign_rsa(psa_key_type_t key_type,
size_t key_bits,
const uint8_t *key_buffer,
Expand Down Expand Up @@ -665,6 +689,41 @@ psa_status_t psa_raw_key_agreement(psa_algorithm_t alg,
wolfpsa_forcezero_free_key_data(key_data, key_data_length);
return PSA_ERROR_INVALID_ARGUMENT;
}
if ((wolfpsa_check_word32_length(key_data_length) != PSA_SUCCESS) ||
(wolfpsa_check_word32_length(peer_key_length) != PSA_SUCCESS) ||
(wolfpsa_check_word32_length(output_size) != PSA_SUCCESS)) {
wolfpsa_forcezero_free_key_data(key_data, key_data_length);
return PSA_ERROR_INVALID_ARGUMENT;
}

if (PSA_KEY_TYPE_ECC_GET_FAMILY(attributes.type) ==
PSA_ECC_FAMILY_MONTGOMERY) {
if (attributes.bits == 255) {
#if defined(HAVE_CURVE25519) && defined(HAVE_CURVE25519_KEY_IMPORT) && \
defined(HAVE_CURVE25519_SHARED_SECRET)
status = psa_asymmetric_key_agreement_x25519(
key_data, key_data_length, peer_key, peer_key_length, output,
output_size, output_length);
#else
status = PSA_ERROR_NOT_SUPPORTED;
#endif
}
else if (attributes.bits == 448) {
#if defined(HAVE_CURVE448) && defined(HAVE_CURVE448_KEY_IMPORT) && \
defined(HAVE_CURVE448_SHARED_SECRET)
status = psa_asymmetric_key_agreement_x448(
key_data, key_data_length, peer_key, peer_key_length, output,
output_size, output_length);
#else
status = PSA_ERROR_NOT_SUPPORTED;
#endif
}
else {
status = PSA_ERROR_NOT_SUPPORTED;
}
wolfpsa_forcezero_free_key_data(key_data, key_data_length);
return status;
}

curve_id = wc_psa_get_ecc_curve_id(attributes.type, attributes.bits);
if (curve_id == ECC_CURVE_INVALID) {
Expand Down Expand Up @@ -782,7 +841,8 @@ psa_status_t psa_key_agreement(psa_key_id_t private_key,
return PSA_ERROR_INSUFFICIENT_MEMORY;
}

status = psa_raw_key_agreement(alg, private_key, peer_key, peer_key_length,
status = psa_raw_key_agreement(PSA_ALG_KEY_AGREEMENT_GET_BASE(alg),
private_key, peer_key, peer_key_length,
secret, secret_len, &output_len);
if (status != PSA_SUCCESS) {
wc_ForceZero(secret, secret_len);
Expand Down Expand Up @@ -813,6 +873,18 @@ psa_status_t psa_key_agreement(psa_key_id_t private_key,
return status;
}

if (PSA_ALG_IS_HKDF(kdf_alg) || PSA_ALG_IS_HKDF_EXTRACT(kdf_alg)) {
status = psa_key_derivation_input_bytes(&kdf_op,
PSA_KEY_DERIVATION_INPUT_SALT,
NULL, 0);
if (status != PSA_SUCCESS) {
wc_ForceZero(secret, secret_len);
XFREE(secret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
psa_key_derivation_abort(&kdf_op);
return status;
}
}

status = psa_key_derivation_input_bytes(&kdf_op, PSA_KEY_DERIVATION_INPUT_SECRET,
secret, output_len);
wc_ForceZero(secret, secret_len);
Expand All @@ -822,6 +894,16 @@ psa_status_t psa_key_agreement(psa_key_id_t private_key,
return status;
}

if (PSA_ALG_IS_HKDF(kdf_alg) || PSA_ALG_IS_HKDF_EXPAND(kdf_alg)) {
status = psa_key_derivation_input_bytes(&kdf_op,
PSA_KEY_DERIVATION_INPUT_INFO,
NULL, 0);
if (status != PSA_SUCCESS) {
psa_key_derivation_abort(&kdf_op);
return status;
}
}

status = psa_key_derivation_output_key(attributes, &kdf_op, key);
psa_key_derivation_abort(&kdf_op);
return status;
Expand Down
25 changes: 10 additions & 15 deletions src/psa_cipher.c
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,14 @@ static psa_status_t wolfpsa_cipher_check_key(
#endif

if (attributes->type == PSA_KEY_TYPE_DES) {
if (*key_data_length != 16 && *key_data_length != 24) {
if (*key_data_length == 16) {
wolfpsa_forcezero_free_key_data(*key_data, *key_data_length);
*key_data = NULL;
*key_data_length = 0;
return PSA_ERROR_NOT_SUPPORTED;
}

if (*key_data_length != 24) {
wolfpsa_forcezero_free_key_data(*key_data, *key_data_length);
*key_data = NULL;
*key_data_length = 0;
Expand Down Expand Up @@ -366,13 +373,7 @@ psa_status_t psa_cipher_encrypt_setup(psa_cipher_operation_t *operation,
#ifndef NO_DES3
byte des_key[DES3_KEY_SIZE];

if (key_data_length == 16) {
XMEMCPY(des_key, key_data, 16);
XMEMCPY(des_key + 16, key_data, 8);
}
else {
XMEMCPY(des_key, key_data, DES3_KEY_SIZE);
}
XMEMCPY(des_key, key_data, DES3_KEY_SIZE);

ret = wc_Des3Init(&ctx->des3, NULL, INVALID_DEVID);
if (ret != 0) {
Expand Down Expand Up @@ -515,13 +516,7 @@ psa_status_t psa_cipher_decrypt_setup(psa_cipher_operation_t *operation,
#ifndef NO_DES3
byte des_key[DES3_KEY_SIZE];

if (key_data_length == 16) {
XMEMCPY(des_key, key_data, 16);
XMEMCPY(des_key + 16, key_data, 8);
}
else {
XMEMCPY(des_key, key_data, DES3_KEY_SIZE);
}
XMEMCPY(des_key, key_data, DES3_KEY_SIZE);

ret = wc_Des3Init(&ctx->des3, NULL, INVALID_DEVID);
if (ret != 0) {
Expand Down
37 changes: 37 additions & 0 deletions src/psa_ed25519_ed448.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#if defined(WOLFSSL_PSA_ENGINE) && (defined(HAVE_ED25519) || defined(HAVE_ED448))

#include <psa/crypto.h>
#include "psa_size.h"
#include <wolfpsa/psa_engine.h>
#include <wolfssl/wolfcrypt/error-crypt.h>
#include <wolfssl/wolfcrypt/types.h>
Expand Down Expand Up @@ -70,6 +71,11 @@ psa_status_t psa_asymmetric_sign_ed25519(psa_key_type_t key_type,
key_bits != 255) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if ((wolfpsa_check_word32_length(key_buffer_size) != PSA_SUCCESS) ||
(wolfpsa_check_word32_length(hash_length) != PSA_SUCCESS) ||
(wolfpsa_check_word32_length(signature_size) != PSA_SUCCESS)) {
return PSA_ERROR_INVALID_ARGUMENT;
}

/* Initialize ED25519 key */
ret = wc_ed25519_init(&ed_key);
Expand Down Expand Up @@ -129,6 +135,11 @@ psa_status_t psa_asymmetric_verify_ed25519(psa_key_type_t key_type,
key_bits != 255) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if ((wolfpsa_check_word32_length(key_buffer_size) != PSA_SUCCESS) ||
(wolfpsa_check_word32_length(hash_length) != PSA_SUCCESS) ||
(wolfpsa_check_word32_length(signature_length) != PSA_SUCCESS)) {
return PSA_ERROR_INVALID_ARGUMENT;
}


/* Initialize ED25519 key */
Expand Down Expand Up @@ -193,6 +204,10 @@ psa_status_t psa_asymmetric_generate_key_ed25519(psa_key_type_t key_type,
key_bits != 255) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if ((wolfpsa_check_word32_length(private_key_size) != PSA_SUCCESS) ||
(wolfpsa_check_word32_length(public_key_size) != PSA_SUCCESS)) {
return PSA_ERROR_INVALID_ARGUMENT;
}

/* Initialize ED25519 key */
ret = wc_ed25519_init(&ed_key);
Expand Down Expand Up @@ -261,6 +276,10 @@ psa_status_t psa_asymmetric_export_public_key_ed25519(psa_key_type_t key_type,
key_bits != 255) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if ((wolfpsa_check_word32_length(key_buffer_size) != PSA_SUCCESS) ||
(wolfpsa_check_word32_length(output_size) != PSA_SUCCESS)) {
return PSA_ERROR_INVALID_ARGUMENT;
}

/* Initialize ED25519 key */
ret = wc_ed25519_init(&ed_key);
Expand Down Expand Up @@ -328,6 +347,11 @@ psa_status_t psa_asymmetric_sign_ed448(psa_key_type_t key_type,
key_bits != 448) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if ((wolfpsa_check_word32_length(key_buffer_size) != PSA_SUCCESS) ||
(wolfpsa_check_word32_length(hash_length) != PSA_SUCCESS) ||
(wolfpsa_check_word32_length(signature_size) != PSA_SUCCESS)) {
return PSA_ERROR_INVALID_ARGUMENT;
}

/* Initialize ED448 key */
ret = wc_ed448_init(&ed_key);
Expand Down Expand Up @@ -387,6 +411,11 @@ psa_status_t psa_asymmetric_verify_ed448(psa_key_type_t key_type,
key_bits != 448) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if ((wolfpsa_check_word32_length(key_buffer_size) != PSA_SUCCESS) ||
(wolfpsa_check_word32_length(hash_length) != PSA_SUCCESS) ||
(wolfpsa_check_word32_length(signature_length) != PSA_SUCCESS)) {
return PSA_ERROR_INVALID_ARGUMENT;
}


/* Initialize ED448 key */
Expand Down Expand Up @@ -450,6 +479,10 @@ psa_status_t psa_asymmetric_generate_key_ed448(psa_key_type_t key_type,
key_bits != 448) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if ((wolfpsa_check_word32_length(private_key_size) != PSA_SUCCESS) ||
(wolfpsa_check_word32_length(public_key_size) != PSA_SUCCESS)) {
return PSA_ERROR_INVALID_ARGUMENT;
}

/* Initialize ED448 key */
ret = wc_ed448_init(&ed_key);
Expand Down Expand Up @@ -518,6 +551,10 @@ psa_status_t psa_asymmetric_export_public_key_ed448(psa_key_type_t key_type,
key_bits != 448) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if ((wolfpsa_check_word32_length(key_buffer_size) != PSA_SUCCESS) ||
(wolfpsa_check_word32_length(output_size) != PSA_SUCCESS)) {
return PSA_ERROR_INVALID_ARGUMENT;
}

/* Initialize ED448 key */
ret = wc_ed448_init(&ed_key);
Expand Down
1 change: 1 addition & 0 deletions src/psa_hash_engine.c
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,7 @@ psa_status_t psa_hash_finish(psa_hash_operation_t *operation,
*hash_length = expected_hash_size;
ctx->finalized = 1;
psa_hash_cleanup_ctx(ctx);
wc_ForceZero(ctx, sizeof(*ctx));
XFREE(ctx, NULL, DYNAMIC_TYPE_TMP_BUFFER);
operation->opaque = (uintptr_t)NULL;

Expand Down
Loading
Loading