Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
712dff3
Add psa_export_key usage test
danielinux Apr 10, 2026
872ab2e
Add psa_copy_key API coverage
danielinux Apr 10, 2026
bd0368b
Fix sequential KDF output slices
danielinux Apr 10, 2026
f76ded2
Reject PSA_ALG_NONE key operations
danielinux Apr 10, 2026
dff642e
Add cipher algorithm mismatch policy test
danielinux Apr 10, 2026
1fa2a94
Add KDF input key policy coverage
danielinux Apr 10, 2026
57e1105
Add key agreement KDF policy coverage
danielinux Apr 10, 2026
bab54f3
Add AEAD policy mismatch coverage
danielinux Apr 10, 2026
8227f5c
Add MAC policy regression coverage
danielinux Apr 10, 2026
d321c58
Allow multipart CCM_STAR_NO_TAG updates
danielinux Apr 10, 2026
e1d65f8
Allow partial HKDF-Extract output
danielinux Apr 10, 2026
1f1c240
scrub cipher ctx on setup failure
danielinux Apr 10, 2026
4ef79ee
Scrub MAC setup failure state
danielinux Apr 10, 2026
ce6ceb0
Fix ECC public bit inference
danielinux Apr 10, 2026
f69741b
Reject zero PBKDF2 cost
danielinux Apr 10, 2026
e82a02a
Reject invalid ChaCha20 key sizes
danielinux Apr 10, 2026
08c2c13
Abort PSA multipart ops on error
danielinux Apr 10, 2026
0eaa83c
Add RSA OAEP asymmetric API coverage
danielinux Apr 10, 2026
e217aff
Add KDF verify_key policy coverage
danielinux Apr 10, 2026
3127df7
Add PSA generate key public type test
danielinux Apr 10, 2026
50f6c03
Zero AEAD stack AES state
danielinux Apr 10, 2026
c0a069e
Zero AEAD context before free
danielinux Apr 10, 2026
7f6b0cc
Fix ChaCha20-Poly1305 multipart finish buffers
danielinux Apr 10, 2026
ce2e7cf
Guard volatile key ID wraparound
danielinux Apr 10, 2026
d2e4a1d
reject unsupported secondary key algorithms
danielinux Apr 10, 2026
8c50962
Initialize wolfCrypt from psa_crypto_init
danielinux Apr 10, 2026
bfcd563
Force zero key buffer on read failure
danielinux Apr 10, 2026
ec67dc4
Validate stored key lengths before reads
danielinux Apr 10, 2026
e2e910b
zero hash ctx before abort free
danielinux Apr 10, 2026
24750b8
Require PSA init for hash entry points
danielinux Apr 10, 2026
fd989c2
Guard psa_generate_random before init
danielinux Apr 10, 2026
dfe9540
add asymmetric algorithm mismatch regression
danielinux Apr 10, 2026
71ad729
Normalize empty AEAD buffers
danielinux Apr 10, 2026
65d0673
Guard zero-length PBKDF2 inputs
danielinux Apr 10, 2026
3f8c5bd
Addressed copilot's review comments
danielinux Apr 10, 2026
142c69b
Addressed reviewer's comments
danielinux Apr 10, 2026
c8717b6
Update gitignore (unit test binary)
danielinux Apr 10, 2026
219d564
Fixed/updated copyright notice
danielinux Apr 10, 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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ test/psa_tls_server
test/psa_des3_stack_scrub_test
test/psa_random_size_test
test/psa_rsa_pss_interop_test
test/psa_crypto_init_test
psa_server/tls_client/psa_tls_client
psa_tls_client
wolfcrypt-benchmark/wolfcrypt-psa-benchmark
Expand Down
18 changes: 17 additions & 1 deletion src/misc_impl.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
/* misc_impl.c
*
* Provide misc.c helper implementations for NO_INLINE builds.
* Copyright (C) 2026 wolfSSL Inc.
*
* This file is part of wolfPSA.
*
* wolfPSA is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfPSA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/

#ifdef HAVE_CONFIG_H
Expand Down
93 changes: 77 additions & 16 deletions src/psa_aead.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,18 @@ static psa_status_t wolfpsa_aead_append(uint8_t **buf, size_t *len,
return PSA_SUCCESS;
}

static const uint8_t* wolfpsa_aead_nonnull_data(const uint8_t *data,
size_t data_length)
{
static const uint8_t empty = 0;
Comment thread
danielinux marked this conversation as resolved.

if (data == NULL && data_length == 0) {
return ∅
}

return data;
}

static size_t wolfpsa_aead_tag_length(psa_algorithm_t alg)
{
return PSA_ALG_AEAD_GET_TAG_LENGTH(alg);
Expand Down Expand Up @@ -134,7 +146,14 @@ static psa_status_t wolfpsa_aead_check_key(psa_key_id_t key,
}

key_alg = psa_get_key_algorithm(attributes);
if (key_alg != PSA_ALG_NONE) {
if (key_alg == PSA_ALG_NONE) {
wolfpsa_forcezero_free_key_data(*key_data, *key_data_length);
*key_data = NULL;
*key_data_length = 0;
return PSA_ERROR_NOT_PERMITTED;
}

{
psa_algorithm_t key_base = PSA_ALG_AEAD_WITH_DEFAULT_LENGTH_TAG(key_alg);
psa_algorithm_t req_base = PSA_ALG_AEAD_WITH_DEFAULT_LENGTH_TAG(alg);
key_tag_len = wolfpsa_aead_tag_length(key_alg);
Expand Down Expand Up @@ -452,6 +471,9 @@ static psa_status_t wolfpsa_aead_encrypt_final(wolfpsa_aead_ctx_t *ctx,
size_t *tag_length)
{
int ret;
size_t chacha_ciphertext_size = 0;
const uint8_t *input;
const uint8_t *aad;

if (ciphertext == NULL || ciphertext_length == NULL ||
tag == NULL || tag_length == NULL) {
Expand All @@ -468,6 +490,13 @@ static psa_status_t wolfpsa_aead_encrypt_final(wolfpsa_aead_ctx_t *ctx,
return PSA_ERROR_INVALID_ARGUMENT;
}

if (PSA_ALG_AEAD_EQUAL(ctx->alg, PSA_ALG_CHACHA20_POLY1305)) {
if (ctx->input_length > SIZE_MAX - ctx->tag_length) {
return PSA_ERROR_BUFFER_TOO_SMALL;
}
chacha_ciphertext_size = ctx->input_length + ctx->tag_length;
}

if (ciphertext_size < ctx->input_length) {
return PSA_ERROR_BUFFER_TOO_SMALL;
}
Expand All @@ -481,20 +510,24 @@ static psa_status_t wolfpsa_aead_encrypt_final(wolfpsa_aead_ctx_t *ctx,
return PSA_ERROR_INVALID_ARGUMENT;
}

input = wolfpsa_aead_nonnull_data(ctx->input, ctx->input_length);
aad = wolfpsa_aead_nonnull_data(ctx->aad, ctx->aad_length);

if (PSA_ALG_AEAD_EQUAL(ctx->alg, PSA_ALG_GCM)) {
Aes aes;
ret = wc_AesInit(&aes, NULL, INVALID_DEVID);
if (ret == 0) {
ret = wc_AesGcmSetKey(&aes, ctx->key, (word32)ctx->key_length);
}
if (ret == 0) {
ret = wc_AesGcmEncrypt(&aes, ciphertext, ctx->input,
ret = wc_AesGcmEncrypt(&aes, ciphertext, input,
(word32)ctx->input_length,
ctx->nonce, (word32)ctx->nonce_length,
tag, (word32)ctx->tag_length,
ctx->aad, (word32)ctx->aad_length);
aad, (word32)ctx->aad_length);
}
wc_AesFree(&aes);
wc_ForceZero(&aes, sizeof(aes));
if (ret != 0) {
return wc_error_to_psa_status(ret);
}
Expand All @@ -509,31 +542,45 @@ static psa_status_t wolfpsa_aead_encrypt_final(wolfpsa_aead_ctx_t *ctx,
ret = wc_AesCcmSetKey(&aes, ctx->key, (word32)ctx->key_length);
}
if (ret == 0) {
ret = wc_AesCcmEncrypt(&aes, ciphertext, ctx->input,
ret = wc_AesCcmEncrypt(&aes, ciphertext, input,
(word32)ctx->input_length,
ctx->nonce, (word32)ctx->nonce_length,
tag, (word32)ctx->tag_length,
ctx->aad, (word32)ctx->aad_length);
aad, (word32)ctx->aad_length);
}
wc_AesFree(&aes);
wc_ForceZero(&aes, sizeof(aes));
if (ret != 0) {
return wc_error_to_psa_status(ret);
}
}
else if (PSA_ALG_AEAD_EQUAL(ctx->alg, PSA_ALG_CHACHA20_POLY1305)) {
size_t out_len = 0;
uint8_t *tmp = (uint8_t *)XMALLOC(chacha_ciphertext_size, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (tmp == NULL) {
return PSA_ERROR_INSUFFICIENT_MEMORY;
}
ret = psa_chacha20_poly1305_encrypt(ctx->key, ctx->key_length, ctx->alg,
ctx->nonce, ctx->nonce_length,
ctx->aad, ctx->aad_length,
ctx->input, ctx->input_length,
ciphertext, ciphertext_size, &out_len);
aad, ctx->aad_length,
input, ctx->input_length,
tmp, chacha_ciphertext_size,
&out_len);
if (ret != 0) {
wc_ForceZero(tmp, chacha_ciphertext_size);
XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return (psa_status_t)ret;
}
if (out_len < ctx->tag_length) {
wc_ForceZero(tmp, chacha_ciphertext_size);
XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return PSA_ERROR_GENERIC_ERROR;
}
XMEMCPY(tag, ciphertext + ctx->input_length, ctx->tag_length);
XMEMCPY(ciphertext, tmp, ctx->input_length);
XMEMCPY(tag, tmp + ctx->input_length, ctx->tag_length);
wc_ForceZero(tmp, chacha_ciphertext_size);
XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
else {
return PSA_ERROR_NOT_SUPPORTED;
Expand All @@ -552,6 +599,8 @@ static psa_status_t wolfpsa_aead_decrypt_final(wolfpsa_aead_ctx_t *ctx,
size_t tag_length)
{
int ret;
const uint8_t *input;
const uint8_t *aad;

if (plaintext == NULL || plaintext_length == NULL || tag == NULL) {
return PSA_ERROR_INVALID_ARGUMENT;
Expand Down Expand Up @@ -586,20 +635,24 @@ static psa_status_t wolfpsa_aead_decrypt_final(wolfpsa_aead_ctx_t *ctx,
return PSA_ERROR_INVALID_ARGUMENT;
}

input = wolfpsa_aead_nonnull_data(ctx->input, ctx->input_length);
aad = wolfpsa_aead_nonnull_data(ctx->aad, ctx->aad_length);

if (PSA_ALG_AEAD_EQUAL(ctx->alg, PSA_ALG_GCM)) {
Aes aes;
ret = wc_AesInit(&aes, NULL, INVALID_DEVID);
if (ret == 0) {
ret = wc_AesGcmSetKey(&aes, ctx->key, (word32)ctx->key_length);
}
if (ret == 0) {
ret = wc_AesGcmDecrypt(&aes, plaintext, ctx->input,
ret = wc_AesGcmDecrypt(&aes, plaintext, input,
(word32)ctx->input_length,
ctx->nonce, (word32)ctx->nonce_length,
tag, (word32)tag_length,
ctx->aad, (word32)ctx->aad_length);
aad, (word32)ctx->aad_length);
}
wc_AesFree(&aes);
wc_ForceZero(&aes, sizeof(aes));
if (ret == AES_GCM_AUTH_E || ret == MAC_CMP_FAILED_E) {
return PSA_ERROR_INVALID_SIGNATURE;
}
Expand All @@ -617,13 +670,14 @@ static psa_status_t wolfpsa_aead_decrypt_final(wolfpsa_aead_ctx_t *ctx,
ret = wc_AesCcmSetKey(&aes, ctx->key, (word32)ctx->key_length);
}
if (ret == 0) {
ret = wc_AesCcmDecrypt(&aes, plaintext, ctx->input,
ret = wc_AesCcmDecrypt(&aes, plaintext, input,
(word32)ctx->input_length,
ctx->nonce, (word32)ctx->nonce_length,
tag, (word32)tag_length,
ctx->aad, (word32)ctx->aad_length);
aad, (word32)ctx->aad_length);
}
wc_AesFree(&aes);
wc_ForceZero(&aes, sizeof(aes));
if (ret == AES_CCM_AUTH_E || ret == MAC_CMP_FAILED_E) {
return PSA_ERROR_INVALID_SIGNATURE;
}
Expand All @@ -634,8 +688,13 @@ static psa_status_t wolfpsa_aead_decrypt_final(wolfpsa_aead_ctx_t *ctx,
else if (PSA_ALG_AEAD_EQUAL(ctx->alg, PSA_ALG_CHACHA20_POLY1305)) {
size_t out_len = 0;
uint8_t *ciphertext = ctx->input;
size_t ciphertext_len = ctx->input_length + tag_length;
uint8_t *tmp = (uint8_t *)XMALLOC(ciphertext_len, NULL,
size_t ciphertext_len;
uint8_t *tmp;
if (ctx->input_length > SIZE_MAX - tag_length) {
return PSA_ERROR_INVALID_ARGUMENT;
}
ciphertext_len = ctx->input_length + tag_length;
tmp = (uint8_t *)XMALLOC(ciphertext_len, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (tmp == NULL) {
return PSA_ERROR_INSUFFICIENT_MEMORY;
Expand All @@ -644,9 +703,10 @@ static psa_status_t wolfpsa_aead_decrypt_final(wolfpsa_aead_ctx_t *ctx,
XMEMCPY(tmp + ctx->input_length, tag, tag_length);
Comment thread
dgarske marked this conversation as resolved.
ret = psa_chacha20_poly1305_decrypt(ctx->key, ctx->key_length, ctx->alg,
ctx->nonce, ctx->nonce_length,
ctx->aad, ctx->aad_length,
aad, ctx->aad_length,
tmp, ciphertext_len,
plaintext, plaintext_size, &out_len);
wc_ForceZero(tmp, ciphertext_len);
XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER);
Comment thread
dgarske marked this conversation as resolved.
if (ret != 0) {
return PSA_ERROR_INVALID_SIGNATURE;
Expand Down Expand Up @@ -862,6 +922,7 @@ psa_status_t psa_aead_abort(psa_aead_operation_t *operation)
wc_ForceZero(ctx->key, ctx->key_length);
XFREE(ctx->key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
wc_ForceZero(ctx, sizeof(*ctx));
XFREE(ctx, NULL, DYNAMIC_TYPE_TMP_BUFFER);
operation->opaque = (uintptr_t)NULL;
}
Expand Down
21 changes: 21 additions & 0 deletions src/psa_aead_internal.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
/* psa_aead_internal.h
*
* Copyright (C) 2026 wolfSSL Inc.
*
* This file is part of wolfPSA.
*
* wolfPSA is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfPSA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/

#ifndef WOLFPSA_PSA_AEAD_INTERNAL_H
#define WOLFPSA_PSA_AEAD_INTERNAL_H

Expand Down
22 changes: 21 additions & 1 deletion src/psa_api_stub.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,24 @@
/* psa_api_stub.c - auto-generated for test linkage */
/* psa_api_stub.c
*
* Copyright (C) 2026 wolfSSL Inc.
*
* This file is part of wolfPSA.
*
* wolfPSA is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfPSA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/

#include <psa/crypto.h>

extern int wolfPSA_CryptoIsInitialized(void);
Expand Down
27 changes: 16 additions & 11 deletions src/psa_asymmetric_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -167,23 +167,28 @@ static psa_status_t wolfpsa_asymmetric_check_key(psa_key_id_t key,
}

key_alg = psa_get_key_algorithm(attributes);
if (key_alg != PSA_ALG_NONE) {
if (PSA_ALG_IS_KEY_AGREEMENT(alg) && PSA_ALG_IS_KEY_AGREEMENT(key_alg)) {
if (PSA_ALG_KEY_AGREEMENT_GET_BASE(key_alg) !=
PSA_ALG_KEY_AGREEMENT_GET_BASE(alg)) {
wolfpsa_forcezero_free_key_data(*key_data, *key_data_length);
*key_data = NULL;
*key_data_length = 0;
return PSA_ERROR_NOT_PERMITTED;
}
}
else if (key_alg != alg) {
if (key_alg == PSA_ALG_NONE) {
wolfpsa_forcezero_free_key_data(*key_data, *key_data_length);
*key_data = NULL;
*key_data_length = 0;
return PSA_ERROR_NOT_PERMITTED;
}

if (PSA_ALG_IS_KEY_AGREEMENT(alg) && PSA_ALG_IS_KEY_AGREEMENT(key_alg)) {
if (PSA_ALG_KEY_AGREEMENT_GET_BASE(key_alg) !=
PSA_ALG_KEY_AGREEMENT_GET_BASE(alg)) {
wolfpsa_forcezero_free_key_data(*key_data, *key_data_length);
*key_data = NULL;
*key_data_length = 0;
return PSA_ERROR_NOT_PERMITTED;
}
}
else if (key_alg != alg) {
wolfpsa_forcezero_free_key_data(*key_data, *key_data_length);
*key_data = NULL;
*key_data_length = 0;
return PSA_ERROR_NOT_PERMITTED;
}

return PSA_SUCCESS;
}
Expand Down
Loading
Loading