diff --git a/.github/scripts/zephyr-4.x/builds.txt b/.github/scripts/zephyr-4.x/builds.txt index b1316f7b98c..b532ed6f004 100644 --- a/.github/scripts/zephyr-4.x/builds.txt +++ b/.github/scripts/zephyr-4.x/builds.txt @@ -11,6 +11,10 @@ native_sim samples/wolfssl_benchmark external_libc.conf native_sim samples/wolfssl_test prj-cert.conf native_sim samples/wolfssl_test prj-x25519-ed448.conf native_sim samples/wolfssl_test prj-ed25519-x448.conf +native_sim samples/wolfssl_test sp_stack.conf +native_sim samples/wolfssl_test rsa_2048.conf +native_sim samples/wolfssl_test rsa_3072.conf +native_sim samples/wolfssl_test rsa_3072_ecc_custom.conf # external_libc overlay is native_sim-only in the original Jenkins matrix frdm_rw612/rw612 samples/wolfssl_tls_sock frdm_rw612/rw612 samples/wolfssl_test diff --git a/.github/scripts/zephyr-4.x/rsa_2048.conf b/.github/scripts/zephyr-4.x/rsa_2048.conf new file mode 100644 index 00000000000..9e5150a5728 --- /dev/null +++ b/.github/scripts/zephyr-4.x/rsa_2048.conf @@ -0,0 +1,2 @@ +# Largest RSA key 2048 bits +CONFIG_WOLFSSL_RSA_MAX_BITS_2048=y diff --git a/.github/scripts/zephyr-4.x/rsa_3072.conf b/.github/scripts/zephyr-4.x/rsa_3072.conf new file mode 100644 index 00000000000..8ad989e26eb --- /dev/null +++ b/.github/scripts/zephyr-4.x/rsa_3072.conf @@ -0,0 +1,2 @@ +# Largest RSA key 3072 bits +CONFIG_WOLFSSL_RSA_MAX_BITS_3072=y diff --git a/.github/scripts/zephyr-4.x/rsa_3072_ecc_custom.conf b/.github/scripts/zephyr-4.x/rsa_3072_ecc_custom.conf new file mode 100644 index 00000000000..4fe0eab1cac --- /dev/null +++ b/.github/scripts/zephyr-4.x/rsa_3072_ecc_custom.conf @@ -0,0 +1,9 @@ +# Custom curves (prj-ecc-custom.conf) with the largest RSA key 3072 bits +CONFIG_WOLFSSL_ECC=y +CONFIG_WOLFSSL_ECC_256=y +CONFIG_WOLFSSL_ECC_384=y +CONFIG_WOLFSSL_ECC_512=y +CONFIG_WOLFSSL_ECC_BRAINPOOL=y +CONFIG_MAIN_STACK_SIZE=65536 +CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=65536 +CONFIG_WOLFSSL_RSA_MAX_BITS_3072=y diff --git a/.github/scripts/zephyr-4.x/sp_stack.conf b/.github/scripts/zephyr-4.x/sp_stack.conf new file mode 100644 index 00000000000..e69c9e87ce5 --- /dev/null +++ b/.github/scripts/zephyr-4.x/sp_stack.conf @@ -0,0 +1,2 @@ +# SP math temporaries on the thread stack +CONFIG_WOLFCRYPT_SP_SMALL_STACK=n diff --git a/.github/scripts/zephyr-4.x/zephyr-test.sh b/.github/scripts/zephyr-4.x/zephyr-test.sh index 1e894238109..968aae069ce 100755 --- a/.github/scripts/zephyr-4.x/zephyr-test.sh +++ b/.github/scripts/zephyr-4.x/zephyr-test.sh @@ -25,7 +25,7 @@ # -h, --help Show this help # # Examples: -# # Test master against Zephyr 4.1.0 for native_sim +# # Test master against Zephyr 4.3.0 for native_sim # ./zephyr-test.sh # # # Test a specific branch for frdm_rw612 on Zephyr 4.3.0 @@ -54,7 +54,7 @@ set -euo pipefail # Defaults WOLFSSL_REPO="https://github.com/wolfSSL/wolfssl" WOLFSSL_BRANCH="master" -ZEPHYR_VERSION="v4.1.0" +ZEPHYR_VERSION="v4.3.0" BOARD_TARGET="native_sim" SAMPLE_NAME="wolfssl_tls_sock" SUBDIR="samples" diff --git a/.github/workflows/zephyr-4.x.yml b/.github/workflows/zephyr-4.x.yml index c5f0f9bc62c..8b1b0db54db 100644 --- a/.github/workflows/zephyr-4.x.yml +++ b/.github/workflows/zephyr-4.x.yml @@ -30,7 +30,7 @@ jobs: strategy: fail-fast: false matrix: - zephyr-ref: [ v4.1.0, v4.3.0, v4.4.0 ] + zephyr-ref: [ v4.3.0, v4.4.0, v4.5.0 ] steps: - name: Checkout test driver uses: actions/checkout@v5 diff --git a/.github/workflows/zephyr.yml b/.github/workflows/zephyr.yml index 770b811309a..1de6fe5f3a2 100644 --- a/.github/workflows/zephyr.yml +++ b/.github/workflows/zephyr.yml @@ -23,10 +23,8 @@ jobs: fail-fast: false matrix: config: - - zephyr-ref: v3.4.0 - zephyr-sdk: 0.16.1 - - zephyr-ref: v3.5.0 - zephyr-sdk: 0.16.3 + - zephyr-ref: v3.7.2 + zephyr-sdk: 0.16.8 - zephyr-ref: v2.7.4 zephyr-sdk: 0.16.3 if: ${{ (github.repository_owner == 'wolfssl') && (github.event_name != 'pull_request' || github.event.pull_request.draft == false) }} @@ -92,17 +90,8 @@ jobs: - name: Run wolfssl test id: wolfssl-test working-directory: zephyr - # Scope -T to the sample directory (not the whole module) so twister does - # not load zephyr/tests/*/testcase.yaml. The condvar test's modern - # list-form platform_allow is rejected by the 2.7.4 twister schema, and - # this is the only sample step that runs on 2.7.4. - # - # Name the two scenarios rather than running the whole sample: the rest - # need a Zephyr these versions predate - hierarchical board names, - # COMMON_LIBC_MALLOC_ARENA_SIZE, and toolchains beyond the x86_64 one - # installed above. --test drops the others before their platform_allow - # is resolved, so an unrecognized board does not abort the run - but - # the yaml is still parsed, so a modern-only key would. + # 2.7.4's twister rejects the zephyr/tests yaml, so -T stays on the + # sample; the other scenarios need boards or toolchains not set up here. run: | ./zephyr/scripts/twister -T modules/crypto/wolfssl/zephyr/samples/wolfssl_test \ --test sample.crypto.wolfssl_test \ diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 36f3f3f5ede..44d35938f0a 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -191,6 +191,7 @@ CONFIG_WOLFCRYPT_FIPS_V5 CONFIG_WOLFCRYPT_FIPS_V6 CONFIG_WOLFCRYPT_FIPS_V7 CONFIG_WOLFCRYPT_SP_SMALL +CONFIG_WOLFCRYPT_SP_SMALL_STACK CONFIG_WOLFSSL CONFIG_WOLFSSL_AES_BITSLICED CONFIG_WOLFSSL_AES_TOUCH_LINES @@ -255,6 +256,9 @@ CONFIG_WOLFSSL_POST_HANDSHAKE_AUTH CONFIG_WOLFSSL_PSK CONFIG_WOLFSSL_PUBLIC_ASN CONFIG_WOLFSSL_RSA +CONFIG_WOLFSSL_RSA_MAX_BITS_2048 +CONFIG_WOLFSSL_RSA_MAX_BITS_3072 +CONFIG_WOLFSSL_RSA_MAX_BITS_4096 CONFIG_WOLFSSL_RSA_PSS CONFIG_WOLFSSL_SESSION_CACHE CONFIG_WOLFSSL_SESSION_EXPORT diff --git a/src/ssl_api_rw.c b/src/ssl_api_rw.c index 8d9349f4724..99eede15a64 100644 --- a/src/ssl_api_rw.c +++ b/src/ssl_api_rw.c @@ -1284,6 +1284,13 @@ int wolfSSL_has_pending(const WOLFSSL* ssl) else if (ssl->buffers.inputBuffer.length > ssl->buffers.inputBuffer.idx) { ret = 1; } + #elif defined(WOLFSSL_DTLS) + /* A DTLS read takes a whole datagram, which can hold more records. They + * may carry no application data, so wolfSSL_read() can still WANT_READ. */ + else if (ssl->options.dtls && + ssl->buffers.inputBuffer.length > ssl->buffers.inputBuffer.idx) { + ret = 1; + } #endif return ret; diff --git a/tests/api/test_ssl_rw.c b/tests/api/test_ssl_rw.c index 4c992da4f74..b5bdf3ab63c 100644 --- a/tests/api/test_ssl_rw.c +++ b/tests/api/test_ssl_rw.c @@ -408,6 +408,88 @@ int test_wolfSSL_pending_api(void) return EXPECT_RESULT(); } +/* Test wolfSSL_has_pending() with two DTLS records in one datagram. + * + * A DTLS read takes the whole datagram, so the second record is still + * buffered, though not decrypted, after the first one is read. + * + * @return TEST_SUCCESS on success. + */ +int test_wolfSSL_has_pending_dtls_datagram(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) && \ + (!defined(WOLFSSL_NO_TLS12) || defined(WOLFSSL_DTLS13)) + WOLFSSL_CTX* ctx_c = NULL; + WOLFSSL_CTX* ctx_s = NULL; + WOLFSSL* ssl_c = NULL; + WOLFSSL* ssl_s = NULL; + struct test_memio_ctx test_ctx; + byte reply[1]; + size_t i; + struct { + method_provider client_meth; + method_provider server_meth; + const char* cipher; + } params[] = { +#ifndef WOLFSSL_NO_TLS12 + { wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method, NULL }, +#if !defined(WOLFSSL_AEAD_ONLY) && !defined(NO_RSA) && !defined(NO_AES) && \ + defined(HAVE_AES_CBC) && !defined(NO_SHA256) && defined(HAVE_ECC) + { wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method, + "ECDHE-RSA-AES128-SHA256" }, +#endif +#endif +#ifdef WOLFSSL_DTLS13 + { wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method, NULL }, +#endif + }; + + for (i = 0; i < XELEM_CNT(params) && !EXPECT_FAIL(); i++) { + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, + &ssl_s, params[i].client_meth, params[i].server_meth), 0); + if (params[i].cipher != NULL) { + ExpectIntEQ(wolfSSL_set_cipher_list(ssl_c, params[i].cipher), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_cipher_list(ssl_s, params[i].cipher), + WOLFSSL_SUCCESS); + } + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + test_memio_clear_buffer(&test_ctx, 1); + + ExpectIntEQ(wolfSSL_write(ssl_s, "A", 1), 1); + ExpectIntEQ(wolfSSL_write(ssl_s, "B", 1), 1); + + /* Deliver both records in one datagram */ + ExpectIntEQ(test_ctx.c_msg_count, 2); + if (EXPECT_SUCCESS()) { + test_ctx.c_msg_sizes[0] += test_ctx.c_msg_sizes[1]; + test_ctx.c_msg_count = 1; + } + + ExpectIntEQ(wolfSSL_read(ssl_c, reply, sizeof(reply)), 1); + ExpectIntEQ(reply[0], 'A'); + ExpectIntEQ(wolfSSL_pending(ssl_c), 0); + ExpectIntEQ(wolfSSL_has_pending(ssl_c), 1); + + ExpectIntEQ(wolfSSL_read(ssl_c, reply, sizeof(reply)), 1); + ExpectIntEQ(reply[0], 'B'); + ExpectIntEQ(wolfSSL_has_pending(ssl_c), 0); + + wolfSSL_free(ssl_c); + ssl_c = NULL; + wolfSSL_free(ssl_s); + ssl_s = NULL; + wolfSSL_CTX_free(ctx_c); + ctx_c = NULL; + wolfSSL_CTX_free(ctx_s); + ctx_s = NULL; + } +#endif + return EXPECT_RESULT(); +} + /* Test parameter validation across the read/write APIs. * * Every entry point in ssl_api_rw.c rejects a NULL object, a NULL buffer or a diff --git a/tests/api/test_ssl_rw.h b/tests/api/test_ssl_rw.h index 822863c4515..f3b771d2873 100644 --- a/tests/api/test_ssl_rw.h +++ b/tests/api/test_ssl_rw.h @@ -29,6 +29,7 @@ int test_wolfSSL_writev(void); int test_wolfSSL_get_shutdown(void); int test_wolfSSL_want(void); int test_wolfSSL_pending_api(void); +int test_wolfSSL_has_pending_dtls_datagram(void); int test_wolfSSL_rw_bad_args(void); int test_wolfSSL_rw_info_callback(void); int test_wolfSSL_write_ex_partial(void); @@ -58,6 +59,7 @@ int test_wolfSSL_write_dup_max_fragment(void); TEST_DECL_GROUP("ssl_rw", test_wolfSSL_get_shutdown), \ TEST_DECL_GROUP("ssl_rw", test_wolfSSL_want), \ TEST_DECL_GROUP("ssl_rw", test_wolfSSL_pending_api), \ + TEST_DECL_GROUP("ssl_rw", test_wolfSSL_has_pending_dtls_datagram), \ TEST_DECL_GROUP("ssl_rw", test_wolfSSL_rw_bad_args), \ TEST_DECL_GROUP("ssl_rw", test_wolfSSL_rw_info_callback), \ TEST_DECL_GROUP("ssl_rw", test_wolfSSL_write_ex_partial), \ diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index 6564f4aa52a..3a015ccb450 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -3176,6 +3176,14 @@ #include #include #include + #if defined(WOLFSSL_HAVE_MIN) || defined(WOLFSSL_HAVE_MAX) + /* Zephyr 4.5 moved the lowercase min() and max() out of util.h */ + #ifdef __has_include + #if __has_include() + #include + #endif + #endif + #endif #else #include #include diff --git a/zephyr/Kconfig b/zephyr/Kconfig index 18e24f6cd5c..3bf763f8a05 100644 --- a/zephyr/Kconfig +++ b/zephyr/Kconfig @@ -259,6 +259,30 @@ config WOLFSSL_RSA help Enable RSA (define RSA support; NO_RSA when off). +choice WOLFSSL_RSA_MAX_BITS + prompt "Largest RSA key size" + depends on WOLFSSL_RSA && !WOLFCRYPT_FIPS + default WOLFSSL_RSA_MAX_BITS_4096 + help + Largest RSA modulus wolfCrypt can sign, verify or decrypt with, so + also the largest RSA key a certificate chain may carry. The big + integers of the RSA and DH math are sized for this length, so a + smaller choice saves stack and heap in each handshake. The + single-precision math handles 2048, 3072 and 4096-bit keys up to the + chosen size; other sizes need WOLFSSL_SP_MATH_ALL. + A FIPS build takes its math sizes from the module settings instead. + +config WOLFSSL_RSA_MAX_BITS_2048 + bool "2048 bits" + +config WOLFSSL_RSA_MAX_BITS_3072 + bool "3072 bits" + +config WOLFSSL_RSA_MAX_BITS_4096 + bool "4096 bits" + +endchoice + config WOLFSSL_ECC bool "wolfCrypt ECC support" depends on !WOLFSSL_HAS_SETTINGS_FILE @@ -719,6 +743,18 @@ config WOLFCRYPT_SP_SMALL turning it off is what makes WOLFCRYPT_ASM pay off on a part with the flash to spare. +config WOLFCRYPT_SP_SMALL_STACK + bool "Single-precision math temporaries on the heap" + depends on WOLFSSL_BUILTIN && !WOLFSSL_HAS_SETTINGS_FILE && !WOLFCRYPT_FIPS + default y + help + Allocate the temporaries of the fixed-size single-precision RSA, DH + and ECC routines (sp_c32.c, sp_c64.c and the assembly sources) on + the heap (WOLFSSL_SP_SMALL_STACK) instead of the stack of the calling + thread. An RSA-3072 operation otherwise needs over 4 KB of stack. The + generic sp_int.c math and the rest of wolfSSL keep their stack use + unless WOLFSSL_SMALL_STACK is set in a settings file. + config WOLFSSL_NO_HAVE_MIN_MAX bool "Force wolfSSL to use its own min/max" help diff --git a/zephyr/samples/wolfssl_benchmark/sample.yaml b/zephyr/samples/wolfssl_benchmark/sample.yaml index 525dfb2069a..bd5be5d1f24 100644 --- a/zephyr/samples/wolfssl_benchmark/sample.yaml +++ b/zephyr/samples/wolfssl_benchmark/sample.yaml @@ -2,7 +2,11 @@ sample: description: wolfCrypt benchmark sample app name: wolfCrypt benchmark common: - tags: crypto wolfssl userspace random + tags: + - crypto + - wolfssl + - userspace + - random harness: console harness_config: type: one_line diff --git a/zephyr/samples/wolfssl_test/sample.yaml b/zephyr/samples/wolfssl_test/sample.yaml index 3698d56b184..e0261065079 100644 --- a/zephyr/samples/wolfssl_test/sample.yaml +++ b/zephyr/samples/wolfssl_test/sample.yaml @@ -33,6 +33,43 @@ tests: extra_args: CONF_FILE="prj.conf;prj-ecc-custom.conf" integration_platforms: - qemu_x86 + sample.crypto.wolfssl_test_rsa_2048: + timeout: 120 + platform_allow: qemu_x86 + extra_configs: + - CONFIG_WOLFSSL_RSA_MAX_BITS_2048=y + integration_platforms: + - qemu_x86 + sample.crypto.wolfssl_test_rsa_2048_ecc_custom: + timeout: 600 + platform_allow: qemu_x86 + extra_args: CONF_FILE="prj.conf;prj-ecc-custom.conf" + extra_configs: + - CONFIG_WOLFSSL_RSA_MAX_BITS_2048=y + integration_platforms: + - qemu_x86 + sample.crypto.wolfssl_test_rsa_3072: + timeout: 120 + platform_allow: qemu_x86 + extra_configs: + - CONFIG_WOLFSSL_RSA_MAX_BITS_3072=y + integration_platforms: + - qemu_x86 + sample.crypto.wolfssl_test_rsa_3072_ecc_custom: + timeout: 600 + platform_allow: qemu_x86 + extra_args: CONF_FILE="prj.conf;prj-ecc-custom.conf" + extra_configs: + - CONFIG_WOLFSSL_RSA_MAX_BITS_3072=y + integration_platforms: + - qemu_x86 + sample.crypto.wolfssl_test_sp_stack: + timeout: 120 + platform_allow: qemu_x86 + extra_configs: + - CONFIG_WOLFCRYPT_SP_SMALL_STACK=n + integration_platforms: + - qemu_x86 sample.crypto.wolfssl_test_ghash_table_4bit: timeout: 120 platform_allow: qemu_x86 diff --git a/zephyr/samples/wolfssl_tls_sock/CMakeLists.txt b/zephyr/samples/wolfssl_tls_sock/CMakeLists.txt index bdd894eda79..183170ed1ab 100644 --- a/zephyr/samples/wolfssl_tls_sock/CMakeLists.txt +++ b/zephyr/samples/wolfssl_tls_sock/CMakeLists.txt @@ -19,7 +19,7 @@ else() ${CMAKE_CURRENT_SOURCE_DIR}/zephyr_legacy.conf) endif() -include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(wolfssl_tls_sock) FILE(GLOB app_sources src/*.c) diff --git a/zephyr/user_settings.h b/zephyr/user_settings.h index 3c58119e2e1..bac85b9c2dc 100644 --- a/zephyr/user_settings.h +++ b/zephyr/user_settings.h @@ -696,12 +696,27 @@ extern "C" { #if defined(HAVE_ECC521) #define WOLFSSL_SP_521 #endif + /* Sizes ECC keys and points for the largest curve */ + #if (!defined(NO_RSA) || !defined(NO_DH)) && !defined(WOLFSSL_NO_MALLOC) && \ + !defined(HAVE_FIPS) + #define ALT_ECC_SIZE + #endif #endif #ifndef NO_RSA #define WOLFSSL_HAVE_SP_RSA //#define WOLFSSL_SP_NO_2048 - //#define WOLFSSL_SP_NO_3072 - //#define WOLFSSL_SP_4096 + #if defined(CONFIG_WOLFSSL_RSA_MAX_BITS_2048) + #define WOLFSSL_SP_NO_3072 + #ifdef WOLFSSL_SP_MATH_ALL + #define SP_INT_BITS 2048 + #endif + #elif defined(CONFIG_WOLFSSL_RSA_MAX_BITS_3072) + #ifdef WOLFSSL_SP_MATH_ALL + #define SP_INT_BITS 3072 + #endif + #elif defined(CONFIG_WOLFSSL_RSA_MAX_BITS_4096) + #define WOLFSSL_SP_4096 + #endif #endif #ifndef NO_DH #define WOLFSSL_HAVE_SP_DH @@ -712,6 +727,10 @@ extern "C" { #endif //#define WOLFSSL_SP_NO_MALLOC /* disable heap in wolf/SP math */ //#define SP_DIV_WORD_USE_DIV /* no div64 */ + #if defined(CONFIG_WOLFCRYPT_SP_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) && \ + !defined(WOLFSSL_SP_NO_MALLOC) + #define WOLFSSL_SP_SMALL_STACK + #endif /* Assembly speedup, keyed on the CPU Zephyr reports. Anything not named * here keeps the C backend. Each pair is two separate backends: the _ASM @@ -801,6 +820,11 @@ extern "C" { #endif /* WOLFSSL_SETTINGS_FILE */ +/* pulls in SoC headers that define RNG, such as STM32's */ +#ifndef NO_OLD_RNGNAME +#define NO_OLD_RNGNAME +#endif + /* The port is silent when its define is missing: els_pkc_port.c compiles to * nothing and no crypto callback is ever registered. */ #if defined(CONFIG_WOLFSSL_ELS_PKC) && \