From 8fec821ed6659653c20d0cfd74b203f3ac3bb02a Mon Sep 17 00:00:00 2001 From: Paul Adelsbach Date: Fri, 30 Oct 2026 18:03:50 -0700 Subject: [PATCH 1/6] Generate PSA_WANT_* for the Makefile build --- .gitignore | 2 + Makefile | 15 +- test/Makefile | 3 +- test/psa_server/psa_want_surface_test.c | 213 +++++++++++++++++++++ {zephyr/gen => tools}/gen-crypto-config.py | 55 ++++-- {zephyr/gen => tools}/psa_want_probe.c | 18 +- wolfpsa/psa/crypto.h | 2 + wolfpsa/psa/crypto_config.h | 18 +- zephyr/CMakeLists.txt | 6 +- 9 files changed, 288 insertions(+), 44 deletions(-) create mode 100644 test/psa_server/psa_want_surface_test.c rename {zephyr/gen => tools}/gen-crypto-config.py (57%) rename {zephyr/gen => tools}/psa_want_probe.c (90%) diff --git a/.gitignore b/.gitignore index 11c06a69..65a12c71 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ build +wolfpsa/psa/crypto_config_generated.h # gcov coverage artifacts (make cov) *.gcda *.gcno @@ -85,3 +86,4 @@ test/psa_copy_key_cross_lifetime_test build-test/out/ test/psa_zero_capacity_buffer_test test/psa_tf_psa_extra_test +test/psa_want_surface_test diff --git a/Makefile b/Makefile index fed5ff8b..7d153120 100644 --- a/Makefile +++ b/Makefile @@ -135,6 +135,18 @@ $(LIBNAME): $(OBJ) $(WOLFCRYPT_OBJ) $(SHLIBNAME): $(OBJ_PIC) $(WOLFCRYPT_OBJ_PIC) $(EXPORT_MAP) $(CC) -shared -Wl,--version-script,$(EXPORT_MAP) -Wl,-Bsymbolic-functions -o $@ $(filter-out $(EXPORT_MAP),$^) $(LDFLAGS) +# Build the PSA_WANT_* macros based on what the wolfCrypt build supports. +PSA_CONFIG := wolfpsa/psa/crypto_config_generated.h +PYTHON ?= python3 + +$(PSA_CONFIG): FORCE + $(PYTHON) tools/gen-crypto-config.py $@ "$(CC)" \ + tools/psa_want_probe.c $(CPPFLAGS) $(CFLAGS) + +$(OBJ) $(OBJ_PIC): $(PSA_CONFIG) + +FORCE: + $(OBJDIR)/%.o: src/%.c @mkdir -p $(OBJDIR) $(CC) $(CPPFLAGS) $(DEPFLAGS) $(CFLAGS) -c $< -o $@ @@ -210,6 +222,7 @@ UNIT_TESTS := psa_api_test \ psa_import_zero_length_test \ psa_copy_key_cross_lifetime_test \ psa_zero_capacity_buffer_test \ + psa_want_surface_test \ psa_tf_psa_extra_test # Run the unit test loop from the repo root (psa_rsa_pss_interop_test reads @@ -273,7 +286,7 @@ covclean: rm -rf $(COV_DIR) clean: - rm -rf $(BUILD_DIR) $(LIBNAME) $(SHLIBNAME) + rm -rf $(BUILD_DIR) $(LIBNAME) $(SHLIBNAME) $(PSA_CONFIG) -include $(OBJ:.o=.d) $(WOLFCRYPT_OBJ:.o=.d) -include $(OBJ_PIC:.o=.d) $(WOLFCRYPT_OBJ_PIC:.o=.d) diff --git a/test/Makefile b/test/Makefile index 254c4a5b..e30aae89 100644 --- a/test/Makefile +++ b/test/Makefile @@ -125,7 +125,8 @@ PSA_REGRESSION_TESTS = psa_aead_multipart_test \ psa_store_dir_validation_test \ psa_import_zero_length_test \ psa_copy_key_cross_lifetime_test \ - psa_zero_capacity_buffer_test + psa_zero_capacity_buffer_test \ + psa_want_surface_test BINARIES += $(PSA_REGRESSION_TESTS) # TF-PSA-Crypto extension tests, built with the default link recipe. diff --git a/test/psa_server/psa_want_surface_test.c b/test/psa_server/psa_want_surface_test.c new file mode 100644 index 00000000..32b02335 --- /dev/null +++ b/test/psa_server/psa_want_surface_test.c @@ -0,0 +1,213 @@ +/* psa_want_surface_test.c + * + * The PSA_WANT_* and MBEDTLS_*_C macros seen through psa/crypto.h match what + * the library supports, and buffers of the *_MAX_SIZE macros are large + * enough for it. + * + * 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 + +#include +#include + +/* A macro is defined when its expansion differs from its name */ +#define STRINGIFY(m) #m +#define EXPANDED(m) STRINGIFY(m) +#define IS_DEFINED(m) (strcmp(EXPANDED(m), #m) != 0) + +#define NO_FEATURE (-1) + +struct want_case { + const char* name; + psa_key_type_t type; + size_t bits; + psa_algorithm_t alg; + int want; /* the PSA_WANT_* macros of the type and algorithm */ + int feature; /* the MBEDTLS_*_C macros, or NO_FEATURE */ +}; + +static int failures; + +static psa_status_t run_ecdh(psa_key_id_t key) +{ + uint8_t pub[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE]; + uint8_t pair[PSA_EXPORT_KEY_PAIR_MAX_SIZE]; + uint8_t secret[PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE]; + size_t pubLen = 0; + size_t len = 0; + psa_status_t status; + + status = psa_export_public_key(key, pub, sizeof(pub), &pubLen); + if (status == PSA_SUCCESS) { + status = psa_export_key(key, pair, sizeof(pair), &len); + } + if (status == PSA_SUCCESS) { + status = psa_raw_key_agreement(PSA_ALG_ECDH, key, pub, pubLen, secret, + sizeof(secret), &len); + } + return status; +} + +static psa_status_t run_aead(psa_key_id_t key, psa_key_type_t type, + psa_algorithm_t alg) +{ + uint8_t nonce[PSA_AEAD_NONCE_MAX_SIZE]; + uint8_t msg[16]; + uint8_t out[PSA_AEAD_ENCRYPT_OUTPUT_MAX_SIZE(sizeof(msg))]; + size_t len = 0; + + memset(nonce, 0, sizeof(nonce)); + memset(msg, 0, sizeof(msg)); + return psa_aead_encrypt(key, alg, nonce, PSA_AEAD_NONCE_LENGTH(type, alg), + NULL, 0, msg, sizeof(msg), out, sizeof(out), &len); +} + +static psa_status_t run_mac(psa_key_id_t key, psa_algorithm_t alg) +{ + uint8_t msg[16]; + uint8_t mac[PSA_MAC_MAX_SIZE]; + size_t len = 0; + + memset(msg, 0, sizeof(msg)); + return psa_mac_compute(key, alg, msg, sizeof(msg), mac, sizeof(mac), &len); +} + +/* Returns PSA_SUCCESS, or PSA_ERROR_NOT_SUPPORTED when the library does not + * support the case */ +static psa_status_t run_case(const struct want_case* c) +{ + psa_key_attributes_t attr = psa_key_attributes_init(); + psa_key_id_t key = PSA_KEY_ID_NULL; + psa_status_t status; + + psa_set_key_type(&attr, c->type); + psa_set_key_bits(&attr, c->bits); + psa_set_key_algorithm(&attr, c->alg); + if (PSA_ALG_IS_KEY_AGREEMENT(c->alg)) { + psa_set_key_usage_flags(&attr, + PSA_KEY_USAGE_DERIVE | PSA_KEY_USAGE_EXPORT); + } + else if (PSA_ALG_IS_AEAD(c->alg)) { + psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_ENCRYPT); + } + else { + psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_SIGN_MESSAGE); + } + + status = psa_generate_key(&attr, &key); + if (status == PSA_SUCCESS) { + if (PSA_ALG_IS_KEY_AGREEMENT(c->alg)) { + status = run_ecdh(key); + } + else if (PSA_ALG_IS_AEAD(c->alg)) { + status = run_aead(key, c->type, c->alg); + } + else { + status = run_mac(key, c->alg); + } + (void)psa_destroy_key(key); + } + return status; +} + +static void check_case(const struct want_case* c) +{ + psa_status_t status = run_case(c); + int supported = (status == PSA_SUCCESS); + + if (status != PSA_SUCCESS && status != PSA_ERROR_NOT_SUPPORTED) { + printf("FAIL %s: status %d\n", c->name, (int)status); + failures++; + } + else if (supported != c->want) { + printf("FAIL %s: supported %d, PSA_WANT_ macros %d\n", c->name, + supported, c->want); + failures++; + } + else if (c->feature != NO_FEATURE && supported != c->feature) { + printf("FAIL %s: supported %d, MBEDTLS_*_C macros %d\n", c->name, + supported, c->feature); + failures++; + } + else { + printf("ok %s: supported %d\n", c->name, supported); + } +} + +int main(void) +{ + const psa_key_type_t ecc = + PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1); + const psa_key_type_t mont = + PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY); + const int ecdh = IS_DEFINED(PSA_WANT_ALG_ECDH) && + IS_DEFINED(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE); + const int aes = IS_DEFINED(PSA_WANT_KEY_TYPE_AES); + const int aesC = IS_DEFINED(MBEDTLS_AES_C); + const struct want_case cases[] = { + { "secp256r1 ECDH", ecc, 256, PSA_ALG_ECDH, + ecdh && IS_DEFINED(PSA_WANT_ECC_SECP_R1_256), NO_FEATURE }, + { "secp384r1 ECDH", ecc, 384, PSA_ALG_ECDH, + ecdh && IS_DEFINED(PSA_WANT_ECC_SECP_R1_384), NO_FEATURE }, + { "secp521r1 ECDH", ecc, 521, PSA_ALG_ECDH, + ecdh && IS_DEFINED(PSA_WANT_ECC_SECP_R1_521), NO_FEATURE }, + { "X25519", mont, 255, PSA_ALG_ECDH, + ecdh && IS_DEFINED(PSA_WANT_ECC_MONTGOMERY_255), NO_FEATURE }, + { "X448", mont, 448, PSA_ALG_ECDH, + ecdh && IS_DEFINED(PSA_WANT_ECC_MONTGOMERY_448), NO_FEATURE }, + { "AES-128-GCM", PSA_KEY_TYPE_AES, 128, PSA_ALG_GCM, + aes && IS_DEFINED(PSA_WANT_ALG_GCM), + aesC && IS_DEFINED(MBEDTLS_GCM_C) }, + { "AES-128-CCM", PSA_KEY_TYPE_AES, 128, PSA_ALG_CCM, + aes && IS_DEFINED(PSA_WANT_ALG_CCM), + aesC && IS_DEFINED(MBEDTLS_CCM_C) }, + { "ChaCha20-Poly1305", PSA_KEY_TYPE_CHACHA20, 256, + PSA_ALG_CHACHA20_POLY1305, + IS_DEFINED(PSA_WANT_KEY_TYPE_CHACHA20) && + IS_DEFINED(PSA_WANT_ALG_CHACHA20_POLY1305), + IS_DEFINED(MBEDTLS_CHACHAPOLY_C) }, + { "HMAC-SHA-256", PSA_KEY_TYPE_HMAC, 256, + PSA_ALG_HMAC(PSA_ALG_SHA_256), + IS_DEFINED(PSA_WANT_KEY_TYPE_HMAC) && + IS_DEFINED(PSA_WANT_ALG_HMAC), NO_FEATURE }, + }; + size_t i; + psa_status_t status; + + status = psa_crypto_init(); + if (status != PSA_SUCCESS) { + printf("FAIL psa_crypto_init status %d\n", (int)status); + return 1; + } + + for (i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) { + check_case(&cases[i]); + } + + mbedtls_psa_crypto_free(); + + if (failures != 0) { + printf("PSA_WANT surface test: FAIL (%d)\n", failures); + return 1; + } + printf("PSA_WANT surface test: OK\n"); + return 0; +} diff --git a/zephyr/gen/gen-crypto-config.py b/tools/gen-crypto-config.py similarity index 57% rename from zephyr/gen/gen-crypto-config.py rename to tools/gen-crypto-config.py index e64966d5..45bdc81f 100644 --- a/zephyr/gen/gen-crypto-config.py +++ b/tools/gen-crypto-config.py @@ -3,46 +3,52 @@ # Copyright (C) 2026 wolfSSL Inc. # SPDX-License-Identifier: GPL-3.0-or-later # -# Generate wolfpsa/psa/crypto_config_zephyr.h from the ACTUAL compiled wolfCrypt +# Generate the PSA_WANT_ header (crypto_config_zephyr.h for Zephyr, +# crypto_config_generated.h for the Makefile) from the ACTUAL compiled wolfCrypt # configuration, by preprocessing psa_want_probe.c with the same flags as the # rest of the build. The result is the consumer-visible PSA_WANT_ surface: # exactly the algorithm families wolfCrypt has enabled AND wolfPSA implements. # # Python (not shell) to fit the Zephyr build ecosystem, invoked via CMake's -# PYTHON_EXECUTABLE from wolfPSA's zephyr/CMakeLists.txt. +# PYTHON_EXECUTABLE from wolfPSA's zephyr/CMakeLists.txt, and by the Makefile. # # Usage: # gen-crypto-config.py [preprocessor flags...] # -# The preprocessor flags must reproduce the build's wolfCrypt config -- at -# minimum -DWOLFSSL_USER_SETTINGS -DWOLFSSL_ZEPHYR, the wolfssl/wolfpsa include -# dirs, any -DWOLFSSL_SETTINGS_FILE, and -imacros . - +# is a path, or a command with arguments such as "ccache gcc". The +# preprocessor flags must reproduce the build's wolfCrypt config -- for +# Zephyr at minimum -DWOLFSSL_USER_SETTINGS -DWOLFSSL_ZEPHYR, the +# wolfssl/wolfpsa include dirs, any -DWOLFSSL_SETTINGS_FILE, and -imacros +# ; for the Makefile build, its CPPFLAGS and CFLAGS. The header is +# written only when its content changes. + +import os import re +import shlex import subprocess import sys HEADER = """\ -/* crypto_config_zephyr.h +/* {name} * * Copyright (C) 2026 wolfSSL Inc. * SPDX-License-Identifier: GPL-3.0-or-later * - * GENERATED at build time by zephyr/gen/gen-crypto-config.py from the compiled + * GENERATED at build time by tools/gen-crypto-config.py from the compiled * wolfCrypt configuration -- DO NOT EDIT and do not check in. It defines the * consumer-visible PSA_WANT_ surface (what wolfPSA exposes as the PSA API), * derived from the wolfCrypt features actually enabled in this build intersected * with what wolfPSA implements. wolfpsa/psa/crypto.h -> crypto_config.h includes - * it under CONFIG_WOLFPSA, so PSA sizing macros (crypto_sizes.h) and consumer - * PSA_WANT_-gated code track the real build. + * it, so PSA sizing macros (crypto_sizes.h) and consumer PSA_WANT_-gated code + * track the real build. */ -#ifndef WOLFPSA_CRYPTO_CONFIG_ZEPHYR_H -#define WOLFPSA_CRYPTO_CONFIG_ZEPHYR_H +#ifndef {guard} +#define {guard} """ -FOOTER = "\n#endif /* WOLFPSA_CRYPTO_CONFIG_ZEPHYR_H */\n" +FOOTER = "\n#endif /* {guard} */\n" EMIT_TAG = "__WPSA_EMIT__" WANT_RE = re.compile(r"PSA_WANT_[A-Z0-9_]+") @@ -54,12 +60,13 @@ def main(argv): "usage: gen-crypto-config.py [flags...]\n") return 2 - out_path, cc, probe = argv[1], argv[2], argv[3] + out_path, probe = argv[1], argv[3] + cc = [argv[2]] if os.path.isfile(argv[2]) else shlex.split(argv[2]) flags = argv[4:] try: preprocessed = subprocess.run( - [cc, "-E", "-P", *flags, probe], + [*cc, "-E", "-P", *flags, probe], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True).stdout except subprocess.CalledProcessError as exc: @@ -79,11 +86,21 @@ def main(argv): "gen-crypto-config.py: probe produced no PSA_WANT symbols\n") return 1 + name = os.path.basename(out_path) + guard = "WOLFPSA_" + re.sub(r"[^A-Z0-9]", "_", name.upper()) + text = (HEADER.format(name=name, guard=guard) + + "".join("#define {} 1\n".format(want) for want in wants) + + FOOTER.format(guard=guard)) + + # Unchanged content keeps its timestamp, so nothing rebuilds + try: + with open(out_path) as out_file: + if out_file.read() == text: + return 0 + except OSError: + pass with open(out_path, "w") as out_file: - out_file.write(HEADER) - for want in wants: - out_file.write("#define {} 1\n".format(want)) - out_file.write(FOOTER) + out_file.write(text) return 0 diff --git a/zephyr/gen/psa_want_probe.c b/tools/psa_want_probe.c similarity index 90% rename from zephyr/gen/psa_want_probe.c rename to tools/psa_want_probe.c index ae4d2424..3038c2d2 100644 --- a/zephyr/gen/psa_want_probe.c +++ b/tools/psa_want_probe.c @@ -23,7 +23,8 @@ * NOT a compiled translation unit. This file is *preprocessed* at build time * (gcc -E -P) with the same wolfCrypt configuration as the rest of the build, * and gen-crypto-config.py extracts the surviving `__WPSA_EMIT__` - * lines to generate wolfpsa/psa/crypto_config_zephyr.h -- the consumer-visible + * lines to generate wolfpsa/psa/crypto_config_zephyr.h (Zephyr) or + * crypto_config_generated.h (Makefile) -- the consumer-visible * PSA_WANT_ surface. Each block below maps an enabled wolfCrypt feature to the * PSA_WANT_ symbol(s) wolfPSA exposes for it, so the advertised PSA surface is * exactly "what wolfCrypt compiled" intersected with "what wolfPSA implements". @@ -37,8 +38,14 @@ * user_settings.h + wolfPSA baseline). We include user_settings.h directly * rather than so this probe preprocesses without * dragging in the Zephyr kernel headers settings.h pulls under WOLFSSL_ZEPHYR; - * every feature macro this probe tests is materialized by user_settings.h. */ + * every feature macro this probe tests is materialized by user_settings.h. + * The Makefile build includes settings.h, which adds macros such as + * HAVE_ALL_CURVES. */ +#if defined(__ZEPHYR__) #include "user_settings.h" +#else +#include +#endif /* __ZEPHYR__ */ /* ----- Hashes ----- */ #if !defined(NO_SHA) @@ -152,13 +159,14 @@ __WPSA_EMIT__PSA_WANT_ALG_ECDH #if defined(WOLFSSL_ECDSA_DETERMINISTIC_K) __WPSA_EMIT__PSA_WANT_ALG_DETERMINISTIC_ECDSA #endif -#if !defined(NO_ECC256) +/* The curves as wolfCrypt's ecc.c enables them */ +#if (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 256 __WPSA_EMIT__PSA_WANT_ECC_SECP_R1_256 #endif -#if defined(HAVE_ECC384) +#if (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 384 __WPSA_EMIT__PSA_WANT_ECC_SECP_R1_384 #endif -#if defined(HAVE_ECC521) +#if (defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 521 __WPSA_EMIT__PSA_WANT_ECC_SECP_R1_521 #endif #endif /* HAVE_ECC */ diff --git a/wolfpsa/psa/crypto.h b/wolfpsa/psa/crypto.h index f708a95d..df21230d 100644 --- a/wolfpsa/psa/crypto.h +++ b/wolfpsa/psa/crypto.h @@ -30,6 +30,8 @@ #include "crypto_types.h" #include "crypto_values.h" #include "crypto_config.h" +/* MBEDTLS_*_C feature macros, which TF-PSA-Crypto's psa/crypto.h includes */ +#include "tf-psa-crypto/build_info.h" #include "crypto_sizes.h" #include "crypto_struct.h" #include "crypto-pqc.h" diff --git a/wolfpsa/psa/crypto_config.h b/wolfpsa/psa/crypto_config.h index e12d1eee..3d333b41 100644 --- a/wolfpsa/psa/crypto_config.h +++ b/wolfpsa/psa/crypto_config.h @@ -24,25 +24,13 @@ #if defined(CONFIG_WOLFPSA) -/* Zephyr build: derive the PSA_WANT_* surface from the consumer's Kconfig - * (CONFIG_PSA_WANT_*) instead of the small hardcoded list below, so that the - * size macros in crypto_sizes.h and any PSA_WANT_*-gated consumer code match - * whatever capabilities the application enabled. */ +/* Generated by the Zephyr build, in zephyr/CMakeLists.txt */ #include "crypto_config_zephyr.h" #else /* standalone (Makefile) build */ -#define PSA_WANT_ALG_SHA_1 1 -#define PSA_WANT_ALG_SHA_224 1 -#define PSA_WANT_ALG_SHA_256 1 -#define PSA_WANT_ALG_SHA_384 1 -#define PSA_WANT_ALG_SHA_512 1 - -#define PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC 1 -#define PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY 1 - -#define PSA_WANT_KEY_TYPE_ML_DSA 1 -#define PSA_WANT_KEY_TYPE_ML_KEM 1 +/* Generated by the Makefile */ +#include "crypto_config_generated.h" /* TF-PSA-Crypto platform option: the platform has stdio files */ #define MBEDTLS_FS_IO diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index 37426e10..683d5d79 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -35,7 +35,7 @@ if(CONFIG_WOLFPSA) # wolfPSA exposes as the PSA API exactly the crypto that the user's wolfCrypt # configuration enabled (and that wolfPSA implements). We derive the # consumer-visible PSA_WANT_ surface from the ACTUAL compiled config by - # preprocessing zephyr/gen/psa_want_probe.c and generating + # preprocessing tools/psa_want_probe.c and generating # crypto_config_zephyr.h, which -> crypto_config.h includes. # Generated at CONFIGURE time (autoconf.h already exists) so it is present # before any TU that includes compiles. @@ -53,8 +53,8 @@ if(CONFIG_WOLFPSA) set(WOLFPSA_GEN_DIR ${CMAKE_CURRENT_BINARY_DIR}/wolfpsa_gen) set(WOLFPSA_GEN_HDR ${WOLFPSA_GEN_DIR}/crypto_config_zephyr.h) - set(WOLFPSA_PROBE ${WOLFPSA_DIR}/zephyr/gen/psa_want_probe.c) - set(WOLFPSA_GEN_PY ${WOLFPSA_DIR}/zephyr/gen/gen-crypto-config.py) + set(WOLFPSA_PROBE ${WOLFPSA_DIR}/tools/psa_want_probe.c) + set(WOLFPSA_GEN_PY ${WOLFPSA_DIR}/tools/gen-crypto-config.py) file(MAKE_DIRECTORY ${WOLFPSA_GEN_DIR}) set(_wolfpsa_probe_flags From 23af930781138d3ed48e3f9b891fded34530ee49 Mon Sep 17 00:00:00 2001 From: Paul Adelsbach Date: Fri, 30 Oct 2026 19:17:31 -0700 Subject: [PATCH 2/6] Add EdDSA and ML-KEM sizes in the PSA_WANT_* macros --- test/psa_server/psa_want_surface_test.c | 67 +++++++++++++++++++------ tools/psa_want_probe.c | 33 ++++++++++-- wolfpsa/psa/crypto_sizes.h | 10 ++++ 3 files changed, 90 insertions(+), 20 deletions(-) diff --git a/test/psa_server/psa_want_surface_test.c b/test/psa_server/psa_want_surface_test.c index 32b02335..8f6219b0 100644 --- a/test/psa_server/psa_want_surface_test.c +++ b/test/psa_server/psa_want_surface_test.c @@ -33,7 +33,9 @@ #define EXPANDED(m) STRINGIFY(m) #define IS_DEFINED(m) (strcmp(EXPANDED(m), #m) != 0) -#define NO_FEATURE (-1) +#define NOT_CHECKED (-1) +/* A family macro: the library may leave out the parameter set */ +#define FAMILY_WANT(defined) ((defined) ? NOT_CHECKED : 0) struct want_case { const char* name; @@ -41,23 +43,36 @@ struct want_case { size_t bits; psa_algorithm_t alg; int want; /* the PSA_WANT_* macros of the type and algorithm */ - int feature; /* the MBEDTLS_*_C macros, or NO_FEATURE */ + int feature; /* the MBEDTLS_*_C macros, or NOT_CHECKED */ }; static int failures; -static psa_status_t run_ecdh(psa_key_id_t key) +static psa_status_t run_export(psa_key_id_t key) { uint8_t pub[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE]; uint8_t pair[PSA_EXPORT_KEY_PAIR_MAX_SIZE]; + size_t len = 0; + psa_status_t status; + + status = psa_export_public_key(key, pub, sizeof(pub), &len); + if (status == PSA_SUCCESS) { + status = psa_export_key(key, pair, sizeof(pair), &len); + } + return status; +} + +static psa_status_t run_ecdh(psa_key_id_t key) +{ + uint8_t pub[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE]; uint8_t secret[PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE]; size_t pubLen = 0; size_t len = 0; psa_status_t status; - status = psa_export_public_key(key, pub, sizeof(pub), &pubLen); + status = run_export(key); if (status == PSA_SUCCESS) { - status = psa_export_key(key, pair, sizeof(pair), &len); + status = psa_export_public_key(key, pub, sizeof(pub), &pubLen); } if (status == PSA_SUCCESS) { status = psa_raw_key_agreement(PSA_ALG_ECDH, key, pub, pubLen, secret, @@ -108,9 +123,12 @@ static psa_status_t run_case(const struct want_case* c) else if (PSA_ALG_IS_AEAD(c->alg)) { psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_ENCRYPT); } - else { + else if (PSA_ALG_IS_MAC(c->alg)) { psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_SIGN_MESSAGE); } + else { + psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_EXPORT); + } status = psa_generate_key(&attr, &key); if (status == PSA_SUCCESS) { @@ -120,9 +138,12 @@ static psa_status_t run_case(const struct want_case* c) else if (PSA_ALG_IS_AEAD(c->alg)) { status = run_aead(key, c->type, c->alg); } - else { + else if (PSA_ALG_IS_MAC(c->alg)) { status = run_mac(key, c->alg); } + else { + status = run_export(key); + } (void)psa_destroy_key(key); } return status; @@ -137,12 +158,12 @@ static void check_case(const struct want_case* c) printf("FAIL %s: status %d\n", c->name, (int)status); failures++; } - else if (supported != c->want) { + else if (c->want != NOT_CHECKED && supported != c->want) { printf("FAIL %s: supported %d, PSA_WANT_ macros %d\n", c->name, supported, c->want); failures++; } - else if (c->feature != NO_FEATURE && supported != c->feature) { + else if (c->feature != NOT_CHECKED && supported != c->feature) { printf("FAIL %s: supported %d, MBEDTLS_*_C macros %d\n", c->name, supported, c->feature); failures++; @@ -158,21 +179,31 @@ int main(void) PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1); const psa_key_type_t mont = PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY); + const psa_key_type_t ed = + PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_TWISTED_EDWARDS); const int ecdh = IS_DEFINED(PSA_WANT_ALG_ECDH) && IS_DEFINED(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE); + const int eddsa = IS_DEFINED(PSA_WANT_ALG_PURE_EDDSA) && + IS_DEFINED(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE); const int aes = IS_DEFINED(PSA_WANT_KEY_TYPE_AES); const int aesC = IS_DEFINED(MBEDTLS_AES_C); const struct want_case cases[] = { { "secp256r1 ECDH", ecc, 256, PSA_ALG_ECDH, - ecdh && IS_DEFINED(PSA_WANT_ECC_SECP_R1_256), NO_FEATURE }, + ecdh && IS_DEFINED(PSA_WANT_ECC_SECP_R1_256), NOT_CHECKED }, { "secp384r1 ECDH", ecc, 384, PSA_ALG_ECDH, - ecdh && IS_DEFINED(PSA_WANT_ECC_SECP_R1_384), NO_FEATURE }, + ecdh && IS_DEFINED(PSA_WANT_ECC_SECP_R1_384), NOT_CHECKED }, { "secp521r1 ECDH", ecc, 521, PSA_ALG_ECDH, - ecdh && IS_DEFINED(PSA_WANT_ECC_SECP_R1_521), NO_FEATURE }, + ecdh && IS_DEFINED(PSA_WANT_ECC_SECP_R1_521), NOT_CHECKED }, { "X25519", mont, 255, PSA_ALG_ECDH, - ecdh && IS_DEFINED(PSA_WANT_ECC_MONTGOMERY_255), NO_FEATURE }, + ecdh && IS_DEFINED(PSA_WANT_ECC_MONTGOMERY_255), NOT_CHECKED }, { "X448", mont, 448, PSA_ALG_ECDH, - ecdh && IS_DEFINED(PSA_WANT_ECC_MONTGOMERY_448), NO_FEATURE }, + ecdh && IS_DEFINED(PSA_WANT_ECC_MONTGOMERY_448), NOT_CHECKED }, + { "Ed25519 export", ed, 255, PSA_ALG_PURE_EDDSA, + eddsa && IS_DEFINED(PSA_WANT_ECC_TWISTED_EDWARDS_255), + NOT_CHECKED }, + { "Ed448 export", ed, 448, PSA_ALG_PURE_EDDSA, + eddsa && IS_DEFINED(PSA_WANT_ECC_TWISTED_EDWARDS_448), + NOT_CHECKED }, { "AES-128-GCM", PSA_KEY_TYPE_AES, 128, PSA_ALG_GCM, aes && IS_DEFINED(PSA_WANT_ALG_GCM), aesC && IS_DEFINED(MBEDTLS_GCM_C) }, @@ -187,7 +218,13 @@ int main(void) { "HMAC-SHA-256", PSA_KEY_TYPE_HMAC, 256, PSA_ALG_HMAC(PSA_ALG_SHA_256), IS_DEFINED(PSA_WANT_KEY_TYPE_HMAC) && - IS_DEFINED(PSA_WANT_ALG_HMAC), NO_FEATURE }, + IS_DEFINED(PSA_WANT_ALG_HMAC), NOT_CHECKED }, + { "ML-KEM-1024 export", PSA_KEY_TYPE_ML_KEM_KEY_PAIR, 1024, + PSA_ALG_ML_KEM, FAMILY_WANT(IS_DEFINED(PSA_WANT_KEY_TYPE_ML_KEM)), + NOT_CHECKED }, + { "ML-DSA-87 export", PSA_KEY_TYPE_ML_DSA_KEY_PAIR, 256, + PSA_ALG_ML_DSA, FAMILY_WANT(IS_DEFINED(PSA_WANT_KEY_TYPE_ML_DSA)), + NOT_CHECKED }, }; size_t i; psa_status_t status; diff --git a/tools/psa_want_probe.c b/tools/psa_want_probe.c index 3038c2d2..820361de 100644 --- a/tools/psa_want_probe.c +++ b/tools/psa_want_probe.c @@ -39,11 +39,14 @@ * rather than so this probe preprocesses without * dragging in the Zephyr kernel headers settings.h pulls under WOLFSSL_ZEPHYR; * every feature macro this probe tests is materialized by user_settings.h. - * The Makefile build includes settings.h, which adds macros such as - * HAVE_ALL_CURVES. */ + * The Makefile build includes config.h and settings.h as src/ does; settings.h + * adds macros such as HAVE_ALL_CURVES. */ #if defined(__ZEPHYR__) #include "user_settings.h" #else +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ #include #endif /* __ZEPHYR__ */ @@ -146,16 +149,23 @@ __WPSA_EMIT__PSA_WANT_ALG_RSA_OAEP #endif #endif /* !NO_RSA */ -/* ----- ECC (secp r1) ----- */ -#if defined(HAVE_ECC) +/* ----- ECC key types, for every curve family ----- */ +#if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || defined(HAVE_CURVE448) || \ + defined(HAVE_ED25519) || defined(HAVE_ED448) __WPSA_EMIT__PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY __WPSA_EMIT__PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC __WPSA_EMIT__PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT __WPSA_EMIT__PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT __WPSA_EMIT__PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE +#endif +#if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || defined(HAVE_CURVE448) +__WPSA_EMIT__PSA_WANT_ALG_ECDH +#endif + +/* ----- ECC (secp r1) ----- */ +#if defined(HAVE_ECC) __WPSA_EMIT__PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE __WPSA_EMIT__PSA_WANT_ALG_ECDSA -__WPSA_EMIT__PSA_WANT_ALG_ECDH #if defined(WOLFSSL_ECDSA_DETERMINISTIC_K) __WPSA_EMIT__PSA_WANT_ALG_DETERMINISTIC_ECDSA #endif @@ -179,6 +189,19 @@ __WPSA_EMIT__PSA_WANT_ECC_MONTGOMERY_255 __WPSA_EMIT__PSA_WANT_ECC_MONTGOMERY_448 #endif +/* ----- Edwards curves ----- */ +#if defined(HAVE_ED25519) +__WPSA_EMIT__PSA_WANT_ECC_TWISTED_EDWARDS_255 +__WPSA_EMIT__PSA_WANT_ALG_ED25519PH +#endif +#if defined(HAVE_ED448) +__WPSA_EMIT__PSA_WANT_ECC_TWISTED_EDWARDS_448 +__WPSA_EMIT__PSA_WANT_ALG_ED448PH +#endif +#if defined(HAVE_ED25519) || defined(HAVE_ED448) +__WPSA_EMIT__PSA_WANT_ALG_PURE_EDDSA +#endif + /* ----- KDFs ----- */ #if defined(HAVE_HKDF) __WPSA_EMIT__PSA_WANT_ALG_HKDF diff --git a/wolfpsa/psa/crypto_sizes.h b/wolfpsa/psa/crypto_sizes.h index 078f41ff..a110899e 100644 --- a/wolfpsa/psa/crypto_sizes.h +++ b/wolfpsa/psa/crypto_sizes.h @@ -151,6 +151,8 @@ #define PSA_VENDOR_ECC_MAX_CURVE_BITS 512u #elif defined(PSA_WANT_ECC_MONTGOMERY_448) #define PSA_VENDOR_ECC_MAX_CURVE_BITS 448u +#elif defined(PSA_WANT_ECC_TWISTED_EDWARDS_448) +#define PSA_VENDOR_ECC_MAX_CURVE_BITS 448u #elif defined(PSA_WANT_ECC_SECP_R1_384) #define PSA_VENDOR_ECC_MAX_CURVE_BITS 384u #elif defined(PSA_WANT_ECC_BRAINPOOL_P_R1_384) @@ -163,6 +165,8 @@ #define PSA_VENDOR_ECC_MAX_CURVE_BITS 256u #elif defined(PSA_WANT_ECC_MONTGOMERY_255) #define PSA_VENDOR_ECC_MAX_CURVE_BITS 255u +#elif defined(PSA_WANT_ECC_TWISTED_EDWARDS_255) +#define PSA_VENDOR_ECC_MAX_CURVE_BITS 255u #else #define PSA_VENDOR_ECC_MAX_CURVE_BITS 0u #endif @@ -469,6 +473,12 @@ #undef PSA_EXPORT_PUBLIC_KEY_MAX_SIZE #define PSA_EXPORT_PUBLIC_KEY_MAX_SIZE 2592u #endif +/* ML-KEM-1024 public key (1568 bytes) */ +#if defined(PSA_WANT_KEY_TYPE_ML_KEM) && \ + (1568u > PSA_EXPORT_PUBLIC_KEY_MAX_SIZE) +#undef PSA_EXPORT_PUBLIC_KEY_MAX_SIZE +#define PSA_EXPORT_PUBLIC_KEY_MAX_SIZE 1568u +#endif #define PSA_EXPORT_KEY_PAIR_OR_PUBLIC_MAX_SIZE \ ((PSA_EXPORT_KEY_PAIR_MAX_SIZE > PSA_EXPORT_PUBLIC_KEY_MAX_SIZE) ? \ From 88d012dddae8104a3965f4ceace447f0d73336c6 Mon Sep 17 00:00:00 2001 From: Paul Adelsbach Date: Sun, 1 Nov 2026 17:46:25 -0800 Subject: [PATCH 3/6] Ensure MBEDTLS_FS_IO and NO_FILESYSTEM agree, add no-filesystem to CI --- .github/workflows/build-config-matrix.yml | 2 ++ src/psa_tf_psa.c | 5 +++++ tools/gen-crypto-config.py | 16 +++++++++++++--- tools/psa_want_probe.c | 5 +++++ wolfpsa/psa/crypto_config.h | 3 --- 5 files changed, 25 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-config-matrix.yml b/.github/workflows/build-config-matrix.yml index 026ddf1a..12b12f7f 100644 --- a/.github/workflows/build-config-matrix.yml +++ b/.github/workflows/build-config-matrix.yml @@ -98,6 +98,8 @@ jobs: - name: no-rng modifiers: "+WC_NO_RNG +WC_BLINDING_NO_RNG_ACKNOWLEDGE_WEAKNESS" target: psa-objects + - name: no-filesystem + modifiers: "+NO_FILESYSTEM +WOLFPSA_CUSTOM_STORE" steps: - name: Check out wolfPSA diff --git a/src/psa_tf_psa.c b/src/psa_tf_psa.c index d2391c92..f0fcbebb 100644 --- a/src/psa_tf_psa.c +++ b/src/psa_tf_psa.c @@ -34,6 +34,11 @@ #include #include +/* The generated crypto config must match the build's NO_FILESYSTEM */ +#if defined(MBEDTLS_FS_IO) == defined(NO_FILESYSTEM) + #error "MBEDTLS_FS_IO must be defined exactly when NO_FILESYSTEM is not" +#endif + void mbedtls_psa_crypto_free(void) { wolfPSA_CryptoCleanup(); diff --git a/tools/gen-crypto-config.py b/tools/gen-crypto-config.py index 45bdc81f..15daa3f5 100644 --- a/tools/gen-crypto-config.py +++ b/tools/gen-crypto-config.py @@ -8,6 +8,7 @@ # configuration, by preprocessing psa_want_probe.c with the same flags as the # rest of the build. The result is the consumer-visible PSA_WANT_ surface: # exactly the algorithm families wolfCrypt has enabled AND wolfPSA implements. +# It also has MBEDTLS_FS_IO unless the build defines NO_FILESYSTEM. # # Python (not shell) to fit the Zephyr build ecosystem, invoked via CMake's # PYTHON_EXECUTABLE from wolfPSA's zephyr/CMakeLists.txt, and by the Makefile. @@ -40,7 +41,7 @@ * derived from the wolfCrypt features actually enabled in this build intersected * with what wolfPSA implements. wolfpsa/psa/crypto.h -> crypto_config.h includes * it, so PSA sizing macros (crypto_sizes.h) and consumer PSA_WANT_-gated code - * track the real build. + * track the real build. MBEDTLS_FS_IO is defined unless NO_FILESYSTEM is. */ #ifndef {guard} @@ -52,6 +53,8 @@ EMIT_TAG = "__WPSA_EMIT__" WANT_RE = re.compile(r"PSA_WANT_[A-Z0-9_]+") +# TF-PSA-Crypto platform options, defined without a value as in TF-PSA +OPTION_RE = re.compile(r"MBEDTLS_FS_IO") def main(argv): @@ -74,12 +77,18 @@ def main(argv): sys.stderr.write("gen-crypto-config.py: preprocessing the probe failed\n") return 1 - # Collect PSA_WANT_ symbols from the surviving __WPSA_EMIT__ lines only. + # Collect symbols from the surviving __WPSA_EMIT__ lines only. + emitted = [line for line in preprocessed.splitlines() if EMIT_TAG in line] wants = sorted({ match.group(0) - for line in preprocessed.splitlines() if EMIT_TAG in line + for line in emitted for match in WANT_RE.finditer(line) }) + options = sorted({ + match.group(0) + for line in emitted + for match in OPTION_RE.finditer(line) + }) if not wants: sys.stderr.write( @@ -90,6 +99,7 @@ def main(argv): guard = "WOLFPSA_" + re.sub(r"[^A-Z0-9]", "_", name.upper()) text = (HEADER.format(name=name, guard=guard) + "".join("#define {} 1\n".format(want) for want in wants) + + "".join("#define {}\n".format(option) for option in options) + FOOTER.format(guard=guard)) # Unchanged content keeps its timestamp, so nothing rebuilds diff --git a/tools/psa_want_probe.c b/tools/psa_want_probe.c index 820361de..a27cb925 100644 --- a/tools/psa_want_probe.c +++ b/tools/psa_want_probe.c @@ -234,3 +234,8 @@ __WPSA_EMIT__PSA_WANT_KEY_TYPE_ML_KEM #if defined(WOLFSSL_HAVE_MLDSA) __WPSA_EMIT__PSA_WANT_KEY_TYPE_ML_DSA #endif + +/* ----- TF-PSA-Crypto platform options ----- */ +#if !defined(NO_FILESYSTEM) +__WPSA_EMIT__MBEDTLS_FS_IO +#endif diff --git a/wolfpsa/psa/crypto_config.h b/wolfpsa/psa/crypto_config.h index 3d333b41..7971087a 100644 --- a/wolfpsa/psa/crypto_config.h +++ b/wolfpsa/psa/crypto_config.h @@ -32,9 +32,6 @@ /* Generated by the Makefile */ #include "crypto_config_generated.h" -/* TF-PSA-Crypto platform option: the platform has stdio files */ -#define MBEDTLS_FS_IO - #endif /* CONFIG_WOLFPSA */ #endif From 35e07800829eb3b8806890aa5031f078bf77df9f Mon Sep 17 00:00:00 2001 From: Paul Adelsbach Date: Mon, 2 Nov 2026 13:17:15 -0800 Subject: [PATCH 4/6] Generate PSA_WANT_* into the build dir, fix max sizes --- .github/workflows/build-config-matrix.yml | 9 ++-- .github/workflows/test-psa-api.yml | 5 ++ .gitignore | 1 - Makefile | 19 +++++-- README.md | 6 +++ src/psa_key_storage.c | 2 + test-psa-api/psa-crypto-tests.sh | 2 +- test/Makefile | 6 ++- test/psa_server/psa_want_surface_test.c | 62 +++++++++++++++++++++-- test/wolfcrypt-benchmark/Makefile | 2 +- tools/gen-crypto-config.py | 14 +++-- tools/psa_want_probe.c | 59 ++++++++++++++------- wolfpsa/psa/crypto_extra.h | 3 +- wolfpsa/psa/crypto_sizes.h | 19 +++++++ wolfpsa/tf-psa-crypto/build_info.h | 4 +- zephyr/CMakeLists.txt | 5 +- 16 files changed, 172 insertions(+), 46 deletions(-) diff --git a/.github/workflows/build-config-matrix.yml b/.github/workflows/build-config-matrix.yml index 12b12f7f..702c6f80 100644 --- a/.github/workflows/build-config-matrix.yml +++ b/.github/workflows/build-config-matrix.yml @@ -92,14 +92,14 @@ jobs: modifiers: "-HAVE_ECC -HAVE_ECC_ENCRYPT" - name: rsa-1024 modifiers: "-WOLFSSL_SP_1024 -RSA_MIN_SIZE +RSA_MIN_SIZE=2048" - # wolfPSA's own sources only: the bundled wolfCrypt sources do not - # build under WC_NO_RNG (asn.c trips -Wnonnull), which is a wolfSSL - # issue outside this lane's scope. + - name: no-rsa + modifiers: "+NO_RSA +ECC_USER_CURVES -WOLFSSL_HAVE_MLDSA" - name: no-rng modifiers: "+WC_NO_RNG +WC_BLINDING_NO_RNG_ACKNOWLEDGE_WEAKNESS" target: psa-objects - name: no-filesystem modifiers: "+NO_FILESYSTEM +WOLFPSA_CUSTOM_STORE" + target: libwolfpsa.a steps: - name: Check out wolfPSA @@ -113,9 +113,10 @@ jobs: - name: Clone sibling wolfSSL run: git clone --depth 1 --branch ${{ matrix.wolfssl-ref }} https://github.com/wolfSSL/wolfssl ../wolfssl + # Builds the library, then runs the PSA_WANT_* surface test against it - name: Build ${{ matrix.config.name }} env: - BUILD_TARGET: ${{ matrix.config.target || 'libwolfpsa.so' }} + BUILD_TARGET: ${{ matrix.config.target || 'want-surface-test' }} # Fail on undefined symbols LDFLAGS: -Wl,-z,defs run: ./build-test/build-variant.sh "${{ matrix.config.name }}" ${{ matrix.config.modifiers }} diff --git a/.github/workflows/test-psa-api.yml b/.github/workflows/test-psa-api.yml index f0aa934c..753265ed 100644 --- a/.github/workflows/test-psa-api.yml +++ b/.github/workflows/test-psa-api.yml @@ -65,6 +65,11 @@ jobs: ./test/psa_ecc_verify_curve_test ./test/psa_ecc_ecdh_curve_test + - name: Run the PSA_WANT surface test + run: | + make want-surface-test \ + USER_SETTINGS_PATH="${GITHUB_WORKSPACE}/build-ecc-var" + test-psa-api: runs-on: ubuntu-latest strategy: diff --git a/.gitignore b/.gitignore index 65a12c71..c41b6d25 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ build -wolfpsa/psa/crypto_config_generated.h # gcov coverage artifacts (make cov) *.gcda *.gcno diff --git a/Makefile b/Makefile index 7d153120..c0dfa083 100644 --- a/Makefile +++ b/Makefile @@ -82,7 +82,8 @@ WOLFCRYPT_OBJ_PIC := $(patsubst $(WOLFSSL_PATH)/wolfcrypt/src/%.c,$(OBJDIR_PIC)/ WOLFSSL_CPPFLAGS ?= -DWOLFSSL_USER_SETTINGS CPPFLAGS += -I$(WOLFSSL_PATH) -I$(USER_SETTINGS_PATH) \ - -I$(CURDIR) -I$(CURDIR)/wolfpsa -I$(CURDIR)/src $(WOLFSSL_CPPFLAGS) + -I$(CURDIR) -I$(CURDIR)/wolfpsa -I$(CURDIR)/src -I$(BUILD_DIR)/include \ + $(WOLFSSL_CPPFLAGS) ifneq ($(strip $(PSA_INCLUDE)),) CPPFLAGS += -I$(PSA_INCLUDE) endif @@ -118,7 +119,8 @@ CFLAGS += --coverage LDFLAGS += --coverage endif -.PHONY: all clean psa-objects unit-run run-tests cov covclean +.PHONY: all clean psa-objects unit-run run-tests cov covclean \ + want-surface-test all: $(LIBNAME) $(SHLIBNAME) @@ -136,10 +138,12 @@ $(SHLIBNAME): $(OBJ_PIC) $(WOLFCRYPT_OBJ_PIC) $(EXPORT_MAP) $(CC) -shared -Wl,--version-script,$(EXPORT_MAP) -Wl,-Bsymbolic-functions -o $@ $(filter-out $(EXPORT_MAP),$^) $(LDFLAGS) # Build the PSA_WANT_* macros based on what the wolfCrypt build supports. -PSA_CONFIG := wolfpsa/psa/crypto_config_generated.h +# Consumers of add $(BUILD_DIR)/include to the include path. +PSA_CONFIG := $(BUILD_DIR)/include/crypto_config_generated.h PYTHON ?= python3 $(PSA_CONFIG): FORCE + @mkdir -p $(dir $@) $(PYTHON) tools/gen-crypto-config.py $@ "$(CC)" \ tools/psa_want_probe.c $(CPPFLAGS) $(CFLAGS) @@ -147,6 +151,13 @@ $(OBJ) $(OBJ_PIC): $(PSA_CONFIG) FORCE: +# Check the PSA_WANT_* surface of this build against its static library +want-surface-test: $(LIBNAME) + $(CC) $(CPPFLAGS) $(CFLAGS) -o $(BUILD_DIR)/psa_want_surface_test \ + test/psa_server/psa_want_surface_test.c $(LIBNAME) $(LDFLAGS) \ + -lpthread -lm + $(BUILD_DIR)/psa_want_surface_test + $(OBJDIR)/%.o: src/%.c @mkdir -p $(OBJDIR) $(CC) $(CPPFLAGS) $(DEPFLAGS) $(CFLAGS) -c $< -o $@ @@ -286,7 +297,7 @@ covclean: rm -rf $(COV_DIR) clean: - rm -rf $(BUILD_DIR) $(LIBNAME) $(SHLIBNAME) $(PSA_CONFIG) + rm -rf $(BUILD_DIR) $(LIBNAME) $(SHLIBNAME) -include $(OBJ:.o=.d) $(WOLFCRYPT_OBJ:.o=.d) -include $(OBJ_PIC:.o=.d) $(WOLFCRYPT_OBJ_PIC:.o=.d) diff --git a/README.md b/README.md index fcfeb8fa..be6e8877 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,12 @@ You can override the wolfSSL source location: make wolfPSA WOLFSSL_PATH=~/src/wolfssl ``` +The build generates the `PSA_WANT_*` macros from the wolfCrypt configuration +into `$(BUILD_DIR)/include/crypto_config_generated.h` (`build/include` by +default), using python3. Set `PYTHON` to use another interpreter. Code that +includes `` needs that directory on its include path next to +`wolfpsa/`, and builds only after `make` has generated the header. + ## Testing (PSA Architecture Test Suite) See `test-psa-api/README.md` for instructions on how to run the tests. diff --git a/src/psa_key_storage.c b/src/psa_key_storage.c index 120eaba1..0ee86474 100644 --- a/src/psa_key_storage.c +++ b/src/psa_key_storage.c @@ -192,6 +192,7 @@ psa_status_t psa_asymmetric_export_public_key_ecc(psa_key_type_t key_type, size_t *output_length); #endif +#ifndef NO_RSA static psa_status_t psa_wc_error_to_psa_status(int ret) { psa_status_t status; @@ -224,6 +225,7 @@ static psa_status_t psa_wc_error_to_psa_status(int ret) return status; } +#endif /* !NO_RSA */ static psa_status_t wolfpsa_validate_stored_key_data_length(size_t key_data_length) diff --git a/test-psa-api/psa-crypto-tests.sh b/test-psa-api/psa-crypto-tests.sh index 28b112d6..d5abd54a 100755 --- a/test-psa-api/psa-crypto-tests.sh +++ b/test-psa-api/psa-crypto-tests.sh @@ -8,7 +8,7 @@ PATCH_FILE="${SCRIPT_DIR}/psa-arch-tests_ec_overflow.patch" TARGET_NAME="tgt_dev_apis_wolfpsa" TARGET_SRC_DIR="${SCRIPT_DIR}/${TARGET_NAME}" TARGET_DST_DIR="${PSA_ARCH_TESTS_DIR}/api-tests/platform/targets/${TARGET_NAME}" -PSA_INCLUDE_PATHS="${REPO_ROOT}/wolfpsa" +PSA_INCLUDE_PATHS="${REPO_ROOT}/wolfpsa;${REPO_ROOT}/build/include" PSA_CRYPTO_LIB_FILENAME="${REPO_ROOT}/libwolfpsa.a" PSA_STORAGE_LIB_FILENAME="" PSA_ARCH_TESTS_REPO=${PSA_ARCH_TESTS_REPO:-"https://github.com/ARM-software/psa-arch-tests.git"} diff --git a/test/Makefile b/test/Makefile index e30aae89..74a4dd47 100644 --- a/test/Makefile +++ b/test/Makefile @@ -56,6 +56,7 @@ ifneq ($(WOLFSSL_BUILD_DIR),) CPPFLAGS += -I$(WOLFSSL_BUILD_DIR) endif CPPFLAGS += -I$(WOLFPSA_PATH) -I$(WOLFPSA_PATH)/wolfpsa +CPPFLAGS += -I$(WOLFPSA_PATH)/$(BUILD_DIR)/include CPPFLAGS += -I$(WOLFPSA_PATH)/src CPPFLAGS += -I$(WOLFPSA_PATH)/test/psa_server @@ -214,7 +215,7 @@ CRYPTOCB_BUILD_DIR := $(abspath .)/build-cryptocb$(if $(SANITIZE_FLAGS),-asan) CRYPTOCB_LIB := $(CRYPTOCB_BUILD_DIR)/libwolfpsa-cryptocb.a CRYPTOCB_CPPFLAGS := -DWOLFSSL_USER_SETTINGS -DWOLF_CRYPTO_CB \ -I$(abspath $(WOLFSSL_PATH)) -I$(WOLFPSA_ABS) -I$(WOLFPSA_ABS)/wolfpsa \ - -I$(WOLFPSA_ABS)/src + -I$(WOLFPSA_ABS)/src -I$(CRYPTOCB_BUILD_DIR)/include # FORCE, because only the sub-make knows whether a library source changed. # Without it make treats the existing archive as permanently up to date and @@ -305,7 +306,8 @@ rebuild-wolfssl-psa: $(WOLFPSA_PATH)/libwolfpsa.so --with-psa-lib="$(WOLFPSA_ABS)" \ --with-psa-lib-name=wolfpsa \ CFLAGS="-O2 $(DEBUG_FLAGS) $(SANITIZE_FLAGS)" \ - CPPFLAGS="-DWOLFSSL_PSA_NO_RNG -DWOLFSSL_PSA_NO_HASH -DWOLFSSL_PSA_NO_AES" \ + CPPFLAGS="-DWOLFSSL_PSA_NO_RNG -DWOLFSSL_PSA_NO_HASH -DWOLFSSL_PSA_NO_AES \ + -I$(WOLFPSA_ABS)/$(BUILD_DIR)/include" \ LDFLAGS="$(SANITIZE_FLAGS) -Wl,-rpath,$(WOLFPSA_ABS) -Wl,-rpath-link,$(WOLFPSA_ABS)" $(MAKE) -C "$(WOLFSSL_PATH)" CFLAGS="-O2 $(DEBUG_FLAGS) $(SANITIZE_FLAGS)" LDFLAGS="$(SANITIZE_FLAGS) -Wl,-rpath,$(WOLFPSA_ABS) -Wl,-rpath-link,$(WOLFPSA_ABS)" src/libwolfssl.la diff --git a/test/psa_server/psa_want_surface_test.c b/test/psa_server/psa_want_surface_test.c index 8f6219b0..daaa92ae 100644 --- a/test/psa_server/psa_want_surface_test.c +++ b/test/psa_server/psa_want_surface_test.c @@ -62,6 +62,22 @@ static psa_status_t run_export(psa_key_id_t key) return status; } +static psa_status_t run_sign(psa_key_id_t key, psa_algorithm_t alg) +{ + uint8_t msg[16]; + uint8_t sig[PSA_SIGNATURE_MAX_SIZE]; + size_t len = 0; + psa_status_t status; + + memset(msg, 0, sizeof(msg)); + status = run_export(key); + if (status == PSA_SUCCESS) { + status = psa_sign_message(key, alg, msg, sizeof(msg), sig, + sizeof(sig), &len); + } + return status; +} + static psa_status_t run_ecdh(psa_key_id_t key) { uint8_t pub[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE]; @@ -126,6 +142,10 @@ static psa_status_t run_case(const struct want_case* c) else if (PSA_ALG_IS_MAC(c->alg)) { psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_SIGN_MESSAGE); } + else if (PSA_ALG_IS_SIGN(c->alg)) { + psa_set_key_usage_flags(&attr, + PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_EXPORT); + } else { psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_EXPORT); } @@ -141,6 +161,9 @@ static psa_status_t run_case(const struct want_case* c) else if (PSA_ALG_IS_MAC(c->alg)) { status = run_mac(key, c->alg); } + else if (PSA_ALG_IS_SIGN(c->alg)) { + status = run_sign(key, c->alg); + } else { status = run_export(key); } @@ -154,7 +177,9 @@ static void check_case(const struct want_case* c) psa_status_t status = run_case(c); int supported = (status == PSA_SUCCESS); - if (status != PSA_SUCCESS && status != PSA_ERROR_NOT_SUPPORTED) { + /* Without its PSA_WANT_ macros, a case may fail with any error */ + if (status != PSA_SUCCESS && status != PSA_ERROR_NOT_SUPPORTED && + c->want != 0) { printf("FAIL %s: status %d\n", c->name, (int)status); failures++; } @@ -177,12 +202,19 @@ int main(void) { const psa_key_type_t ecc = PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1); + const psa_key_type_t k1 = + PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_K1); + const psa_key_type_t bp = + PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_BRAINPOOL_P_R1); const psa_key_type_t mont = PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY); const psa_key_type_t ed = PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_TWISTED_EDWARDS); + const psa_algorithm_t ecdsaAlg = PSA_ALG_ECDSA(PSA_ALG_SHA_256); const int ecdh = IS_DEFINED(PSA_WANT_ALG_ECDH) && IS_DEFINED(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE); + const int ecdsa = IS_DEFINED(PSA_WANT_ALG_ECDSA) && + IS_DEFINED(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE); const int eddsa = IS_DEFINED(PSA_WANT_ALG_PURE_EDDSA) && IS_DEFINED(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE); const int aes = IS_DEFINED(PSA_WANT_KEY_TYPE_AES); @@ -194,14 +226,31 @@ int main(void) ecdh && IS_DEFINED(PSA_WANT_ECC_SECP_R1_384), NOT_CHECKED }, { "secp521r1 ECDH", ecc, 521, PSA_ALG_ECDH, ecdh && IS_DEFINED(PSA_WANT_ECC_SECP_R1_521), NOT_CHECKED }, + { "secp256r1 ECDSA", ecc, 256, ecdsaAlg, + ecdsa && IS_DEFINED(PSA_WANT_ECC_SECP_R1_256), NOT_CHECKED }, + { "secp384r1 ECDSA", ecc, 384, ecdsaAlg, + ecdsa && IS_DEFINED(PSA_WANT_ECC_SECP_R1_384), NOT_CHECKED }, + { "secp521r1 ECDSA", ecc, 521, ecdsaAlg, + ecdsa && IS_DEFINED(PSA_WANT_ECC_SECP_R1_521), NOT_CHECKED }, + { "secp256k1 ECDH", k1, 256, PSA_ALG_ECDH, + ecdh && IS_DEFINED(PSA_WANT_ECC_SECP_K1_256), NOT_CHECKED }, + { "brainpoolP256r1 ECDH", bp, 256, PSA_ALG_ECDH, + ecdh && IS_DEFINED(PSA_WANT_ECC_BRAINPOOL_P_R1_256), + NOT_CHECKED }, + { "brainpoolP384r1 ECDH", bp, 384, PSA_ALG_ECDH, + ecdh && IS_DEFINED(PSA_WANT_ECC_BRAINPOOL_P_R1_384), + NOT_CHECKED }, + { "brainpoolP512r1 ECDH", bp, 512, PSA_ALG_ECDH, + ecdh && IS_DEFINED(PSA_WANT_ECC_BRAINPOOL_P_R1_512), + NOT_CHECKED }, { "X25519", mont, 255, PSA_ALG_ECDH, ecdh && IS_DEFINED(PSA_WANT_ECC_MONTGOMERY_255), NOT_CHECKED }, { "X448", mont, 448, PSA_ALG_ECDH, ecdh && IS_DEFINED(PSA_WANT_ECC_MONTGOMERY_448), NOT_CHECKED }, - { "Ed25519 export", ed, 255, PSA_ALG_PURE_EDDSA, + { "Ed25519", ed, 255, PSA_ALG_PURE_EDDSA, eddsa && IS_DEFINED(PSA_WANT_ECC_TWISTED_EDWARDS_255), NOT_CHECKED }, - { "Ed448 export", ed, 448, PSA_ALG_PURE_EDDSA, + { "Ed448", ed, 448, PSA_ALG_PURE_EDDSA, eddsa && IS_DEFINED(PSA_WANT_ECC_TWISTED_EDWARDS_448), NOT_CHECKED }, { "AES-128-GCM", PSA_KEY_TYPE_AES, 128, PSA_ALG_GCM, @@ -222,9 +271,14 @@ int main(void) { "ML-KEM-1024 export", PSA_KEY_TYPE_ML_KEM_KEY_PAIR, 1024, PSA_ALG_ML_KEM, FAMILY_WANT(IS_DEFINED(PSA_WANT_KEY_TYPE_ML_KEM)), NOT_CHECKED }, - { "ML-DSA-87 export", PSA_KEY_TYPE_ML_DSA_KEY_PAIR, 256, + { "ML-DSA-87", PSA_KEY_TYPE_ML_DSA_KEY_PAIR, 256, PSA_ALG_ML_DSA, FAMILY_WANT(IS_DEFINED(PSA_WANT_KEY_TYPE_ML_DSA)), NOT_CHECKED }, + { "RSA-2048 PKCS#1 v1.5", PSA_KEY_TYPE_RSA_KEY_PAIR, 2048, + PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_SHA_256), + IS_DEFINED(PSA_WANT_ALG_RSA_PKCS1V15_SIGN) && + IS_DEFINED(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE), + NOT_CHECKED }, }; size_t i; psa_status_t status; diff --git a/test/wolfcrypt-benchmark/Makefile b/test/wolfcrypt-benchmark/Makefile index 914ad6c5..e8402b7b 100644 --- a/test/wolfcrypt-benchmark/Makefile +++ b/test/wolfcrypt-benchmark/Makefile @@ -13,7 +13,7 @@ WOLFPSA_DEVID ?= 0x505341 CFLAGS ?= -O2 CPPFLAGS += -I$(WOLFSSL_PATH) -I$(WOLFSSL_PATH)/wolfssl -CPPFLAGS += -I$(WOLFPSA_PATH)/wolfpsa +CPPFLAGS += -I$(WOLFPSA_PATH)/wolfpsa -I$(WOLFPSA_PATH)/build/include CPPFLAGS += -DWOLFSSL_USER_SETTINGS -U HAVE_CONFIG_H CPPFLAGS += -DWOLFSSL_HAVE_PSA CPPFLAGS += -DWOLFPSA_DEVID=$(WOLFPSA_DEVID) diff --git a/tools/gen-crypto-config.py b/tools/gen-crypto-config.py index 15daa3f5..008eea82 100644 --- a/tools/gen-crypto-config.py +++ b/tools/gen-crypto-config.py @@ -8,7 +8,8 @@ # configuration, by preprocessing psa_want_probe.c with the same flags as the # rest of the build. The result is the consumer-visible PSA_WANT_ surface: # exactly the algorithm families wolfCrypt has enabled AND wolfPSA implements. -# It also has MBEDTLS_FS_IO unless the build defines NO_FILESYSTEM. +# It also has the TF-PSA-Crypto options the build supports, such as +# MBEDTLS_FS_IO. # # Python (not shell) to fit the Zephyr build ecosystem, invoked via CMake's # PYTHON_EXECUTABLE from wolfPSA's zephyr/CMakeLists.txt, and by the Makefile. @@ -41,7 +42,7 @@ * derived from the wolfCrypt features actually enabled in this build intersected * with what wolfPSA implements. wolfpsa/psa/crypto.h -> crypto_config.h includes * it, so PSA sizing macros (crypto_sizes.h) and consumer PSA_WANT_-gated code - * track the real build. MBEDTLS_FS_IO is defined unless NO_FILESYSTEM is. + * track the real build, as do the MBEDTLS_ options it defines. */ #ifndef {guard} @@ -53,8 +54,8 @@ EMIT_TAG = "__WPSA_EMIT__" WANT_RE = re.compile(r"PSA_WANT_[A-Z0-9_]+") -# TF-PSA-Crypto platform options, defined without a value as in TF-PSA -OPTION_RE = re.compile(r"MBEDTLS_FS_IO") +# TF-PSA-Crypto options, defined without a value as in TF-PSA +OPTION_RE = re.compile(r"MBEDTLS_[A-Z0-9_]+") def main(argv): @@ -109,8 +110,11 @@ def main(argv): return 0 except OSError: pass - with open(out_path, "w") as out_file: + # Replace atomically, so a parallel compile never reads a partial header + tmp_path = out_path + ".tmp" + with open(tmp_path, "w") as out_file: out_file.write(text) + os.replace(tmp_path, out_path) return 0 diff --git a/tools/psa_want_probe.c b/tools/psa_want_probe.c index a27cb925..65aa6541 100644 --- a/tools/psa_want_probe.c +++ b/tools/psa_want_probe.c @@ -30,25 +30,15 @@ * exactly "what wolfCrypt compiled" intersected with "what wolfPSA implements". * * Excluded on purpose (wolfPSA has no PSA binding): finite-field DH, PAKE, - * Camellia, ARIA, ECC Brainpool/Koblitz. Keep this in sync with src/ when a - * feature graduates. + * Camellia, ARIA. Keep this in sync with src/ when a feature graduates. */ -/* Pull in the effective wolfCrypt feature configuration (the module's - * user_settings.h + wolfPSA baseline). We include user_settings.h directly - * rather than so this probe preprocesses without - * dragging in the Zephyr kernel headers settings.h pulls under WOLFSSL_ZEPHYR; - * every feature macro this probe tests is materialized by user_settings.h. - * The Makefile build includes config.h and settings.h as src/ does; settings.h - * adds macros such as HAVE_ALL_CURVES. */ -#if defined(__ZEPHYR__) -#include "user_settings.h" -#else +/* The wolfCrypt configuration as src/ sees it. The Zephyr build defines + * __ASSEMBLER__ so settings.h skips the Zephyr kernel headers. */ #ifdef HAVE_CONFIG_H #include #endif /* HAVE_CONFIG_H */ #include -#endif /* __ZEPHYR__ */ /* ----- Hashes ----- */ #if !defined(NO_SHA) @@ -162,23 +152,51 @@ __WPSA_EMIT__PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE __WPSA_EMIT__PSA_WANT_ALG_ECDH #endif -/* ----- ECC (secp r1) ----- */ +/* ----- ECC (secp, Koblitz, Brainpool) ----- */ #if defined(HAVE_ECC) __WPSA_EMIT__PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE __WPSA_EMIT__PSA_WANT_ALG_ECDSA #if defined(WOLFSSL_ECDSA_DETERMINISTIC_K) __WPSA_EMIT__PSA_WANT_ALG_DETERMINISTIC_ECDSA #endif -/* The curves as wolfCrypt's ecc.c enables them */ +/* The curve sizes as wolfCrypt's ecc.c enables them */ #if (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 256 -__WPSA_EMIT__PSA_WANT_ECC_SECP_R1_256 +#define WPSA_ECC256 #endif #if (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 384 -__WPSA_EMIT__PSA_WANT_ECC_SECP_R1_384 +#define WPSA_ECC384 +#endif +#if (defined(HAVE_ECC512) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 512 +#define WPSA_ECC512 #endif #if (defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 521 +#define WPSA_ECC521 +#endif +#if !defined(NO_ECC_SECP) +#if defined(WPSA_ECC256) +__WPSA_EMIT__PSA_WANT_ECC_SECP_R1_256 +#endif +#if defined(WPSA_ECC384) +__WPSA_EMIT__PSA_WANT_ECC_SECP_R1_384 +#endif +#if defined(WPSA_ECC521) __WPSA_EMIT__PSA_WANT_ECC_SECP_R1_521 #endif +#endif /* !NO_ECC_SECP */ +#if defined(HAVE_ECC_KOBLITZ) && defined(WPSA_ECC256) +__WPSA_EMIT__PSA_WANT_ECC_SECP_K1_256 +#endif +#if defined(HAVE_ECC_BRAINPOOL) +#if defined(WPSA_ECC256) +__WPSA_EMIT__PSA_WANT_ECC_BRAINPOOL_P_R1_256 +#endif +#if defined(WPSA_ECC384) +__WPSA_EMIT__PSA_WANT_ECC_BRAINPOOL_P_R1_384 +#endif +#if defined(WPSA_ECC512) +__WPSA_EMIT__PSA_WANT_ECC_BRAINPOOL_P_R1_512 +#endif +#endif /* HAVE_ECC_BRAINPOOL */ #endif /* HAVE_ECC */ /* ----- Montgomery curves ----- */ @@ -235,7 +253,12 @@ __WPSA_EMIT__PSA_WANT_KEY_TYPE_ML_KEM __WPSA_EMIT__PSA_WANT_KEY_TYPE_ML_DSA #endif -/* ----- TF-PSA-Crypto platform options ----- */ +/* ----- TF-PSA-Crypto options ----- */ #if !defined(NO_FILESYSTEM) __WPSA_EMIT__MBEDTLS_FS_IO #endif +/* The PSA RNG, wolfCrypt's DRBG. No public API in TF-PSA-Crypto 1.x. */ +#if !defined(WC_NO_RNG) +__WPSA_EMIT__MBEDTLS_ENTROPY_C +__WPSA_EMIT__MBEDTLS_CTR_DRBG_C +#endif diff --git a/wolfpsa/psa/crypto_extra.h b/wolfpsa/psa/crypto_extra.h index 1f194846..a57fa720 100644 --- a/wolfpsa/psa/crypto_extra.h +++ b/wolfpsa/psa/crypto_extra.h @@ -58,7 +58,8 @@ static inline int mbedtls_svc_key_id_is_null(mbedtls_svc_key_id_t key) /* Destroy all volatile keys and return to the state before psa_crypto_init(). * Not thread safe: call when no other PSA call is in progress. Also - * unregisters crypto callbacks; register them again after psa_crypto_init(). */ + * unregisters crypto callbacks when PSA held the last wolfCrypt_Init() + * reference; register them again after psa_crypto_init(). */ void mbedtls_psa_crypto_free(void); #ifdef __cplusplus diff --git a/wolfpsa/psa/crypto_sizes.h b/wolfpsa/psa/crypto_sizes.h index a110899e..837088b2 100644 --- a/wolfpsa/psa/crypto_sizes.h +++ b/wolfpsa/psa/crypto_sizes.h @@ -318,6 +318,16 @@ #undef PSA_SIGNATURE_MAX_SIZE #define PSA_SIGNATURE_MAX_SIZE 4627u #endif +/* Ed448 (114 bytes) and Ed25519 (64 bytes) signatures */ +#if defined(PSA_WANT_ECC_TWISTED_EDWARDS_448) && \ + (114u > PSA_SIGNATURE_MAX_SIZE) +#undef PSA_SIGNATURE_MAX_SIZE +#define PSA_SIGNATURE_MAX_SIZE 114u +#elif defined(PSA_WANT_ECC_TWISTED_EDWARDS_255) && \ + (64u > PSA_SIGNATURE_MAX_SIZE) +#undef PSA_SIGNATURE_MAX_SIZE +#define PSA_SIGNATURE_MAX_SIZE 64u +#endif #define PSA_ASYMMETRIC_ENCRYPT_OUTPUT_SIZE(key_type, key_bits, alg) \ @@ -443,6 +453,15 @@ #define PSA_EXPORT_KEY_PAIR_MAX_SIZE \ PSA_KEY_EXPORT_FFDH_KEY_PAIR_MAX_SIZE(PSA_VENDOR_FFDH_MAX_KEY_BITS) #endif +/* ML-KEM and ML-DSA key pairs export as their 64 and 32 byte seeds */ +#if defined(PSA_WANT_KEY_TYPE_ML_KEM) && (64u > PSA_EXPORT_KEY_PAIR_MAX_SIZE) +#undef PSA_EXPORT_KEY_PAIR_MAX_SIZE +#define PSA_EXPORT_KEY_PAIR_MAX_SIZE 64u +#endif +#if defined(PSA_WANT_KEY_TYPE_ML_DSA) && (32u > PSA_EXPORT_KEY_PAIR_MAX_SIZE) +#undef PSA_EXPORT_KEY_PAIR_MAX_SIZE +#define PSA_EXPORT_KEY_PAIR_MAX_SIZE 32u +#endif #define PSA_EXPORT_PUBLIC_KEY_MAX_SIZE 1 diff --git a/wolfpsa/tf-psa-crypto/build_info.h b/wolfpsa/tf-psa-crypto/build_info.h index 7da0f571..f70d3574 100644 --- a/wolfpsa/tf-psa-crypto/build_info.h +++ b/wolfpsa/tf-psa-crypto/build_info.h @@ -30,9 +30,7 @@ #define MBEDTLS_PSA_CRYPTO_C #define MBEDTLS_PSA_CRYPTO_CLIENT -/* The PSA RNG, wolfCrypt's DRBG. No public API in TF-PSA-Crypto 1.x. */ -#define MBEDTLS_ENTROPY_C -#define MBEDTLS_CTR_DRBG_C +/* MBEDTLS_ENTROPY_C and MBEDTLS_CTR_DRBG_C come from crypto_config.h */ #if defined(PSA_WANT_KEY_TYPE_AES) #define MBEDTLS_AES_C diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index 683d5d79..bf0f2181 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -57,9 +57,10 @@ if(CONFIG_WOLFPSA) set(WOLFPSA_GEN_PY ${WOLFPSA_DIR}/tools/gen-crypto-config.py) file(MAKE_DIRECTORY ${WOLFPSA_GEN_DIR}) + # __ASSEMBLER__: settings.h then skips the Zephyr kernel headers set(_wolfpsa_probe_flags - -D__ZEPHYR__=1 -DWOLFSSL_USER_SETTINGS -DWOLFSSL_ZEPHYR - -I${WOLFPSA_DIR} -I${WOLFPSA_DIR}/wolfpsa + -D__ZEPHYR__=1 -D__ASSEMBLER__ -DWOLFSSL_USER_SETTINGS -DWOLFSSL_ZEPHYR + -I${_wolfssl_mod_dir} -I${WOLFPSA_DIR} -I${WOLFPSA_DIR}/wolfpsa -I${_wolfssl_mod_dir}/zephyr -imacros ${_wolfpsa_autoconf}) # If the user supplied their own wolfCrypt config, the probe must see it too. From 04b256c60a878f21f8a1de0c410ee0fa2ee36446 Mon Sep 17 00:00:00 2001 From: Paul Adelsbach Date: Mon, 2 Nov 2026 18:44:33 -0800 Subject: [PATCH 5/6] Add PSA_WANT_ALG_ECDSA_ANY, PSA_WANT_ALG_RSA_PKCS1V15_SIGN_RAW and PSA_WANT_ALG_RSA_PSS_ANY_SALT to probe --- test/psa_server/psa_want_surface_test.c | 35 +++++++++++++++++++++---- tools/psa_want_probe.c | 5 ++++ 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/test/psa_server/psa_want_surface_test.c b/test/psa_server/psa_want_surface_test.c index daaa92ae..5e0a362e 100644 --- a/test/psa_server/psa_want_surface_test.c +++ b/test/psa_server/psa_want_surface_test.c @@ -64,16 +64,27 @@ static psa_status_t run_export(psa_key_id_t key) static psa_status_t run_sign(psa_key_id_t key, psa_algorithm_t alg) { - uint8_t msg[16]; + uint8_t msg[32]; uint8_t sig[PSA_SIGNATURE_MAX_SIZE]; size_t len = 0; psa_status_t status; memset(msg, 0, sizeof(msg)); status = run_export(key); - if (status == PSA_SUCCESS) { + if (status == PSA_SUCCESS && PSA_ALG_IS_SIGN_MESSAGE(alg)) { status = psa_sign_message(key, alg, msg, sizeof(msg), sig, sizeof(sig), &len); + if (status == PSA_SUCCESS) { + status = psa_verify_message(key, alg, msg, sizeof(msg), sig, len); + } + } + /* Hash-only algorithms such as ECDSA_ANY sign msg as the hash */ + else if (status == PSA_SUCCESS) { + status = psa_sign_hash(key, alg, msg, sizeof(msg), sig, sizeof(sig), + &len); + if (status == PSA_SUCCESS) { + status = psa_verify_hash(key, alg, msg, sizeof(msg), sig, len); + } } return status; } @@ -144,7 +155,9 @@ static psa_status_t run_case(const struct want_case* c) } else if (PSA_ALG_IS_SIGN(c->alg)) { psa_set_key_usage_flags(&attr, - PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_EXPORT); + PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_MESSAGE | + PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH | + PSA_KEY_USAGE_EXPORT); } else { psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_EXPORT); @@ -215,6 +228,9 @@ int main(void) IS_DEFINED(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE); const int ecdsa = IS_DEFINED(PSA_WANT_ALG_ECDSA) && IS_DEFINED(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE); + const int ecdsaAny = IS_DEFINED(PSA_WANT_ALG_ECDSA_ANY) && + IS_DEFINED(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE); + const int rsaGen = IS_DEFINED(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE); const int eddsa = IS_DEFINED(PSA_WANT_ALG_PURE_EDDSA) && IS_DEFINED(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE); const int aes = IS_DEFINED(PSA_WANT_KEY_TYPE_AES); @@ -232,6 +248,8 @@ int main(void) ecdsa && IS_DEFINED(PSA_WANT_ECC_SECP_R1_384), NOT_CHECKED }, { "secp521r1 ECDSA", ecc, 521, ecdsaAlg, ecdsa && IS_DEFINED(PSA_WANT_ECC_SECP_R1_521), NOT_CHECKED }, + { "secp256r1 ECDSA any", ecc, 256, PSA_ALG_ECDSA_ANY, + ecdsaAny && IS_DEFINED(PSA_WANT_ECC_SECP_R1_256), NOT_CHECKED }, { "secp256k1 ECDH", k1, 256, PSA_ALG_ECDH, ecdh && IS_DEFINED(PSA_WANT_ECC_SECP_K1_256), NOT_CHECKED }, { "brainpoolP256r1 ECDH", bp, 256, PSA_ALG_ECDH, @@ -276,8 +294,15 @@ int main(void) NOT_CHECKED }, { "RSA-2048 PKCS#1 v1.5", PSA_KEY_TYPE_RSA_KEY_PAIR, 2048, PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_SHA_256), - IS_DEFINED(PSA_WANT_ALG_RSA_PKCS1V15_SIGN) && - IS_DEFINED(PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE), + rsaGen && IS_DEFINED(PSA_WANT_ALG_RSA_PKCS1V15_SIGN), + NOT_CHECKED }, + { "RSA-2048 PKCS#1 v1.5 raw", PSA_KEY_TYPE_RSA_KEY_PAIR, 2048, + PSA_ALG_RSA_PKCS1V15_SIGN_RAW, + rsaGen && IS_DEFINED(PSA_WANT_ALG_RSA_PKCS1V15_SIGN_RAW), + NOT_CHECKED }, + { "RSA-2048 PSS any salt", PSA_KEY_TYPE_RSA_KEY_PAIR, 2048, + PSA_ALG_RSA_PSS_ANY_SALT(PSA_ALG_SHA_256), + rsaGen && IS_DEFINED(PSA_WANT_ALG_RSA_PSS_ANY_SALT), NOT_CHECKED }, }; size_t i; diff --git a/tools/psa_want_probe.c b/tools/psa_want_probe.c index 65aa6541..c7fdc009 100644 --- a/tools/psa_want_probe.c +++ b/tools/psa_want_probe.c @@ -127,12 +127,16 @@ __WPSA_EMIT__PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC __WPSA_EMIT__PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_IMPORT __WPSA_EMIT__PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_EXPORT __WPSA_EMIT__PSA_WANT_ALG_RSA_PKCS1V15_SIGN +__WPSA_EMIT__PSA_WANT_ALG_RSA_PKCS1V15_SIGN_RAW __WPSA_EMIT__PSA_WANT_ALG_RSA_PKCS1V15_CRYPT #if defined(WOLFSSL_KEY_GEN) __WPSA_EMIT__PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE #endif #if defined(WC_RSA_PSS) __WPSA_EMIT__PSA_WANT_ALG_RSA_PSS +#if defined(WOLFSSL_PSS_SALT_LEN_DISCOVER) +__WPSA_EMIT__PSA_WANT_ALG_RSA_PSS_ANY_SALT +#endif #endif #if defined(WOLFSSL_RSA_OAEP) || defined(WC_RSA_OAEP) __WPSA_EMIT__PSA_WANT_ALG_RSA_OAEP @@ -156,6 +160,7 @@ __WPSA_EMIT__PSA_WANT_ALG_ECDH #if defined(HAVE_ECC) __WPSA_EMIT__PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE __WPSA_EMIT__PSA_WANT_ALG_ECDSA +__WPSA_EMIT__PSA_WANT_ALG_ECDSA_ANY #if defined(WOLFSSL_ECDSA_DETERMINISTIC_K) __WPSA_EMIT__PSA_WANT_ALG_DETERMINISTIC_ECDSA #endif From d289ba94f3ccd0c6fdcdd52c2805de25d517886c Mon Sep 17 00:00:00 2001 From: Paul Adelsbach Date: Thu, 5 Nov 2026 10:42:07 -0800 Subject: [PATCH 6/6] Makefile and test updates to address comments --- Makefile | 5 ++--- test/Makefile | 16 ++++++++++++---- test/psa_server/psa_want_surface_test.c | 9 +++++---- test/wolfcrypt-benchmark/Makefile | 7 ++++++- 4 files changed, 25 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index c0dfa083..4c9c141d 100644 --- a/Makefile +++ b/Makefile @@ -147,12 +147,11 @@ $(PSA_CONFIG): FORCE $(PYTHON) tools/gen-crypto-config.py $@ "$(CC)" \ tools/psa_want_probe.c $(CPPFLAGS) $(CFLAGS) -$(OBJ) $(OBJ_PIC): $(PSA_CONFIG) +$(OBJ) $(OBJ_PIC) $(WOLFCRYPT_OBJ) $(WOLFCRYPT_OBJ_PIC): $(PSA_CONFIG) FORCE: -# Check the PSA_WANT_* surface of this build against its static library -want-surface-test: $(LIBNAME) +want-surface-test: $(LIBNAME) $(SHLIBNAME) $(CC) $(CPPFLAGS) $(CFLAGS) -o $(BUILD_DIR)/psa_want_surface_test \ test/psa_server/psa_want_surface_test.c $(LIBNAME) $(LDFLAGS) \ -lpthread -lm diff --git a/test/Makefile b/test/Makefile index 74a4dd47..717ea292 100644 --- a/test/Makefile +++ b/test/Makefile @@ -2,6 +2,11 @@ WOLFPSA_PATH ?= .. WOLFSSL_PATH ?= $(WOLFPSA_PATH)/../wolfssl WOLFPSA_ABS := $(abspath $(WOLFPSA_PATH)) BUILD_DIR ?= build +WOLFPSA_BUILD_DIR := $(WOLFPSA_ABS)/$(BUILD_DIR) +ifneq ($(filter /%,$(BUILD_DIR)),) +WOLFPSA_BUILD_DIR := $(BUILD_DIR) +endif +PSA_CONFIG := $(WOLFPSA_BUILD_DIR)/include/crypto_config_generated.h WOLFSSL_CANDIDATE_DIRS := \ $(WOLFSSL_PATH)/build \ @@ -56,7 +61,7 @@ ifneq ($(WOLFSSL_BUILD_DIR),) CPPFLAGS += -I$(WOLFSSL_BUILD_DIR) endif CPPFLAGS += -I$(WOLFPSA_PATH) -I$(WOLFPSA_PATH)/wolfpsa -CPPFLAGS += -I$(WOLFPSA_PATH)/$(BUILD_DIR)/include +CPPFLAGS += -I$(WOLFPSA_BUILD_DIR)/include CPPFLAGS += -I$(WOLFPSA_PATH)/src CPPFLAGS += -I$(WOLFPSA_PATH)/test/psa_server @@ -148,8 +153,8 @@ PSA_DES3_STACK_SCRUB_TEST_OBJS = psa_server/psa_des3_stack_scrub_test.o PSA_ECC_BIT_INFERENCE_TEST_OBJS = psa_server/psa_ecc_bit_inference_test.o PSA_ECC_CURVE_ID_TEST_OBJS = psa_server/psa_ecc_curve_id_test.o PSA_RANDOM_SIZE_TEST_OBJS = psa_server/psa_random_size_test.o -PSA_ECC_CURVE_ID_TEST_DEPS = $(WOLFPSA_PATH)/$(BUILD_DIR)/obj/psa_asymmetric.o \ - $(WOLFPSA_PATH)/$(BUILD_DIR)/obj/psa_pq.o +PSA_ECC_CURVE_ID_TEST_DEPS = $(WOLFPSA_BUILD_DIR)/obj/psa_asymmetric.o \ + $(WOLFPSA_BUILD_DIR)/obj/psa_pq.o PSA_RSA_PSS_TEST_OBJS = psa_server/psa_rsa_pss_interop_test.o .PHONY: all clean rebuild-wolfssl-psa require-wolfssl-lib FORCE @@ -198,6 +203,9 @@ $(PSA_REGRESSION_TESTS) $(PSA_TF_PSA_TESTS): %: require-wolfssl-lib \ psa_server/%.o $(CC) $(CFLAGS) -o $@ psa_server/$@.o $(LDFLAGS) $(LDLIBS) $(RPATH_WOLFPSA) $(RPATH_WOLFSSL) +# Its expectations come from the library's PSA_WANT_* macros +psa_server/psa_want_surface_test.o: $(wildcard $(PSA_CONFIG)) + ifdef WOLFSSL_HAS_PSA_TLS psa_tls_server: psa_server/psa_tls_server.o $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LDLIBS) $(RPATH_WOLFPSA) $(RPATH_WOLFSSL) @@ -307,7 +315,7 @@ rebuild-wolfssl-psa: $(WOLFPSA_PATH)/libwolfpsa.so --with-psa-lib-name=wolfpsa \ CFLAGS="-O2 $(DEBUG_FLAGS) $(SANITIZE_FLAGS)" \ CPPFLAGS="-DWOLFSSL_PSA_NO_RNG -DWOLFSSL_PSA_NO_HASH -DWOLFSSL_PSA_NO_AES \ - -I$(WOLFPSA_ABS)/$(BUILD_DIR)/include" \ + -I$(WOLFPSA_BUILD_DIR)/include" \ LDFLAGS="$(SANITIZE_FLAGS) -Wl,-rpath,$(WOLFPSA_ABS) -Wl,-rpath-link,$(WOLFPSA_ABS)" $(MAKE) -C "$(WOLFSSL_PATH)" CFLAGS="-O2 $(DEBUG_FLAGS) $(SANITIZE_FLAGS)" LDFLAGS="$(SANITIZE_FLAGS) -Wl,-rpath,$(WOLFPSA_ABS) -Wl,-rpath-link,$(WOLFPSA_ABS)" src/libwolfssl.la diff --git a/test/psa_server/psa_want_surface_test.c b/test/psa_server/psa_want_surface_test.c index 5e0a362e..6cd1cf0d 100644 --- a/test/psa_server/psa_want_surface_test.c +++ b/test/psa_server/psa_want_surface_test.c @@ -224,9 +224,10 @@ int main(void) const psa_key_type_t ed = PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_TWISTED_EDWARDS); const psa_algorithm_t ecdsaAlg = PSA_ALG_ECDSA(PSA_ALG_SHA_256); + const int sha256 = IS_DEFINED(PSA_WANT_ALG_SHA_256); const int ecdh = IS_DEFINED(PSA_WANT_ALG_ECDH) && IS_DEFINED(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE); - const int ecdsa = IS_DEFINED(PSA_WANT_ALG_ECDSA) && + const int ecdsa = sha256 && IS_DEFINED(PSA_WANT_ALG_ECDSA) && IS_DEFINED(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE); const int ecdsaAny = IS_DEFINED(PSA_WANT_ALG_ECDSA_ANY) && IS_DEFINED(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE); @@ -284,7 +285,7 @@ int main(void) IS_DEFINED(MBEDTLS_CHACHAPOLY_C) }, { "HMAC-SHA-256", PSA_KEY_TYPE_HMAC, 256, PSA_ALG_HMAC(PSA_ALG_SHA_256), - IS_DEFINED(PSA_WANT_KEY_TYPE_HMAC) && + sha256 && IS_DEFINED(PSA_WANT_KEY_TYPE_HMAC) && IS_DEFINED(PSA_WANT_ALG_HMAC), NOT_CHECKED }, { "ML-KEM-1024 export", PSA_KEY_TYPE_ML_KEM_KEY_PAIR, 1024, PSA_ALG_ML_KEM, FAMILY_WANT(IS_DEFINED(PSA_WANT_KEY_TYPE_ML_KEM)), @@ -294,7 +295,7 @@ int main(void) NOT_CHECKED }, { "RSA-2048 PKCS#1 v1.5", PSA_KEY_TYPE_RSA_KEY_PAIR, 2048, PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_SHA_256), - rsaGen && IS_DEFINED(PSA_WANT_ALG_RSA_PKCS1V15_SIGN), + sha256 && rsaGen && IS_DEFINED(PSA_WANT_ALG_RSA_PKCS1V15_SIGN), NOT_CHECKED }, { "RSA-2048 PKCS#1 v1.5 raw", PSA_KEY_TYPE_RSA_KEY_PAIR, 2048, PSA_ALG_RSA_PKCS1V15_SIGN_RAW, @@ -302,7 +303,7 @@ int main(void) NOT_CHECKED }, { "RSA-2048 PSS any salt", PSA_KEY_TYPE_RSA_KEY_PAIR, 2048, PSA_ALG_RSA_PSS_ANY_SALT(PSA_ALG_SHA_256), - rsaGen && IS_DEFINED(PSA_WANT_ALG_RSA_PSS_ANY_SALT), + sha256 && rsaGen && IS_DEFINED(PSA_WANT_ALG_RSA_PSS_ANY_SALT), NOT_CHECKED }, }; size_t i; diff --git a/test/wolfcrypt-benchmark/Makefile b/test/wolfcrypt-benchmark/Makefile index e8402b7b..f15337cf 100644 --- a/test/wolfcrypt-benchmark/Makefile +++ b/test/wolfcrypt-benchmark/Makefile @@ -2,6 +2,11 @@ WOLFPSA_PATH ?= ../.. WOLFSSL_PATH ?= $(WOLFPSA_PATH)/../wolfssl +BUILD_DIR ?= build +WOLFPSA_BUILD_DIR := $(WOLFPSA_PATH)/$(BUILD_DIR) +ifneq ($(filter /%,$(BUILD_DIR)),) +WOLFPSA_BUILD_DIR := $(BUILD_DIR) +endif # libwolfpsa.so location and link flags. WOLFPSA_LIBDIR ?= $(WOLFPSA_PATH) @@ -13,7 +18,7 @@ WOLFPSA_DEVID ?= 0x505341 CFLAGS ?= -O2 CPPFLAGS += -I$(WOLFSSL_PATH) -I$(WOLFSSL_PATH)/wolfssl -CPPFLAGS += -I$(WOLFPSA_PATH)/wolfpsa -I$(WOLFPSA_PATH)/build/include +CPPFLAGS += -I$(WOLFPSA_PATH)/wolfpsa -I$(WOLFPSA_BUILD_DIR)/include CPPFLAGS += -DWOLFSSL_USER_SETTINGS -U HAVE_CONFIG_H CPPFLAGS += -DWOLFSSL_HAVE_PSA CPPFLAGS += -DWOLFPSA_DEVID=$(WOLFPSA_DEVID)