diff --git a/.github/workflows/arduino.yml b/.github/workflows/arduino.yml index 7bab71c119..f2316f57fc 100644 --- a/.github/workflows/arduino.yml +++ b/.github/workflows/arduino.yml @@ -52,6 +52,7 @@ on: paths: # Specific to this Arduino CI Build (1 of 4) - '.github/workflows/arduino.yml' + - 'examples/configs/user_settings_arduino.h' - 'IDE/ARDUINO/**' - 'src/**' - 'wolfcrypt/**' @@ -61,6 +62,7 @@ on: branches: [ '**' ] paths: - '.github/workflows/arduino.yml' + - 'examples/configs/user_settings_arduino.h' - 'IDE/ARDUINO/**' - 'src/**' - 'wolfcrypt/**' diff --git a/.github/workflows/cryptocb-only.yml b/.github/workflows/cryptocb-only.yml index 63400f2f9a..5aedf4c873 100644 --- a/.github/workflows/cryptocb-only.yml +++ b/.github/workflows/cryptocb-only.yml @@ -33,6 +33,19 @@ jobs: # the software path via cryptocb. - name: SHA256 cppflags: -DWOLF_CRYPTO_CB_ONLY_SHA256 + # WOLF_CRYPTO_CB_ONLY_SHA512: strips software SHA-512 family (SHA-384, + # SHA-512/224, SHA-512/256, SHA-512); swdev handles every variant + # explicitly via cryptocb. + - name: SHA512 + cppflags: -DWOLF_CRYPTO_CB_ONLY_SHA512 + # Same as SHA512 but tells swdev to refuse the SHA-384 / SHA-512/224 / + # SHA-512/256 variant callbacks (WOLFSSL_SWDEV_SHA512_GENERAL_ONLY). That + # forces the cryptocb dispatcher's fallback-to-plain-SHA-512-with- + # truncation path. The SHA512 entry above instead has swdev handle + # every variant end-to-end, so the dispatcher fallback is otherwise + # uncovered. + - name: SHA512_via_general + cppflags: -DWOLF_CRYPTO_CB_ONLY_SHA512 -DWOLFSSL_SWDEV_SHA512_GENERAL_ONLY # WOLF_CRYPTO_CB_ONLY_AES: strips software AES; swdev provides the # software path via cryptocb. - name: AES @@ -51,7 +64,8 @@ jobs: - name: ALL cppflags: >- -DWOLF_CRYPTO_CB_ONLY_ECC -DWOLF_CRYPTO_CB_ONLY_RSA - -DWOLF_CRYPTO_CB_ONLY_SHA256 -DWOLF_CRYPTO_CB_ONLY_AES + -DWOLF_CRYPTO_CB_ONLY_SHA256 -DWOLF_CRYPTO_CB_ONLY_SHA512 + -DWOLF_CRYPTO_CB_ONLY_AES name: make check (${{ matrix.name }}) if: ${{ (github.repository_owner == 'wolfssl') && (github.event_name != 'pull_request' || github.event.pull_request.draft == false) }} runs-on: ubuntu-24.04 diff --git a/.github/workflows/membrowse-report.yml b/.github/workflows/membrowse-report.yml index 201fbed2e8..805ae01eae 100644 --- a/.github/workflows/membrowse-report.yml +++ b/.github/workflows/membrowse-report.yml @@ -8,8 +8,8 @@ on: workflow_dispatch: concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + group: ${{ github.workflow }}-${{ github.event_name == 'push' && github.sha || github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: load-targets: diff --git a/.github/workflows/ocsp.yml b/.github/workflows/ocsp.yml index c545592fa5..6ce5a2cb68 100644 --- a/.github/workflows/ocsp.yml +++ b/.github/workflows/ocsp.yml @@ -27,7 +27,7 @@ jobs: run: autoreconf -ivf && ./configure --enable-ocsp --enable-ocspstapling && make - name: Start OCSP responder 1 - run: openssl ocsp -port 22221 -ndays 1000 -index certs/ocsp/index-intermediate1-ca-issued-certs.txt -rsigner certs/ocsp/ocsp-responder-cert.pem -rkey certs/ocsp/ocsp-responder-key.pem -CA certs/ocsp/intermediate1-ca-cert.pem & + run: openssl ocsp -port 22221 -ndays 1000 -index certs/ocsp/index-intermediate1-ca-issued-certs.txt -rsigner certs/ocsp/ocsp-responder-int1-cert.pem -rkey certs/ocsp/ocsp-responder-int1-key.pem -CA certs/ocsp/intermediate1-ca-cert.pem & - name: Start OCSP responder 2 run: openssl ocsp -port 22220 -ndays 1000 -index certs/ocsp/index-ca-and-intermediate-cas.txt -rsigner certs/ocsp/ocsp-responder-cert.pem -rkey certs/ocsp/ocsp-responder-key.pem -CA certs/ocsp/root-ca-cert.pem & diff --git a/.github/workflows/stm32-sim.yml b/.github/workflows/stm32-sim.yml index 9a2bcb6a83..66c5f608b4 100644 --- a/.github/workflows/stm32-sim.yml +++ b/.github/workflows/stm32-sim.yml @@ -15,12 +15,20 @@ concurrency: # Build the STM32 software simulator (https://github.com/wolfSSL/simulators, # STM32Sim/ subdirectory) and run the wolfCrypt test suite on emulated -# STM32H753 (Cortex-M7) and STM32U585 (Cortex-M33) hardware. Replaces the -# previous Renode-based STM32H753 workflow and adds U5/PKA coverage. +# STM32H753 (Cortex-M7), STM32U585 (Cortex-M33), and STM32MP135 (Cortex-A7) +# hardware. Replaces the previous Renode-based STM32H753 workflow and adds +# U5/PKA + MP135 (SHA3/SHAKE on HASH1) coverage. # # Dockerfile.wolfcrypt reads wolfSSL from /opt/wolfssl at runtime via a # bind mount, so unlike se050-sim.yml / stsafe-a120-sim.yml no Dockerfile # patching is required - we just mount the PR checkout. +# +# The simulators repo is pinned via SIMULATORS_REF so the MP135 SHAKE- +# enabling sed patch below has a known anchor in user_settings.h. Bump +# the pin when simulators changes are needed. + +env: + SIMULATORS_REF: 840da2f4a28a9e3027c127da38d758ded902d926 jobs: stm32_sim: @@ -36,6 +44,8 @@ jobs: script: run-wolfcrypt-h7.sh - chip_label: U585 script: run-wolfcrypt-u5.sh + - chip_label: MP135 + script: run-wolfcrypt-mp135.sh steps: - name: Checkout wolfSSL (PR source) uses: actions/checkout@v4 @@ -43,7 +53,24 @@ jobs: path: wolfssl - name: Clone STM32 simulator - run: git clone --depth 1 https://github.com/wolfSSL/simulators simulators + run: | + git clone https://github.com/wolfSSL/simulators simulators + cd simulators && git checkout "$SIMULATORS_REF" + + # The MP135 firmware in the simulators repo currently disables SHAKE + # in user_settings.h with a comment pointing at the wolfSSL build + # break that this PR resolves. Once the simulators repo refreshes + # that file, this patch step becomes a no-op (the grep below will + # still pass) - drop it then. + - name: Enable SHAKE in MP135 firmware user_settings.h + if: matrix.chip_label == 'MP135' + working-directory: simulators/STM32Sim/firmware/wolfcrypt-test-mp135 + run: | + sed -i 's|^#define WOLFSSL_SHA3$|#define WOLFSSL_SHA3\n#define WOLFSSL_SHAKE128\n#define WOLFSSL_SHAKE256|' user_settings.h + # Fail fast if the anchor line drifted - better than silently + # building with SHAKE off and "passing" without exercising it. + grep -q '^#define WOLFSSL_SHAKE128$' user_settings.h + grep -q '^#define WOLFSSL_SHAKE256$' user_settings.h - uses: docker/setup-buildx-action@v3 diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index fe9146dca7..c23fd8949e 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -183,6 +183,7 @@ CONFIG_WOLFSSL_KEEP_PEER_CERT CONFIG_WOLFSSL_MAX_FRAGMENT_LEN CONFIG_WOLFSSL_MLKEM CONFIG_WOLFSSL_NO_ASN_STRICT +CONFIG_WOLFSSL_OPENSSL_EXTRA_X509_SMALL CONFIG_WOLFSSL_PSK CONFIG_WOLFSSL_RSA_PSS CONFIG_WOLFSSL_SESSION_EXPORT @@ -661,6 +662,7 @@ WC_HASH_CUSTOM_MAX_BLOCK_SIZE WC_HASH_CUSTOM_MAX_DIGEST_SIZE WC_HASH_CUSTOM_MIN_DIGEST_SIZE WC_LINUXKM_NO_USE_HEAP_WRAPPERS +WC_INIT_ERROR_WHEN_CONTENDED WC_MLKEM_KERNEL_ASM WC_NO_ASYNC_SLEEP WC_NO_RNG_SIMPLE @@ -844,7 +846,6 @@ WOLFSSL_NO_KCAPI_SHA224 WOLFSSL_NO_KTRI_ORACLE_WARNING WOLFSSL_NO_LMS_SHAKE256_256 WOLFSSL_NO_OCSP_DATE_CHECK -WOLFSSL_NO_OCSP_ISSUER_CHAIN_CHECK WOLFSSL_NO_OCSP_OPTIONAL_CERTS WOLFSSL_NO_RSA_KEY_CHECK WOLFSSL_NO_SERVER_GROUPS_EXT @@ -968,6 +969,8 @@ WOLFSSL_XIL_MSG_NO_SLEEP WOLFSSL_ZEPHYR WOLF_ALLOW_BUILTIN WOLF_CRYPTO_CB_CMD +WOLF_CRYPTO_CB_NO_SHA512_FALLBACK +WOLF_CRYPTO_CB_ONLY_SHA512 WOLF_CRYPTO_DEV WOLF_NO_TRAILING_ENUM_COMMAS WindowsCE @@ -979,6 +982,7 @@ _ABI64 _ABIO64 _ARCH_PPC64 _ARCH_PWR8 +_CALL_ELF _COMPILER_VERSION _INTPTR_T_DECLARED _LINUX_REFCOUNT_H diff --git a/CMakeLists.txt b/CMakeLists.txt index 217a9e1574..31b77bae8c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2945,6 +2945,9 @@ if(WOLFSSL_EXAMPLES) tests/api/test_lms_xmss.c tests/api/test_dtls.c tests/api/test_dtls13.c + tests/api/test_ssl_cert.c + tests/api/test_ssl_pk.c + tests/api/test_ssl_ext.c tests/api/test_ocsp.c tests/api/test_evp.c tests/api/test_tls_ext.c diff --git a/ChangeLog.md b/ChangeLog.md index ef01745e95..860eede35a 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -2,6 +2,17 @@ ## Enhancements +* **Behavioral change (RSA-PSS trailerField enforcement)**: `DecodeRsaPssParams` + (and its public wrapper `wc_DecodeRsaPssParams`) now enforces RFC 8017 A.2.3, + which mandates `trailerField == trailerFieldBC(1)`. In the default build + (i.e., without `WOLFSSL_NO_ASN_STRICT`), any certificate or CMS/PKCS#7 + structure whose RSA-PSS parameters contain a `trailerField` value other than 1 + is now rejected with `ASN_PARSE_E`. Previously, any positive integer value was + silently accepted. This affects all call paths that decode RSA-PSS algorithm + parameters, including X.509 certificate parsing and PKCS#7 signature + verification. Users who need to interoperate with non-conformant peers can + define `WOLFSSL_NO_ASN_STRICT` to restore the previous permissive behavior. + * **BREAKING (FIPS 205 SLH-DSA)**: `wc_SlhDsaKey_SignHash`, `wc_SlhDsaKey_SignHashDeterministic`, `wc_SlhDsaKey_SignHashWithRandom`, and `wc_SlhDsaKey_VerifyHash` now take the **caller-pre-hashed message digest** @@ -46,6 +57,14 @@ per-record nonce. Scoped to TLS 1.3, non-DTLS, non-QUIC; requires `WOLF_CRYPTO_CB` and `WOLF_CRYPTO_CB_AES_SETKEY`. +* **BREAKING (RFC 6960 4.2.2.2)**: OCSP responder authorization is now + strictly enforced. Removes the non-compliant `CheckOcspResponderChain()` + fallback, which authorized any OCSP responder cert issued by an ancestor + of the target's issuer; [RFC 6960 4.2.2.2](https://datatracker.ietf.org/doc/html/rfc6960#section-4.2.2.2) + requires direct issuance by the CA identified in the request. Also + removes the now-unused `WOLFSSL_NO_OCSP_ISSUER_CHAIN_CHECK` macro and + the `vp` parameter from `CheckOcspResponder()`. + # wolfSSL Release 5.9.1 (Apr. 8, 2026) Release 5.9.1 has been developed according to wolfSSL's development and QA diff --git a/Docker/OpenWrt/runTests.sh b/Docker/OpenWrt/runTests.sh index 1585da5d9a..fd802a891a 100755 --- a/Docker/OpenWrt/runTests.sh +++ b/Docker/OpenWrt/runTests.sh @@ -1,14 +1,20 @@ #!/bin/sh -runCMD() { # usage: runCMD "" "" +runCMD() { # usage: runCMD "" "[ ...]" TMP_FILE=$(mktemp) - eval $1 > $TMP_FILE 2>&1 + eval $1 > "$TMP_FILE" 2>&1 RETVAL=$? - if [ "$RETVAL" != "$2" ]; then - echo "Command ($1) returned ${RETVAL}, but expected $2. Error output:" - cat $TMP_FILE - exit 1 - fi + # Accept any code in the space-separated list "$2" (e.g. "4 5"). + case " $2 " in + *" $RETVAL "*) + rm -f "$TMP_FILE" + return 0 + ;; + esac + echo "Command ($1) returned ${RETVAL}, but expected one of: $2. Error output:" + cat "$TMP_FILE" + rm -f "$TMP_FILE" + exit 1 } # Successful tests @@ -18,10 +24,15 @@ runCMD "ldd /lib/libustream-ssl.so" 0 runCMD "sed '\/src\/gz openwrt_kmods https:\/\/downloads.openwrt.org\/releases\/21.02-SNAPSHOT\/targets\/x86\/64\/kmods\/5.4.238-1-5a722da41bc36de95a7195be6fce1b45/s//#&/' -i /etc/opkg/distfeeds.conf" 0 runCMD "opkg update" 0 runCMD "uclient-fetch 'https://letsencrypt.org'" 0 -# Negative tests -runCMD "uclient-fetch --ca-certificate=/dev/null 'https://letsencrypt.org'" 5 -runCMD "uclient-fetch 'https://self-signed.badssl.com/'" 5 -runCMD "uclient-fetch 'https://untrusted-root.badssl.com/'" 5 -runCMD "uclient-fetch 'https://expired.badssl.com/'" 5 +# Negative tests: each must fail TLS verification, so a non-zero exit is expected. +# BAND-AID: accept exit 4 OR 5. 5 = clean "invalid certificate"; 4 = "connection +# reset prematurely". Since wolfSSL enabled ML-KEM by default the TLS ClientHello +# grew (~1.8 KB) and some servers/load balancers intermittently RST it before the +# cert is evaluated (seen with badssl.com, ~1 in 3) -> exit 4 on any of these. +# TODO: proper fix (retry-on-reset, or a local bad-cert server). +runCMD "uclient-fetch --ca-certificate=/dev/null 'https://letsencrypt.org'" "4 5" +runCMD "uclient-fetch 'https://self-signed.badssl.com/'" "4 5" +runCMD "uclient-fetch 'https://untrusted-root.badssl.com/'" "4 5" +runCMD "uclient-fetch 'https://expired.badssl.com/'" "4 5" echo "All tests passed." diff --git a/bsdkm/wolfkmod.c b/bsdkm/wolfkmod.c index 872d68589f..6e19995ca7 100644 --- a/bsdkm/wolfkmod.c +++ b/bsdkm/wolfkmod.c @@ -491,6 +491,7 @@ static int wolfkdriv_attach(device_t dev) attach_out: if (error) { + device_printf(dev, "error: attach_out: %d\n", error); wolfkdriv_unregister(softc); (void)wolfkmod_cleanup(); } @@ -503,16 +504,14 @@ static int wolfkdriv_detach(device_t dev) struct wolfkdriv_softc * softc = NULL; int ret = 0; + /* unregister wolfcrypt algs */ + softc = device_get_softc(dev); + wolfkdriv_unregister(softc); ret = wolfkmod_cleanup(); - - if (ret == 0) { - /* unregister wolfcrypt algs */ - softc = device_get_softc(dev); - wolfkdriv_unregister(softc); - } - #if defined(WOLFSSL_BSDKM_VERBOSE_DEBUG) - device_printf(dev, "info: exiting detach\n"); + device_printf(dev, "info: exiting detach: %d\n", ret); + #else + (void)ret; #endif /* WOLFSSL_BSDKM_VERBOSE_DEBUG */ return (0); @@ -802,6 +801,7 @@ static int wolfkdriv_cbc_work(device_t dev, wolfkdriv_session_t * session, cbc_work_out: /* cleanup. */ + wc_ForceZero(&aes, sizeof(aes)); wc_ForceZero(iv, sizeof(iv)); wc_ForceZero(block, sizeof(block)); @@ -812,6 +812,11 @@ cbc_work_out: error); #endif /* WOLFSSL_BSDKM_VERBOSE_DEBUG */ + if (error < 0) { + /* convert wolfcrypt errors to EINVAL. */ + error = EINVAL; + } + return (error); } @@ -979,6 +984,7 @@ static int wolfkdriv_gcm_work(device_t dev, wolfkdriv_session_t * session, gcm_work_out: /* cleanup. */ + wc_ForceZero(&aes, sizeof(aes)); wc_ForceZero(iv, sizeof(iv)); wc_ForceZero(auth_tag, sizeof(auth_tag)); @@ -989,6 +995,11 @@ gcm_work_out: error); #endif /* WOLFSSL_BSDKM_VERBOSE_DEBUG */ + if (error < 0) { + /* convert wolfcrypt errors to EINVAL. */ + error = EINVAL; + } + return (error); } diff --git a/bsdkm/wolfkmod_aes.c b/bsdkm/wolfkmod_aes.c index 9fb776e988..fc356d6a86 100644 --- a/bsdkm/wolfkmod_aes.c +++ b/bsdkm/wolfkmod_aes.c @@ -212,7 +212,7 @@ static int wolfkdriv_test_aes_gcm(device_t dev, int crid) XMEMSET(resultT, 0, sizeof(resultT)); XMEMSET(resultC, 0, sizeof(resultC)); - XMEMSET(resultC2, 0, sizeof(resultC)); + XMEMSET(resultC2, 0, sizeof(resultC2)); XMEMCPY(resultC2, p, sizeof(p)); /* wolfcrypt encrypt */ diff --git a/bsdkm/x86_vecreg.c b/bsdkm/x86_vecreg.c index c96cc0afd1..48f0df7b47 100644 --- a/bsdkm/x86_vecreg.c +++ b/bsdkm/x86_vecreg.c @@ -139,6 +139,11 @@ int wolfkmod_vecreg_save(int flags_unused) wolfkmod_print_curthread("wolfkmod_vecreg_save"); #endif + if (fpu_states == NULL) { + printf("error: wolfkmod_vecreg_save: fpu_states null\n"); + return (EINVAL); + } + if (is_fpu_kern_thread(0)) { /* kernel fpu threads are special, do nothing. They own a * persistent, dedicated fpu context. */ @@ -189,6 +194,11 @@ void wolfkmod_vecreg_restore(void) wolfkmod_print_curthread("wolfkmod_vecreg_restore"); #endif + if (fpu_states == NULL) { + printf("error: wolfkmod_vecreg_restore: fpu_states null\n"); + return; + } + if (is_fpu_kern_thread(0)) { /* kernel fpu threads are special, do nothing. They own a * persistent, dedicated fpu context. */ diff --git a/certs/include.am b/certs/include.am index 0b17390c88..6afa36129b 100644 --- a/certs/include.am +++ b/certs/include.am @@ -162,7 +162,6 @@ include certs/falcon/include.am include certs/rsapss/include.am include certs/slhdsa/include.am include certs/lms/include.am -include certs/xmss/include.am include certs/rpk/include.am include certs/acert/include.am include certs/mldsa/include.am diff --git a/certs/lms/bc_hss_L2_H5_W8_root.der b/certs/lms/bc_hss_L2_H5_W8_root.der deleted file mode 100644 index 824d5664af..0000000000 Binary files a/certs/lms/bc_hss_L2_H5_W8_root.der and /dev/null differ diff --git a/certs/lms/bc_hss_L3_H5_W4_root.der b/certs/lms/bc_hss_L3_H5_W4_root.der deleted file mode 100644 index 43904f7ae7..0000000000 Binary files a/certs/lms/bc_hss_L3_H5_W4_root.der and /dev/null differ diff --git a/certs/lms/bc_lms_chain_ca.der b/certs/lms/bc_lms_chain_ca.der deleted file mode 100644 index e3cebcccbb..0000000000 Binary files a/certs/lms/bc_lms_chain_ca.der and /dev/null differ diff --git a/certs/lms/bc_lms_chain_leaf.der b/certs/lms/bc_lms_chain_leaf.der deleted file mode 100644 index 4346b7aa15..0000000000 Binary files a/certs/lms/bc_lms_chain_leaf.der and /dev/null differ diff --git a/certs/lms/bc_lms_sha256_h10_w8_root.der b/certs/lms/bc_lms_sha256_h10_w8_root.der deleted file mode 100644 index c9ca9bf226..0000000000 Binary files a/certs/lms/bc_lms_sha256_h10_w8_root.der and /dev/null differ diff --git a/certs/lms/bc_lms_sha256_h5_w4_root.der b/certs/lms/bc_lms_sha256_h5_w4_root.der deleted file mode 100644 index ef4941ee8c..0000000000 Binary files a/certs/lms/bc_lms_sha256_h5_w4_root.der and /dev/null differ diff --git a/certs/lms/include.am b/certs/lms/include.am index f9e39c1d04..d5b89871e9 100644 --- a/certs/lms/include.am +++ b/certs/lms/include.am @@ -2,11 +2,10 @@ # All paths should be given relative to the root # +# bc_lms_native_bc_root.der is stock Bouncy Castle output (RFC 9802-aligned +# HSS/LMS) kept as the cross-implementation interop anchor. wolfSSL's own +# LMS certificate/CSR/chain generation is exercised in-process by the +# test_rfc9802_lms_x509_gen unit test, so no other committed fixtures are +# needed here. EXTRA_DIST += \ - certs/lms/bc_lms_sha256_h5_w4_root.der \ - certs/lms/bc_lms_sha256_h10_w8_root.der \ - certs/lms/bc_hss_L2_H5_W8_root.der \ - certs/lms/bc_hss_L3_H5_W4_root.der \ - certs/lms/bc_lms_chain_ca.der \ - certs/lms/bc_lms_chain_leaf.der \ certs/lms/bc_lms_native_bc_root.der diff --git a/certs/ocsp/include.am b/certs/ocsp/include.am index 29ab4dc3b8..aa55cd20be 100644 --- a/certs/ocsp/include.am +++ b/certs/ocsp/include.am @@ -29,6 +29,10 @@ EXTRA_DIST += \ certs/ocsp/ocsp-responder-key.der \ certs/ocsp/ocsp-responder-cert.pem \ certs/ocsp/ocsp-responder-cert.der \ + certs/ocsp/ocsp-responder-int1-key.pem \ + certs/ocsp/ocsp-responder-int1-key.der \ + certs/ocsp/ocsp-responder-int1-cert.pem \ + certs/ocsp/ocsp-responder-int1-cert.der \ certs/ocsp/server1-key.pem \ certs/ocsp/server1-key.der \ certs/ocsp/server1-cert.pem \ diff --git a/certs/ocsp/ocsp-responder-int1-cert.der b/certs/ocsp/ocsp-responder-int1-cert.der new file mode 100644 index 0000000000..c9203cb81b Binary files /dev/null and b/certs/ocsp/ocsp-responder-int1-cert.der differ diff --git a/certs/ocsp/ocsp-responder-int1-cert.pem b/certs/ocsp/ocsp-responder-int1-cert.pem new file mode 100644 index 0000000000..e7447e3fc9 --- /dev/null +++ b/certs/ocsp/ocsp-responder-int1-cert.pem @@ -0,0 +1,273 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 10 (0xa) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, ST=Washington, L=Seattle, O=wolfSSL, OU=Engineering, CN=wolfSSL intermediate CA 1, emailAddress=info@wolfssl.com + Validity + Not Before: May 27 16:15:23 2026 GMT + Not After : Feb 20 16:15:23 2029 GMT + Subject: C=US, ST=Washington, L=Seattle, O=wolfSSL, OU=Engineering, CN=wolfSSL OCSP Responder Int1, emailAddress=info@wolfssl.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:98:82:f0:e7:da:58:cf:85:0b:a4:de:34:41:3f: + 79:5a:ff:75:78:95:c6:89:5c:b7:2e:c4:6d:05:73: + a5:b1:45:58:72:3e:2c:e2:c0:17:87:fe:b4:64:82: + 00:fd:56:7d:8a:73:8d:6f:88:77:bb:98:56:a8:b6: + 28:36:a8:0c:9f:d6:7a:25:1d:ad:10:b8:d0:19:7c: + 80:70:9c:80:26:95:53:42:1c:90:4e:27:ed:f5:6e: + 87:6f:2e:eb:92:95:e0:6f:53:fe:be:17:a9:7f:e6: + b7:09:4b:63:9c:08:97:c8:b3:36:75:38:6d:3e:ff: + d8:e1:22:75:57:1a:5f:60:30:4d:1b:bc:2f:99:7f: + 02:ef:df:24:25:88:57:91:7b:2c:6f:f7:98:90:29: + 9f:12:66:a9:3e:73:c4:81:73:e7:9c:eb:22:f5:6c: + d5:23:e0:7b:ba:a6:ca:16:a3:33:f9:2e:52:a3:a8: + c9:f1:dd:85:1f:c1:94:0b:1e:8f:b7:48:be:20:d0: + da:bd:3b:85:8e:92:c1:f0:7c:ec:2e:c5:27:a0:4e: + 22:c5:c2:4d:1b:66:e7:ac:57:8c:34:2b:a5:55:e9: + 34:9c:7f:33:29:d0:4e:cb:1a:1a:02:17:b2:45:a3: + 49:05:5d:00:79:85:50:91:c0:3d:30:cb:84:0a:9a: + 2d:6d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 Subject Key Identifier: + 90:3C:B9:FB:15:20:AB:F6:6F:D3:F1:C9:71:B0:D0:1D:97:C6:A5:C5 + X509v3 Authority Key Identifier: + keyid:83:C6:3A:89:2C:81:F4:02:D7:9D:4C:E2:2A:C0:71:82:64:44:DA:0E + DirName:/C=US/ST=Washington/L=Seattle/O=wolfSSL/OU=Engineering/CN=wolfSSL root CA/emailAddress=info@wolfssl.com + serial:01 + X509v3 Extended Key Usage: + OCSP Signing + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 3c:42:b5:c3:a3:1a:d7:2d:c6:6a:3d:b2:5c:18:49:85:26:65: + 85:af:c2:2e:46:dc:a1:1c:8d:22:86:fc:a9:73:02:79:60:3e: + e7:f8:cc:ff:c9:b1:38:e0:96:4f:31:b8:e5:b5:0c:b0:1d:1c: + c2:27:29:c7:3f:70:86:5a:61:2e:11:c7:81:75:8a:72:f8:75: + 0c:84:be:65:44:98:ce:29:87:02:30:ed:42:47:fc:75:d9:88: + 73:64:ad:6b:cd:32:96:55:ea:b5:fb:8e:21:ce:02:59:dc:3e: + 9f:33:40:66:c4:be:f0:71:88:ce:f5:98:79:2d:dd:58:2b:28: + bf:09:89:88:05:3e:36:de:e6:b1:9a:fc:4a:80:1b:00:fd:c9: + 2a:46:ce:8c:64:81:b8:25:c9:7d:d2:31:05:2c:49:57:e9:84: + c0:a4:dc:f6:20:7e:fb:c1:d7:c5:bc:ea:07:bf:e6:10:a0:53: + 25:4f:7e:c5:77:a8:b4:c6:98:2c:72:76:49:ea:e5:45:bb:c4: + e5:fc:4b:9c:08:64:b4:2f:bf:97:8e:84:84:d7:30:82:7f:32: + 25:73:00:d5:58:44:2b:4a:2c:08:79:86:50:0f:e9:e7:94:d1: + d4:0e:4f:a9:e0:ab:ba:8b:e8:1a:be:90:92:64:39:10:35:90: + 09:7f:ed:69 +-----BEGIN CERTIFICATE----- +MIIEzTCCA7WgAwIBAgIBCjANBgkqhkiG9w0BAQsFADCBoTELMAkGA1UEBhMCVVMx +EzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxEDAOBgNVBAoM +B3dvbGZTU0wxFDASBgNVBAsMC0VuZ2luZWVyaW5nMSIwIAYDVQQDDBl3b2xmU1NM +IGludGVybWVkaWF0ZSBDQSAxMR8wHQYJKoZIhvcNAQkBFhBpbmZvQHdvbGZzc2wu +Y29tMB4XDTI2MDUyNzE2MTUyM1oXDTI5MDIyMDE2MTUyM1owgaMxCzAJBgNVBAYT +AlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMRAwDgYDVQQHDAdTZWF0dGxlMRAwDgYD +VQQKDAd3b2xmU1NMMRQwEgYDVQQLDAtFbmdpbmVlcmluZzEkMCIGA1UEAwwbd29s +ZlNTTCBPQ1NQIFJlc3BvbmRlciBJbnQxMR8wHQYJKoZIhvcNAQkBFhBpbmZvQHdv +bGZzc2wuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmILw59pY +z4ULpN40QT95Wv91eJXGiVy3LsRtBXOlsUVYcj4s4sAXh/60ZIIA/VZ9inONb4h3 +u5hWqLYoNqgMn9Z6JR2tELjQGXyAcJyAJpVTQhyQTift9W6Hby7rkpXgb1P+vhep +f+a3CUtjnAiXyLM2dThtPv/Y4SJ1VxpfYDBNG7wvmX8C798kJYhXkXssb/eYkCmf +EmapPnPEgXPnnOsi9WzVI+B7uqbKFqMz+S5So6jJ8d2FH8GUCx6Pt0i+INDavTuF +jpLB8HzsLsUnoE4ixcJNG2bnrFeMNCulVek0nH8zKdBOyxoaAheyRaNJBV0AeYVQ +kcA9MMuECpotbQIDAQABo4IBCjCCAQYwCQYDVR0TBAIwADAdBgNVHQ4EFgQUkDy5 ++xUgq/Zv0/HJcbDQHZfGpcUwgcQGA1UdIwSBvDCBuYAUg8Y6iSyB9ALXnUziKsBx +gmRE2g6hgZ2kgZowgZcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9u +MRAwDgYDVQQHDAdTZWF0dGxlMRAwDgYDVQQKDAd3b2xmU1NMMRQwEgYDVQQLDAtF +bmdpbmVlcmluZzEYMBYGA1UEAwwPd29sZlNTTCByb290IENBMR8wHQYJKoZIhvcN +AQkBFhBpbmZvQHdvbGZzc2wuY29tggEBMBMGA1UdJQQMMAoGCCsGAQUFBwMJMA0G +CSqGSIb3DQEBCwUAA4IBAQA8QrXDoxrXLcZqPbJcGEmFJmWFr8IuRtyhHI0ihvyp +cwJ5YD7n+Mz/ybE44JZPMbjltQywHRzCJynHP3CGWmEuEceBdYpy+HUMhL5lRJjO +KYcCMO1CR/x12YhzZK1rzTKWVeq1+44hzgJZ3D6fM0BmxL7wcYjO9Zh5Ld1YKyi/ +CYmIBT423uaxmvxKgBsA/ckqRs6MZIG4Jcl90jEFLElX6YTApNz2IH77wdfFvOoH +v+YQoFMlT37Fd6i0xpgscnZJ6uVFu8Tl/EucCGS0L7+XjoSE1zCCfzIlcwDVWEQr +SiwIeYZQD+nnlNHUDk+p4Ku6i+gavpCSZDkQNZAJf+1p +-----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, ST=Washington, L=Seattle, O=wolfSSL, OU=Engineering, CN=wolfSSL root CA, emailAddress=info@wolfssl.com + Validity + Not Before: Nov 13 20:41:34 2025 GMT + Not After : Aug 9 20:41:34 2028 GMT + Subject: C=US, ST=Washington, L=Seattle, O=wolfSSL, OU=Engineering, CN=wolfSSL intermediate CA 1, emailAddress=info@wolfssl.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:de:b4:c8:5c:77:e0:2d:b1:f5:b9:ad:16:47:35: + a0:35:65:65:c6:e1:40:ab:1e:b4:b9:13:b7:cb:8c: + bb:77:a5:76:da:6d:87:87:f6:4a:4d:13:e4:26:3e: + 27:87:ee:5b:c7:6a:3f:45:30:61:55:5c:f6:35:d1: + 65:fa:98:11:a3:a7:55:d5:be:91:82:4b:fc:be:90: + d6:50:53:63:9a:2c:22:e1:35:11:dc:78:02:97:8a: + e4:46:92:9c:53:08:76:de:1f:53:b6:b8:ca:77:3e: + 79:6e:bc:d0:e3:0d:30:5b:4c:f6:94:0d:30:29:64: + 9f:04:e5:db:fb:89:60:67:bb:af:26:83:51:77:24: + 2f:2b:0b:a1:94:81:10:98:e8:eb:26:a8:1e:7c:e4: + c4:6c:67:06:95:55:4a:dd:52:f4:f2:60:6d:01:2b: + 19:91:35:6d:a4:08:47:06:71:24:00:d9:de:c6:56: + f3:8b:53:2c:e2:9a:96:a5:f3:62:e5:c4:e3:23:f2: + d2:fc:21:ea:0f:62:76:8d:d5:99:48:ce:dc:58:c4: + bb:7f:da:94:2c:80:74:83:c5:e0:b0:15:7e:41:fd: + 0e:f2:f4:f0:78:76:7b:ad:26:0d:aa:48:96:17:2f: + 21:e3:95:2b:26:37:f9:aa:80:2f:fe:de:f6:5e:bc: + 97:7f + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:TRUE + X509v3 Subject Key Identifier: + 83:C6:3A:89:2C:81:F4:02:D7:9D:4C:E2:2A:C0:71:82:64:44:DA:0E + X509v3 Authority Key Identifier: + keyid:73:B0:1C:A4:2F:82:CB:CF:47:A5:38:D7:B0:04:82:3A:7E:72:15:21 + DirName:/C=US/ST=Washington/L=Seattle/O=wolfSSL/OU=Engineering/CN=wolfSSL root CA/emailAddress=info@wolfssl.com + serial:63 + X509v3 Key Usage: + Certificate Sign, CRL Sign + Authority Information Access: + OCSP - URI:http://127.0.0.1:22220 + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 77:ec:89:37:d4:35:2e:24:fd:d2:de:d9:98:87:be:52:ae:b5: + d4:f6:13:34:12:2c:f0:78:98:07:9f:f7:e4:76:df:6e:eb:97: + c7:03:a3:e6:15:6e:e2:94:16:6b:ed:59:a9:4a:10:a0:cc:c2: + 61:78:c7:fb:1c:04:4a:20:c1:fc:94:c6:99:b0:3a:8c:2f:2b: + 7d:15:30:53:c7:9b:73:54:6f:4d:16:a6:ab:2d:8a:51:70:1f: + 1b:8e:60:0b:56:8b:f2:94:01:fd:81:5f:73:cb:ed:5e:cc:4a: + 71:c1:a9:1a:d7:c7:2b:5a:66:02:77:da:10:e8:45:42:a0:7c: + ef:78:ff:dd:08:f6:84:2f:41:f5:18:c9:a2:48:d1:5d:b6:a4: + 4d:32:af:83:5d:b9:64:ec:40:e9:62:38:ef:1b:d1:8e:c9:e8: + fd:b3:e8:e1:a1:da:16:1e:26:3c:82:36:cb:8d:80:67:33:ca: + 30:bf:93:03:c8:9c:be:a2:6f:aa:7c:76:24:3d:06:99:ab:a7: + fe:12:f3:db:fd:a0:8a:b5:0d:c1:9c:90:b7:ca:7e:6d:fb:ff: + 2a:c3:fe:7c:9f:41:e8:c2:7f:4f:fa:4b:49:c4:a0:d0:bc:fd: + 38:34:22:ff:d5:83:79:70:7f:6c:30:8d:ad:93:fb:b8:77:01: + 34:af:cc:0e +-----BEGIN CERTIFICATE----- +MIIE8DCCA9igAwIBAgIBATANBgkqhkiG9w0BAQsFADCBlzELMAkGA1UEBhMCVVMx +EzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxEDAOBgNVBAoM +B3dvbGZTU0wxFDASBgNVBAsMC0VuZ2luZWVyaW5nMRgwFgYDVQQDDA93b2xmU1NM +IHJvb3QgQ0ExHzAdBgkqhkiG9w0BCQEWEGluZm9Ad29sZnNzbC5jb20wHhcNMjUx +MTEzMjA0MTM0WhcNMjgwODA5MjA0MTM0WjCBoTELMAkGA1UEBhMCVVMxEzARBgNV +BAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxEDAOBgNVBAoMB3dvbGZT +U0wxFDASBgNVBAsMC0VuZ2luZWVyaW5nMSIwIAYDVQQDDBl3b2xmU1NMIGludGVy +bWVkaWF0ZSBDQSAxMR8wHQYJKoZIhvcNAQkBFhBpbmZvQHdvbGZzc2wuY29tMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3rTIXHfgLbH1ua0WRzWgNWVl +xuFAqx60uRO3y4y7d6V22m2Hh/ZKTRPkJj4nh+5bx2o/RTBhVVz2NdFl+pgRo6dV +1b6Rgkv8vpDWUFNjmiwi4TUR3HgCl4rkRpKcUwh23h9TtrjKdz55brzQ4w0wW0z2 +lA0wKWSfBOXb+4lgZ7uvJoNRdyQvKwuhlIEQmOjrJqgefOTEbGcGlVVK3VL08mBt +ASsZkTVtpAhHBnEkANnexlbzi1Ms4pqWpfNi5cTjI/LS/CHqD2J2jdWZSM7cWMS7 +f9qULIB0g8XgsBV+Qf0O8vTweHZ7rSYNqkiWFy8h45UrJjf5qoAv/t72XryXfwID +AQABo4IBOTCCATUwDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQUg8Y6iSyB9ALXnUzi +KsBxgmRE2g4wgcQGA1UdIwSBvDCBuYAUc7AcpC+Cy89HpTjXsASCOn5yFSGhgZ2k +gZowgZcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMRAwDgYDVQQH +DAdTZWF0dGxlMRAwDgYDVQQKDAd3b2xmU1NMMRQwEgYDVQQLDAtFbmdpbmVlcmlu +ZzEYMBYGA1UEAwwPd29sZlNTTCByb290IENBMR8wHQYJKoZIhvcNAQkBFhBpbmZv +QHdvbGZzc2wuY29tggFjMAsGA1UdDwQEAwIBBjAyBggrBgEFBQcBAQQmMCQwIgYI +KwYBBQUHMAGGFmh0dHA6Ly8xMjcuMC4wLjE6MjIyMjAwDQYJKoZIhvcNAQELBQAD +ggEBAHfsiTfUNS4k/dLe2ZiHvlKutdT2EzQSLPB4mAef9+R2327rl8cDo+YVbuKU +FmvtWalKEKDMwmF4x/scBEogwfyUxpmwOowvK30VMFPHm3NUb00WpqstilFwHxuO +YAtWi/KUAf2BX3PL7V7MSnHBqRrXxytaZgJ32hDoRUKgfO94/90I9oQvQfUYyaJI +0V22pE0yr4NduWTsQOliOO8b0Y7J6P2z6OGh2hYeJjyCNsuNgGczyjC/kwPInL6i +b6p8diQ9Bpmrp/4S89v9oIq1DcGckLfKfm37/yrD/nyfQejCf0/6S0nEoNC8/Tg0 +Iv/Vg3lwf2wwja2T+7h3ATSvzA4= +-----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 99 (0x63) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, ST=Washington, L=Seattle, O=wolfSSL, OU=Engineering, CN=wolfSSL root CA, emailAddress=info@wolfssl.com + Validity + Not Before: Nov 13 20:41:34 2025 GMT + Not After : Aug 9 20:41:34 2028 GMT + Subject: C=US, ST=Washington, L=Seattle, O=wolfSSL, OU=Engineering, CN=wolfSSL root CA, emailAddress=info@wolfssl.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:ab:2c:b4:2f:1d:06:09:ef:4e:29:86:84:7e:cc: + bf:a6:79:7c:f0:c0:c1:64:25:8c:75:b7:10:05:ca: + 48:27:0c:0e:32:1c:b0:fe:99:85:39:b6:b9:a2:f7: + 27:ff:6d:3c:8c:16:73:29:21:7f:8b:a6:54:71:90: + ad:cc:05:b9:9f:15:c7:0a:3f:5f:69:f4:0a:5f:8c: + 71:b5:2c:bf:66:e2:03:9a:32:f4:d2:ec:2a:89:4b: + f9:35:88:14:33:47:4e:2e:05:79:01:ed:64:36:76: + b9:f8:85:cd:01:88:ac:c5:b2:b1:59:b8:cd:5a:f4: + 09:09:38:9b:da:5a:cf:ce:78:99:1f:49:3d:41:d6: + 06:7c:52:99:c8:97:d1:b3:80:3a:a2:4f:36:c4:c5: + 96:30:77:31:38:c8:70:cc:e1:67:06:b3:2b:2f:93: + b5:69:cf:83:7e:88:53:9b:0f:46:21:4c:d6:05:36: + 44:99:60:68:47:e5:32:01:12:d4:10:73:ae:9a:34: + 94:fa:6e:b8:58:4f:7b:5b:8a:92:97:ad:fd:97:b9: + 75:ca:c2:d4:45:7d:17:6b:cd:2f:f3:63:7a:0e:30: + b5:0b:a9:d9:a6:7c:74:60:9d:cc:09:03:43:f1:0f: + 90:d3:b7:fe:6c:9f:d9:cd:78:4b:15:ae:8c:5b:f9: + 99:81 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:TRUE + X509v3 Subject Key Identifier: + 73:B0:1C:A4:2F:82:CB:CF:47:A5:38:D7:B0:04:82:3A:7E:72:15:21 + X509v3 Authority Key Identifier: + keyid:73:B0:1C:A4:2F:82:CB:CF:47:A5:38:D7:B0:04:82:3A:7E:72:15:21 + DirName:/C=US/ST=Washington/L=Seattle/O=wolfSSL/OU=Engineering/CN=wolfSSL root CA/emailAddress=info@wolfssl.com + serial:63 + X509v3 Key Usage: + Certificate Sign, CRL Sign + Authority Information Access: + OCSP - URI:http://127.0.0.1:22220 + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 58:41:01:e5:1b:ce:bc:51:0c:23:b2:66:df:39:d9:1e:b1:bd: + 9a:db:fa:da:16:83:26:6e:7e:2e:f9:5d:46:9a:52:a0:09:6f: + f2:c0:96:ba:49:ad:29:54:06:e9:21:d6:36:5e:d5:43:07:2c: + 5d:4e:b7:bf:7c:e5:91:75:ea:0d:56:7c:a3:fd:82:d8:2e:70: + fa:fc:ab:36:36:d5:ba:63:d5:42:da:21:b4:50:9a:86:8a:df: + 21:26:03:e8:ca:6f:c7:51:50:6c:cc:40:da:4e:8f:06:15:c0: + 9a:0d:7a:80:2c:95:aa:5a:ad:e2:66:b0:32:d6:74:87:ea:7a: + b2:46:d5:2c:cf:fa:18:8a:2f:e0:3a:ae:17:6a:f2:ce:75:8d: + e4:4d:74:8f:e7:c6:21:29:65:5d:41:07:fb:29:d9:be:ea:b2: + e3:80:07:8c:14:8d:a3:7d:d1:51:af:26:9d:cd:01:d5:80:af: + 68:12:41:2b:eb:94:cc:45:d1:c7:66:f3:f9:15:72:be:94:e3: + 21:6d:f1:08:78:b6:5a:ee:73:09:4b:f4:1a:5e:02:2a:25:f0: + 3d:d2:03:f2:22:15:4b:3d:aa:35:ea:90:ca:44:4e:61:77:db: + b4:94:46:77:c6:8c:33:09:b6:84:3c:4e:ac:ad:9d:e0:2f:22: + 5a:be:25:19 +-----BEGIN CERTIFICATE----- +MIIE5jCCA86gAwIBAgIBYzANBgkqhkiG9w0BAQsFADCBlzELMAkGA1UEBhMCVVMx +EzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxEDAOBgNVBAoM +B3dvbGZTU0wxFDASBgNVBAsMC0VuZ2luZWVyaW5nMRgwFgYDVQQDDA93b2xmU1NM +IHJvb3QgQ0ExHzAdBgkqhkiG9w0BCQEWEGluZm9Ad29sZnNzbC5jb20wHhcNMjUx +MTEzMjA0MTM0WhcNMjgwODA5MjA0MTM0WjCBlzELMAkGA1UEBhMCVVMxEzARBgNV +BAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxEDAOBgNVBAoMB3dvbGZT +U0wxFDASBgNVBAsMC0VuZ2luZWVyaW5nMRgwFgYDVQQDDA93b2xmU1NMIHJvb3Qg +Q0ExHzAdBgkqhkiG9w0BCQEWEGluZm9Ad29sZnNzbC5jb20wggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCrLLQvHQYJ704phoR+zL+meXzwwMFkJYx1txAF +ykgnDA4yHLD+mYU5trmi9yf/bTyMFnMpIX+LplRxkK3MBbmfFccKP19p9ApfjHG1 +LL9m4gOaMvTS7CqJS/k1iBQzR04uBXkB7WQ2drn4hc0BiKzFsrFZuM1a9AkJOJva +Ws/OeJkfST1B1gZ8UpnIl9GzgDqiTzbExZYwdzE4yHDM4WcGsysvk7Vpz4N+iFOb +D0YhTNYFNkSZYGhH5TIBEtQQc66aNJT6brhYT3tbipKXrf2XuXXKwtRFfRdrzS/z +Y3oOMLULqdmmfHRgncwJA0PxD5DTt/5sn9nNeEsVroxb+ZmBAgMBAAGjggE5MIIB +NTAMBgNVHRMEBTADAQH/MB0GA1UdDgQWBBRzsBykL4LLz0elONewBII6fnIVITCB +xAYDVR0jBIG8MIG5gBRzsBykL4LLz0elONewBII6fnIVIaGBnaSBmjCBlzELMAkG +A1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUx +EDAOBgNVBAoMB3dvbGZTU0wxFDASBgNVBAsMC0VuZ2luZWVyaW5nMRgwFgYDVQQD +DA93b2xmU1NMIHJvb3QgQ0ExHzAdBgkqhkiG9w0BCQEWEGluZm9Ad29sZnNzbC5j +b22CAWMwCwYDVR0PBAQDAgEGMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcwAYYW +aHR0cDovLzEyNy4wLjAuMToyMjIyMDANBgkqhkiG9w0BAQsFAAOCAQEAWEEB5RvO +vFEMI7Jm3znZHrG9mtv62haDJm5+LvldRppSoAlv8sCWukmtKVQG6SHWNl7VQwcs +XU63v3zlkXXqDVZ8o/2C2C5w+vyrNjbVumPVQtohtFCahorfISYD6Mpvx1FQbMxA +2k6PBhXAmg16gCyVqlqt4mawMtZ0h+p6skbVLM/6GIov4DquF2ryznWN5E10j+fG +ISllXUEH+ynZvuqy44AHjBSNo33RUa8mnc0B1YCvaBJBK+uUzEXRx2bz+RVyvpTj +IW3xCHi2Wu5zCUv0Gl4CKiXwPdID8iIVSz2qNeqQykROYXfbtJRGd8aMMwm2hDxO +rK2d4C8iWr4lGQ== +-----END CERTIFICATE----- diff --git a/certs/ocsp/ocsp-responder-int1-key.der b/certs/ocsp/ocsp-responder-int1-key.der new file mode 100644 index 0000000000..8162fe88dd Binary files /dev/null and b/certs/ocsp/ocsp-responder-int1-key.der differ diff --git a/certs/ocsp/ocsp-responder-int1-key.pem b/certs/ocsp/ocsp-responder-int1-key.pem new file mode 100644 index 0000000000..a73d0c2ac9 --- /dev/null +++ b/certs/ocsp/ocsp-responder-int1-key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCYgvDn2ljPhQuk +3jRBP3la/3V4lcaJXLcuxG0Fc6WxRVhyPiziwBeH/rRkggD9Vn2Kc41viHe7mFao +tig2qAyf1nolHa0QuNAZfIBwnIAmlVNCHJBOJ+31bodvLuuSleBvU/6+F6l/5rcJ +S2OcCJfIszZ1OG0+/9jhInVXGl9gME0bvC+ZfwLv3yQliFeReyxv95iQKZ8SZqk+ +c8SBc+ec6yL1bNUj4Hu6psoWozP5LlKjqMnx3YUfwZQLHo+3SL4g0Nq9O4WOksHw +fOwuxSegTiLFwk0bZuesV4w0K6VV6TScfzMp0E7LGhoCF7JFo0kFXQB5hVCRwD0w +y4QKmi1tAgMBAAECggEAExWnocvP+z/x4hKwRU31GK8I+yr66iuA/Mg1wE3leRZt +Z/Zh1YomJ61203D1QL52/UFSfJd+LCp3BautwpEq60GCjWx2QLZvzBCpXe4nlyxu +e8JpSG50t5a6Oe6MKg65RBUltpHtcwTi+LXHZDorDEFo2ihSe2S2tg2C04CIWNfh +CkvSCtth7HmLYtNtQJzjHY7N+I2PQDFW/VxeXBlnVHpyVFqJj3m3t6WFJS9P9Z+J +0VX3iz1UZjdSZec7V0KwIaKQS8+24f2gPIzNM4O488rh6sB8SVZBdHdioDdE3gVv +YuGEVaB1nLqCYKuuzhi5k16n020/OkXL/UdUFy6AIQKBgQDGm0qXuF6xfwW45CVM +cjMG5Q44XRAgfWe3s7N3wzC4ympbd6d/xZuiKKOJuQnHbGMRBwmB7qwjXdsz0hTw +ywC69JwzlCtur3ylfadUsQYhQJOnV2qO15+gnrOVWsJiNFpGRUlyUw3t4mcKbrsn +8VPNj4gKO+6hctkNGfKW+a/iyQKBgQDElZTDR4AgP9N2C2O6TbH585yRklp14Wy5 +NP2NwDyFQyLjb4Jo4K3yeBikA+77VSbsTZ84/cPrbs/5nBi4uRYuDY+2GdxH46jB +Ywm60UgkE0FP1YeAhpAoOIktpTDKWTTcablSHMBXkdKF4KZRxftFxC0T5JchwoD6 +vT+VPYkDhQKBgQDGI9GkUg0u2cH0trA7d0dPHqA0PSxErbgW/tISropiIZdAT7ys +7ZGakx6s3Q1Tht/C8hlbJqlX02BIb9PycyT0X+uiTbWTBMK/O///r2ilLg7hCYZG +ofogPZR+cgCyBvb1WlSvGQsxhAk20EgpzkrELukTBL3LFpBS0MtEMjB2eQKBgQCi +Ryhqm5d1B7sz8ur8XC7TOvrAYKQ0M0ZhDRFR9qL/DxC51s88bFyrj+AnZOfeqchb +wSfzD+ivbOZaEzWFJ6Tbl25O0MI6xgAExBDAGwsGXK7JjGcy/eH6kdEL0RWZtFIi +sVO+KOXOZB35Th1924U1bmAXz9fCkqGOWrMmK4nzUQKBgCgiCQcgsqpfSIfFknD6 +HTHlCV3+tJAeaimw9C9ctxvT6/JlfU/nWQCCi7cAiHp+cYoQmzE7TKAlhdIOgx5Z +MRPoZstFgVHu5VvLRJZEIXBXmGg5hEZilwOUpRXAtC2Nm7yA9J6vrjAyp10jnk+K +NbOQKX7lqmFEo8pmTXqIhwyg +-----END PRIVATE KEY----- diff --git a/certs/ocsp/renewcerts.sh b/certs/ocsp/renewcerts.sh index 24f8a0e493..45864f16ce 100755 --- a/certs/ocsp/renewcerts.sh +++ b/certs/ocsp/renewcerts.sh @@ -131,6 +131,13 @@ update_cert intermediate3-ca "wolfSSL REVOKED intermediate CA" root-ca update_cert ocsp-responder "wolfSSL OCSP Responder" root-ca v3_ocsp 04 +# Delegated OCSP responder issued directly by intermediate1-ca. RFC 6960 +# 4.2.2.2 authorizes a delegated responder only for the CA that issued it. +# We keep one (int1) to exercise the delegated-responder path in the live +# tests; the intermediate2/3 responders sign their OCSP responses directly +# with the CA key (the CA-direct path), so no extra responder certs are needed. +update_cert ocsp-responder-int1 "wolfSSL OCSP Responder Int1" intermediate1-ca v3_ocsp 10 + update_cert server1 "www1.wolfssl.com" intermediate1-ca v3_req1 05 update_cert server2 "www2.wolfssl.com" intermediate1-ca v3_req1 06 # REVOKED update_cert server3 "www3.wolfssl.com" intermediate2-ca v3_req2 07 @@ -153,10 +160,12 @@ openssl ocsp -issuer ./root-ca-cert.pem -cert ./intermediate1-ca-cert.pem -cert kill $PID wait $PID -# Create a response DER buffer for testing leaf certificate +# Create a response DER buffer for testing leaf certificate. Signed by the +# intermediate1-issued responder (RFC 6960 4.2.2.2 requires the delegated +# responder to be directly issued by the CA named in the CertID). openssl ocsp -port 22221 -ndays 1000 -index \ -./index-intermediate1-ca-issued-certs.txt -rsigner ocsp-responder-cert.pem \ --rkey ocsp-responder-key.pem -CA intermediate1-ca-cert.pem -partial_chain & +./index-intermediate1-ca-issued-certs.txt -rsigner ocsp-responder-int1-cert.pem \ +-rkey ocsp-responder-int1-key.pem -CA intermediate1-ca-cert.pem -partial_chain & PID=$! sleep 1 # Make sure server is ready diff --git a/certs/ocsp/test-leaf-response.der b/certs/ocsp/test-leaf-response.der index dc086fed43..1e0f16dece 100644 Binary files a/certs/ocsp/test-leaf-response.der and b/certs/ocsp/test-leaf-response.der differ diff --git a/certs/xmss/bc_xmss_chain_ca.der b/certs/xmss/bc_xmss_chain_ca.der deleted file mode 100644 index 31c8690e5b..0000000000 Binary files a/certs/xmss/bc_xmss_chain_ca.der and /dev/null differ diff --git a/certs/xmss/bc_xmss_chain_leaf.der b/certs/xmss/bc_xmss_chain_leaf.der deleted file mode 100644 index cf168ee3e2..0000000000 Binary files a/certs/xmss/bc_xmss_chain_leaf.der and /dev/null differ diff --git a/certs/xmss/bc_xmss_sha2_10_256_root.der b/certs/xmss/bc_xmss_sha2_10_256_root.der deleted file mode 100644 index 12d70a002e..0000000000 Binary files a/certs/xmss/bc_xmss_sha2_10_256_root.der and /dev/null differ diff --git a/certs/xmss/bc_xmss_sha2_16_256_root.der b/certs/xmss/bc_xmss_sha2_16_256_root.der deleted file mode 100644 index 91f3bf5546..0000000000 Binary files a/certs/xmss/bc_xmss_sha2_16_256_root.der and /dev/null differ diff --git a/certs/xmss/bc_xmssmt_sha2_20_2_256_root.der b/certs/xmss/bc_xmssmt_sha2_20_2_256_root.der deleted file mode 100644 index 24b47019e1..0000000000 Binary files a/certs/xmss/bc_xmssmt_sha2_20_2_256_root.der and /dev/null differ diff --git a/certs/xmss/bc_xmssmt_sha2_20_4_256_root.der b/certs/xmss/bc_xmssmt_sha2_20_4_256_root.der deleted file mode 100644 index b3037316d2..0000000000 Binary files a/certs/xmss/bc_xmssmt_sha2_20_4_256_root.der and /dev/null differ diff --git a/certs/xmss/bc_xmssmt_sha2_40_8_256_root.der b/certs/xmss/bc_xmssmt_sha2_40_8_256_root.der deleted file mode 100644 index 870faa2c18..0000000000 Binary files a/certs/xmss/bc_xmssmt_sha2_40_8_256_root.der and /dev/null differ diff --git a/certs/xmss/include.am b/certs/xmss/include.am deleted file mode 100644 index ff3bfbee4d..0000000000 --- a/certs/xmss/include.am +++ /dev/null @@ -1,12 +0,0 @@ -# vim:ft=automake -# All paths should be given relative to the root -# - -EXTRA_DIST += \ - certs/xmss/bc_xmss_sha2_10_256_root.der \ - certs/xmss/bc_xmss_sha2_16_256_root.der \ - certs/xmss/bc_xmssmt_sha2_20_2_256_root.der \ - certs/xmss/bc_xmssmt_sha2_20_4_256_root.der \ - certs/xmss/bc_xmssmt_sha2_40_8_256_root.der \ - certs/xmss/bc_xmss_chain_ca.der \ - certs/xmss/bc_xmss_chain_leaf.der diff --git a/configure.ac b/configure.ac index 0c427d4ca7..606ed24118 100644 --- a/configure.ac +++ b/configure.ac @@ -12316,7 +12316,7 @@ AM_CONDITIONAL([BUILD_MLDSA],[test "x$ENABLED_MLDSA" != "xno" || test "x$ENABLED AM_CONDITIONAL([BUILD_ECCSI],[test "x$ENABLED_ECCSI" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_SAKKE],[test "x$ENABLED_SAKKE" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_MEMORY],[test "x$ENABLED_MEMORY" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) -AM_CONDITIONAL([BUILD_MEMUSE],[test "x$ENABLED_ENTROPY_MEMUSE" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) +AM_CONDITIONAL([BUILD_MEMUSE],[test "x$ENABLED_ENTROPY_MEMUSE" != "xno" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_RNG_BANK],[test "$ENABLED_RNG_BANK" = "yes" || test "$ENABLED_USERSETTINGS" = "yes"]) AM_CONDITIONAL([BUILD_RSA],[test "x$ENABLED_RSA" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"]) AM_CONDITIONAL([BUILD_DH],[test "x$ENABLED_DH" != "xno" || test "x$ENABLED_USERSETTINGS" = "xyes"]) diff --git a/doc/dox_comments/header_files/arc4.h b/doc/dox_comments/header_files/arc4.h index 3bbcced77c..7058e09c6f 100644 --- a/doc/dox_comments/header_files/arc4.h +++ b/doc/dox_comments/header_files/arc4.h @@ -7,7 +7,10 @@ Before this method may be called, one must first initialize the ARC4 structure using wc_Arc4SetKey. - \return none + \return 0 Returned upon successfully processing the message. + \return BAD_FUNC_ARG If arc4, out, or in is NULL. + \return MISSING_KEY If no key has been set on the ARC4 structure with + wc_Arc4SetKey. \param arc4 pointer to the ARC4 structure used to process the message \param out pointer to the output buffer in which to store the diff --git a/doc/dox_comments/header_files/des3.h b/doc/dox_comments/header_files/des3.h index 9b071ad752..89d7b5cc31 100644 --- a/doc/dox_comments/header_files/des3.h +++ b/doc/dox_comments/header_files/des3.h @@ -273,6 +273,10 @@ int wc_Des3_SetIV(Des3* des, const byte* iv); with cipher block chaining (CBC) mode. \return 0 Returned upon successfully encrypting the given input message + \return BAD_FUNC_ARG If des, out, or in is NULL. + \return BAD_LENGTH_E If sz is not a multiple of DES_BLOCK_SIZE. + \return MISSING_KEY If no key has been set on the Des3 structure with + wc_Des3_SetKey. \param des pointer to the Des3 structure to use for encryption \param out pointer to the buffer in which to store the encrypted ciphertext @@ -306,6 +310,10 @@ int wc_Des3_CbcEncrypt(Des3* des, byte* out, encryption with cipher block chaining (CBC) mode. \return 0 Returned upon successfully decrypting the given ciphertext + \return BAD_FUNC_ARG If des, out, or in is NULL. + \return BAD_LENGTH_E If sz is not a multiple of DES_BLOCK_SIZE. + \return MISSING_KEY If no key has been set on the Des3 structure with + wc_Des3_SetKey. \param des pointer to the Des3 structure to use for decryption \param out pointer to the buffer in which to store the decrypted plaintext diff --git a/doc/dox_comments/header_files/doxygen_groups.h b/doc/dox_comments/header_files/doxygen_groups.h index c9469fe186..1f308964f9 100644 --- a/doc/dox_comments/header_files/doxygen_groups.h +++ b/doc/dox_comments/header_files/doxygen_groups.h @@ -15,6 +15,70 @@ \defgroup ECC Algorithms - ECC \defgroup ED25519 Algorithms - ED25519 \defgroup ED448 Algorithms - ED448 + \defgroup ML_DSA Algorithms - ML-DSA (FIPS 204) + ML-DSA (Module-Lattice-based Digital Signature Algorithm) is a + quantum-resistant digital signature scheme standardized by NIST as + FIPS 204. The pre-standardization name was Dilithium; legacy + Dilithium type and macro names remain as aliases for unmigrated + consumer code (see ). + + ML-DSA defines three parameter sets identified by NIST security + category: ML-DSA-44 (level 2), ML-DSA-65 (level 3) and ML-DSA-87 + (level 5). All three are supported by the same wc_MlDsaKey object; + the parameter set is selected with wc_MlDsaKey_SetParams(). + + \defgroup ML_KEM Algorithms - ML-KEM (FIPS 203) + ML-KEM (Module-Lattice-based Key Encapsulation Mechanism) is a + quantum-resistant key encapsulation mechanism standardized by NIST + as FIPS 203. The pre-standardization name was Kyber; legacy Kyber + type and macro names remain as aliases for unmigrated consumer + code. + + ML-KEM defines three parameter sets: ML-KEM-512 (NIST level 1), + ML-KEM-768 (level 3) and ML-KEM-1024 (level 5). The variant is + selected when the key is initialized via wc_MlKemKey_Init() or + wc_MlKemKey_New(). + + \defgroup SLH_DSA Algorithms - SLH-DSA (FIPS 205) + SLH-DSA (Stateless Hash-based Digital Signature Algorithm) is a + quantum-resistant signature scheme standardized by NIST as + FIPS 205. It descends from the SPHINCS+ submission and is + stateless: signing does not mutate the private key, so there is no + key-state synchronization burden on the application. + + Twelve parameter sets are supported, formed by combining a hash + family (SHAKE or SHA2), a security category (128/192/256) and a + speed/size tradeoff (s = small signatures, f = fast signing). The + parameter set is selected when the key is initialized via + wc_SlhDsaKey_Init(). + + \defgroup LMS Algorithms - LMS / HSS (RFC 8554) + LMS (Leighton-Micali Signatures) and its multi-tree composition + HSS (Hierarchical Signature System) are stateful hash-based + signature schemes specified in RFC 8554 and NIST SP 800-208. Each + signature consumes a one-time component of the private key, so the + application MUST persist the private key state (via the read/write + callbacks registered with wc_LmsKey_SetReadCb() and + wc_LmsKey_SetWriteCb()) between signing operations. Reusing a + one-time key destroys the security of the scheme. + + The number of signatures available from a key is bounded by the + parameter set; query the remaining count with + wc_LmsKey_SigsLeft(). + + \defgroup XMSS Algorithms - XMSS / XMSS^MT (RFC 8391) + XMSS (eXtended Merkle Signature Scheme) and its multi-tree variant + XMSS^MT are stateful hash-based signature schemes specified in + RFC 8391 and NIST SP 800-208. As with LMS, each signature consumes + a one-time component of the private key, so the application MUST + persist the private key state via the callbacks registered with + wc_XmssKey_SetReadCb() and wc_XmssKey_SetWriteCb(). Reusing a + one-time key destroys the security of the scheme. + + The number of signatures available from a key is bounded by the + parameter set; query the remaining count with + wc_XmssKey_SigsLeft(). + \defgroup ECCSI_Overview Overview of ECCSI ECCSI (Elliptic Curve-Based Certificateless Signatures for Identity-Based Encryption) is specified in RFC 6507 (https://tools.ietf.org/html/rfc6507). diff --git a/doc/dox_comments/header_files/wc_lms.h b/doc/dox_comments/header_files/wc_lms.h new file mode 100644 index 0000000000..485b964dbc --- /dev/null +++ b/doc/dox_comments/header_files/wc_lms.h @@ -0,0 +1,643 @@ +/*! + \ingroup LMS + + \brief Initializes an LmsKey object. Must be called before any + other LMS/HSS operation. Use wc_LmsKey_Free() to release resources + when done. + + LMS (Leighton-Micali Signatures) and the HSS multi-tree + composition (RFC 8554, NIST SP 800-208) are STATEFUL hash-based + signature schemes: each call to wc_LmsKey_Sign() consumes a + one-time component of the private key, and reusing a one-time key + breaks the security of the scheme. Applications MUST persist the + private key state between sign calls; see wc_LmsKey_SetWriteCb() + and wc_LmsKey_SetReadCb(). + + After init the key is in state WC_LMS_STATE_INITED. The + parameters must be set with wc_LmsKey_SetLmsParm() or + wc_LmsKey_SetParameters() before generating or reloading a key. + + \return 0 on success. + \return BAD_FUNC_ARG if key is NULL. + + \param [in,out] key Pointer to the LmsKey to initialize. + \param [in] heap Heap hint for dynamic memory allocation. May be + NULL. + \param [in] devId Device identifier for hardware crypto callbacks. + Use INVALID_DEVID for software-only. + + _Example_ + \code + LmsKey key; + int ret; + + ret = wc_LmsKey_Init(&key, NULL, INVALID_DEVID); + if (ret != 0) { + // error initializing key + } + wc_LmsKey_SetLmsParm(&key, WC_LMS_PARM_L2_H10_W8); + // ... use key ... + wc_LmsKey_Free(&key); + \endcode + + \sa wc_LmsKey_Free + \sa wc_LmsKey_SetLmsParm + \sa wc_LmsKey_SetParameters + \sa wc_LmsKey_MakeKey +*/ +int wc_LmsKey_Init(LmsKey* key, void* heap, int devId); + +/*! + \ingroup LMS + + \brief Initializes an LmsKey with a device-side key identifier. + Equivalent to wc_LmsKey_Init() but also stashes a binary id that + a crypto callback can use to look up the underlying key material + on the device. Only available when wolfSSL is built with + WOLF_PRIVATE_KEY_ID. + + The id is copied into the key object; the caller may free its + buffer immediately after this call returns. + + \return 0 on success. + \return BAD_FUNC_ARG if key is NULL, or id is NULL while len > 0. + \return BUFFER_E if len is negative or greater than + LMS_MAX_ID_LEN. + + \param [in,out] key Pointer to the LmsKey to initialize. + \param [in] id Pointer to the device-side key identifier bytes. + May be NULL when len is 0. + \param [in] len Number of bytes in id; must be in + [0, LMS_MAX_ID_LEN]. + \param [in] heap Heap hint for dynamic memory allocation. + \param [in] devId Device identifier for the crypto callback. + + \sa wc_LmsKey_Init + \sa wc_LmsKey_InitLabel + \sa wc_LmsKey_Free +*/ +int wc_LmsKey_InitId(LmsKey* key, const unsigned char* id, int len, + void* heap, int devId); + +/*! + \ingroup LMS + + \brief Initializes an LmsKey with a device-side key label. + Equivalent to wc_LmsKey_Init() but also stashes a label string + that a crypto callback can use to look up the underlying key + material on the device. Only available when wolfSSL is built with + WOLF_PRIVATE_KEY_ID. + + \return 0 on success. + \return BAD_FUNC_ARG if key or label is NULL. + \return BUFFER_E if label is empty or longer than + LMS_MAX_LABEL_LEN. + + \param [in,out] key Pointer to the LmsKey to initialize. + \param [in] label NUL-terminated device-side key label. + \param [in] heap Heap hint for dynamic memory allocation. + \param [in] devId Device identifier for the crypto callback. + + \sa wc_LmsKey_Init + \sa wc_LmsKey_InitId +*/ +int wc_LmsKey_InitLabel(LmsKey* key, const char* label, void* heap, + int devId); + +/*! + \ingroup LMS + + \brief Selects a predefined LMS/HSS parameter set by name. The + enum wc_LmsParm encodes the tree depth (levels), per-tree height, + Winternitz parameter and hash family in a single value. See the + wc_LmsParm definition for the list of names available in a given + build. + + \return 0 on success. + \return BAD_FUNC_ARG if key is NULL, or if lmsParm is not + recognized or names a parameter set that was not compiled in. + \return BAD_STATE_E if key is not in state WC_LMS_STATE_INITED. + + \param [in,out] key Pointer to an LmsKey in state + WC_LMS_STATE_INITED. + \param [in] lmsParm A wc_LmsParm constant (e.g. + WC_LMS_PARM_L2_H10_W8). + + _Example_ + \code + LmsKey key; + + wc_LmsKey_Init(&key, NULL, INVALID_DEVID); + wc_LmsKey_SetLmsParm(&key, WC_LMS_PARM_L2_H10_W8); + \endcode + + \sa wc_LmsKey_SetParameters + \sa wc_LmsKey_GetParameters + \sa wc_LmsKey_ParmToStr +*/ +int wc_LmsKey_SetLmsParm(LmsKey* key, enum wc_LmsParm lmsParm); + +/*! + \ingroup LMS + + \brief Sets the LMS/HSS parameters individually. The default + SHA-256/256 hash is used. For finer control over the hash family + use wc_LmsKey_SetParameters_ex(). + + The combination of parameters must match one of the allowed sets + in RFC 8554: + - levels: 1..8 + - height: 5, 10, 15, 20 (and 25 in some builds) + - winternitz: 1, 2, 4, or 8 + + The maximum number of signatures available from a key is + 2^(levels * height). + + \return 0 on success. + \return BAD_FUNC_ARG if key is NULL, or if the requested + parameter combination is not supported in this build. + \return BAD_STATE_E if key is not in state WC_LMS_STATE_INITED. + + \param [in,out] key Pointer to an LmsKey in state + WC_LMS_STATE_INITED. + \param [in] levels Number of Merkle-tree levels in the HSS chain. + \param [in] height Height of each individual Merkle tree. + \param [in] winternitz Winternitz parameter (1, 2, 4 or 8). + + \sa wc_LmsKey_SetParameters_ex + \sa wc_LmsKey_SetLmsParm + \sa wc_LmsKey_GetParameters +*/ +int wc_LmsKey_SetParameters(LmsKey* key, int levels, int height, + int winternitz); + +/*! + \ingroup LMS + + \brief Sets the LMS/HSS parameters individually with an explicit + hash family selector. + + \return 0 on success. + \return BAD_FUNC_ARG if key is NULL, or if the requested + parameter combination is not supported in this build. + \return BAD_STATE_E if key is not in state WC_LMS_STATE_INITED. + + \param [in,out] key Pointer to an LmsKey in state + WC_LMS_STATE_INITED. + \param [in] levels Number of Merkle-tree levels. + \param [in] height Height of each tree. + \param [in] winternitz Winternitz parameter (1, 2, 4 or 8). + \param [in] hash Hash family selector identifying SHA-256/256, + SHA-256/192, SHAKE256/256 or SHAKE256/192, as supported by the + build. + + \sa wc_LmsKey_SetParameters + \sa wc_LmsKey_GetParameters_ex +*/ +int wc_LmsKey_SetParameters_ex(LmsKey* key, int levels, int height, + int winternitz, int hash); + +/*! + \ingroup LMS + + \brief Retrieves the LMS/HSS parameters previously set on this + key. + + \return 0 on success. + \return BAD_FUNC_ARG if any pointer is NULL or no parameters are + set. + + \param [in] key Pointer to an LmsKey with parameters set. + \param [out] levels Receives the number of tree levels. + \param [out] height Receives the per-tree height. + \param [out] winternitz Receives the Winternitz parameter. + + \sa wc_LmsKey_SetParameters + \sa wc_LmsKey_GetParameters_ex +*/ +int wc_LmsKey_GetParameters(const LmsKey* key, int* levels, int* height, + int* winternitz); + +/*! + \ingroup LMS + + \brief Retrieves the LMS/HSS parameters and hash family selector + from this key. + + \return 0 on success. + \return BAD_FUNC_ARG if any pointer is NULL or no parameters are + set. + + \param [in] key Pointer to an LmsKey with parameters set. + \param [out] levels Receives the number of tree levels. + \param [out] height Receives the per-tree height. + \param [out] winternitz Receives the Winternitz parameter. + \param [out] hash Receives the hash family selector. + + \sa wc_LmsKey_SetParameters_ex +*/ +int wc_LmsKey_GetParameters_ex(const LmsKey* key, int* levels, int* height, + int* winternitz, int* hash); + +/*! + \ingroup LMS + + \brief Registers the callback that wolfSSL invokes to persist + updated private key state. Because LMS/HSS is stateful, the + application MUST persist the private key after each successful + sign before the signature is released to a peer; otherwise a + crash or restart can lead to one-time key reuse and break the + scheme. + + The callback receives the encoded private key bytes and returns + one of the wc_LmsRc codes. WC_LMS_RC_SAVED_TO_NV_MEMORY signals a + durable write; other return codes are treated as failures. + + \return 0 on success. + \return BAD_FUNC_ARG if key or write_cb is NULL. + + \param [in,out] key Pointer to an LmsKey. + \param [in] write_cb Callback invoked to persist the private key. + + \sa wc_LmsKey_SetReadCb + \sa wc_LmsKey_SetContext + \sa wc_LmsKey_Sign +*/ +int wc_LmsKey_SetWriteCb(LmsKey* key, wc_lms_write_private_key_cb write_cb); + +/*! + \ingroup LMS + + \brief Registers the callback that wolfSSL invokes to load + persisted private key state. Used by wc_LmsKey_Reload() to bring + a saved key back into memory for further signing. + + \return 0 on success. + \return BAD_FUNC_ARG if key or read_cb is NULL. + + \param [in,out] key Pointer to an LmsKey. + \param [in] read_cb Callback invoked to load the private key. + + \sa wc_LmsKey_SetWriteCb + \sa wc_LmsKey_SetContext + \sa wc_LmsKey_Reload +*/ +int wc_LmsKey_SetReadCb(LmsKey* key, wc_lms_read_private_key_cb read_cb); + +/*! + \ingroup LMS + + \brief Sets the opaque context pointer passed to both the read + and write private-key callbacks. Typically used to carry a file + handle, database connection, or other persistence-layer state. + + \return 0 on success. + \return BAD_FUNC_ARG if key is NULL. + + \param [in,out] key Pointer to an LmsKey. + \param [in] context Application-defined pointer; may be NULL. + + \sa wc_LmsKey_SetReadCb + \sa wc_LmsKey_SetWriteCb +*/ +int wc_LmsKey_SetContext(LmsKey* key, void* context); + +/*! + \ingroup LMS + + \brief Generates a fresh LMS/HSS key pair. Parameters must + already be set (via wc_LmsKey_SetLmsParm() or + wc_LmsKey_SetParameters()) and read/write callbacks must be + registered. The newly generated private key is persisted via the + write callback before the function returns; on success the key + transitions to state WC_LMS_STATE_OK. + + Key generation runtime grows quickly with the first tree's + height: a 3-level h=5 tree is much faster than a 1-level h=15 + tree even though both yield the same total signature count. + + \return 0 on success. + \return BAD_FUNC_ARG if any required pointer is NULL. + \return MEMORY_E on allocation failure. + + \param [in,out] key Pointer to an LmsKey in state + WC_LMS_STATE_PARMSET with callbacks set. + \param [in] rng Pointer to an initialized WC_RNG. + + _Example_ + \code + LmsKey key; + WC_RNG rng; + + wc_LmsKey_Init(&key, NULL, INVALID_DEVID); + wc_LmsKey_SetLmsParm(&key, WC_LMS_PARM_L2_H10_W8); + wc_LmsKey_SetWriteCb(&key, my_write_cb); + wc_LmsKey_SetReadCb(&key, my_read_cb); + wc_LmsKey_SetContext(&key, &my_storage); + wc_InitRng(&rng); + + if (wc_LmsKey_MakeKey(&key, &rng) != 0) { + // error generating key + } + \endcode + + \sa wc_LmsKey_Sign + \sa wc_LmsKey_Reload +*/ +int wc_LmsKey_MakeKey(LmsKey* key, WC_RNG* rng); + +/*! + \ingroup LMS + + \brief Reloads a previously generated LMS/HSS private key from + persistent storage using the registered read callback, restoring + the key to a state where it can sign further messages. On success + the key is in state WC_LMS_STATE_OK. + + The same parameters set at key-generation time must be reapplied + to the LmsKey before calling Reload (the persisted blob is just + the private key bytes; the parameter set is metadata the + application owns). + + \return 0 on success. + \return BAD_FUNC_ARG if any required pointer is NULL. + \return WC_LMS_RC_* mapped error if the read callback fails. + + \param [in,out] key Pointer to an LmsKey with parameters and read + callback set. + + \sa wc_LmsKey_MakeKey + \sa wc_LmsKey_SetReadCb +*/ +int wc_LmsKey_Reload(LmsKey* key); + +/*! + \ingroup LMS + + \brief Returns the size in bytes of the encoded private key for + the parameter set selected on this key. + + \return 0 on success. + \return BAD_FUNC_ARG if key or len is NULL. + + \param [in] key Pointer to an LmsKey with parameters set. + \param [out] len Receives the private key size in bytes. + + \sa wc_LmsKey_GetPubLen + \sa wc_LmsKey_GetSigLen +*/ +int wc_LmsKey_GetPrivLen(const LmsKey* key, word32* len); + +/*! + \ingroup LMS + + \brief Returns the size in bytes of the LMS/HSS public key for + the parameter set selected on this key. + + \return 0 on success. + \return BAD_FUNC_ARG if key or len is NULL. + + \param [in] key Pointer to an LmsKey with parameters set. + \param [out] len Receives the public key size in bytes. + + \sa wc_LmsKey_ExportPubRaw + \sa wc_LmsKey_GetPrivLen +*/ +int wc_LmsKey_GetPubLen(const LmsKey* key, word32* len); + +/*! + \ingroup LMS + + \brief Returns the LMS/HSS signature size in bytes for the + parameter set selected on this key. + + \return 0 on success. + \return BAD_FUNC_ARG if key or len is NULL. + + \param [in] key Pointer to an LmsKey with parameters set. + \param [out] len Receives the signature size in bytes. + + \sa wc_LmsKey_Sign +*/ +int wc_LmsKey_GetSigLen(const LmsKey* key, word32* len); + +/*! + \ingroup LMS + + \brief Signs msg with the LMS/HSS private key in key. On entry + *sigSz is the size of the sig buffer; on success it is updated to + the bytes written. + + Each successful sign call consumes a one-time component of the + private key. The updated key state is persisted via the + registered write callback BEFORE the new signature is returned to + the caller. If the write callback fails the sign call fails and + the signature is not released. When the supply of one-time keys + is exhausted the key transitions to state WC_LMS_STATE_NOSIGS and + further sign attempts return SIG_OTHER_E (or similar) -- query + wc_LmsKey_SigsLeft() to detect this condition in advance. + + \return 0 on success. + \return BAD_FUNC_ARG if any required pointer is NULL. + \return BUFFER_E if *sigSz is smaller than the signature size. + \return -1 (or similar) if all one-time keys have been used. + + \param [in,out] key Pointer to an LmsKey in state WC_LMS_STATE_OK. + \param [out] sig Buffer that receives the signature. + \param [in,out] sigSz In: size of sig. Out: bytes written. + \param [in] msg Message to sign. + \param [in] msgSz Length of msg in bytes. + + \sa wc_LmsKey_Verify + \sa wc_LmsKey_SigsLeft + \sa wc_LmsKey_SetWriteCb +*/ +int wc_LmsKey_Sign(LmsKey* key, byte* sig, word32* sigSz, const byte* msg, + int msgSz); + +/*! + \ingroup LMS + + \brief Returns the number of one-time signatures still available + from this key. When the count reaches zero the key can no longer + sign and should be retired. + + \return Non-negative number of remaining signatures on success. + \return Negative error code on failure (e.g. BAD_FUNC_ARG if key + is NULL). + + \param [in,out] key Pointer to an LmsKey in state WC_LMS_STATE_OK. + + \sa wc_LmsKey_Sign +*/ +int wc_LmsKey_SigsLeft(LmsKey* key); + +/*! + \ingroup LMS + + \brief Releases resources held by an LmsKey. Safe to call with a + NULL pointer. After this call the key is in state + WC_LMS_STATE_FREED and must be re-initialized before reuse. + + \param [in,out] key Pointer to the LmsKey to free. + + \sa wc_LmsKey_Init +*/ +void wc_LmsKey_Free(LmsKey* key); + +/*! + \ingroup LMS + + \brief Copies the public part of keySrc into keyDst. The + destination key inherits the same parameters and may be used for + verification; it does not carry the private key state and cannot + sign. Useful for handing a verifier the minimal data it needs. + + \return 0 on success. + \return BAD_FUNC_ARG if keyDst or keySrc is NULL. + + \param [in,out] keyDst Pointer to an initialized destination + LmsKey. + \param [in] keySrc Pointer to an LmsKey with the public key. + + \sa wc_LmsKey_ExportPub_ex + \sa wc_LmsKey_ExportPubRaw +*/ +int wc_LmsKey_ExportPub(LmsKey* keyDst, const LmsKey* keySrc); + +/*! + \ingroup LMS + + \brief Like wc_LmsKey_ExportPub() but the destination key is + initialized fresh with the supplied heap and devId. + + \return 0 on success. + \return BAD_FUNC_ARG if keyDst or keySrc is NULL. + + \param [in,out] keyDst Pointer to an LmsKey to populate. + \param [in] keySrc Pointer to an LmsKey with the public key. + \param [in] heap Heap hint for keyDst. + \param [in] devId Device identifier for keyDst. + + \sa wc_LmsKey_ExportPub +*/ +int wc_LmsKey_ExportPub_ex(LmsKey* keyDst, const LmsKey* keySrc, void* heap, + int devId); + +/*! + \ingroup LMS + + \brief Exports the LMS/HSS public key as a raw byte string. On + entry *outLen is the size of out; on success it is updated to the + bytes written. + + \return 0 on success. + \return BAD_FUNC_ARG if any required pointer is NULL. + \return BUFFER_E if *outLen is smaller than the public key size. + + \param [in] key Pointer to an LmsKey. + \param [out] out Buffer that receives the public key. + \param [in,out] outLen In: size of out. Out: bytes written. + + \sa wc_LmsKey_ImportPubRaw + \sa wc_LmsKey_GetPubLen +*/ +int wc_LmsKey_ExportPubRaw(const LmsKey* key, byte* out, word32* outLen); + +/*! + \ingroup LMS + + \brief Imports a raw LMS/HSS public key into key. The key must be + in state WC_LMS_STATE_INITED. Parameter information is recovered + from the encoded header, after which the key transitions to + state WC_LMS_STATE_VERIFYONLY. + + \return 0 on success. + \return BAD_FUNC_ARG if any required pointer is NULL. + \return BUFFER_E if inLen is too small. + + \param [in,out] key Pointer to an LmsKey in WC_LMS_STATE_INITED. + \param [in] in Raw public key bytes. + \param [in] inLen Length of in in bytes. + + \sa wc_LmsKey_ExportPubRaw + \sa wc_LmsKey_Verify +*/ +int wc_LmsKey_ImportPubRaw(LmsKey* key, const byte* in, word32 inLen); + +/*! + \ingroup LMS + + \brief Verifies an LMS/HSS signature against msg using the public + key held in key. The function returns 0 only when the signature + is valid; any other value indicates the signature was rejected. + + \return 0 on a valid signature. + \return BAD_FUNC_ARG if any required pointer is NULL. + \return SIG_VERIFY_E (or similar) if the signature is invalid or + malformed. + + \param [in,out] key Pointer to an LmsKey with the public key set. + \param [in] sig Signature bytes to verify. + \param [in] sigSz Length of sig in bytes. + \param [in] msg Message that was signed. + \param [in] msgSz Length of msg in bytes. + + \sa wc_LmsKey_Sign + \sa wc_LmsKey_ImportPubRaw +*/ +int wc_LmsKey_Verify(LmsKey* key, const byte* sig, word32 sigSz, + const byte* msg, int msgSz); + +/*! + \ingroup LMS + + \brief Returns a static, NUL-terminated string describing an LMS + parameter set. Useful for logging and diagnostics. + + \return Pointer to a static string on success. + \return NULL if lmsParm is not recognized. + + \param [in] lmsParm A wc_LmsParm constant. + + \sa wc_LmsKey_SetLmsParm +*/ +const char* wc_LmsKey_ParmToStr(enum wc_LmsParm lmsParm); + +/*! + \ingroup LMS + + \brief Returns a pointer to the 16-byte LMS Key Identifier (I) + embedded in the private key, together with its length. The + returned pointer aliases internal key memory and is valid only + until the key is freed. + + \return 0 on success. + \return BAD_FUNC_ARG if any required pointer is NULL. + + \param [in,out] key Pointer to an LmsKey with a private key. + \param [out] kid Receives a pointer to the I bytes. + \param [out] kidSz Receives the length (16 / WC_LMS_I_LEN). + + \sa wc_LmsKey_GetKidFromPrivRaw +*/ +int wc_LmsKey_GetKid(LmsKey* key, const byte** kid, word32* kidSz); + +/*! + \ingroup LMS + + \brief Returns a pointer to the LMS Key Identifier (I) within a + raw encoded private key buffer, without requiring an LmsKey + object. Used to look up the matching state record in persistent + storage during reload. + + \return Pointer to the I bytes within priv on success. + \return NULL if priv is NULL or privSz is too small to contain a + valid header. + + \param [in] priv Encoded private key bytes. + \param [in] privSz Length of priv in bytes. + + \sa wc_LmsKey_GetKid +*/ +const byte* wc_LmsKey_GetKidFromPrivRaw(const byte* priv, word32 privSz); diff --git a/doc/dox_comments/header_files/wc_mldsa.h b/doc/dox_comments/header_files/wc_mldsa.h new file mode 100644 index 0000000000..9a6be48153 --- /dev/null +++ b/doc/dox_comments/header_files/wc_mldsa.h @@ -0,0 +1,932 @@ +/*! + \ingroup ML_DSA + + \brief Initializes a wc_MlDsaKey object. Must be called before any + other ML-DSA operation. Use wc_MlDsaKey_Free() to release resources + when done. + + ML-DSA (FIPS 204) is a quantum-resistant digital signature + algorithm. Three parameter sets are defined and selected via + wc_MlDsaKey_SetParams() after init: + - WC_ML_DSA_44 (NIST security level 2), + - WC_ML_DSA_65 (level 3), + - WC_ML_DSA_87 (level 5). + + \return 0 on success. + \return BAD_FUNC_ARG if key is NULL. + + \param [in,out] key Pointer to the wc_MlDsaKey to initialize. + \param [in] heap Heap hint for dynamic memory allocation. May be + NULL. + \param [in] devId Device identifier for hardware crypto callbacks. + Use INVALID_DEVID for software-only. + + _Example_ + \code + wc_MlDsaKey key; + int ret; + + ret = wc_MlDsaKey_Init(&key, NULL, INVALID_DEVID); + if (ret != 0) { + // error initializing key + } + ret = wc_MlDsaKey_SetParams(&key, WC_ML_DSA_65); + // ... use key ... + wc_MlDsaKey_Free(&key); + \endcode + + \sa wc_MlDsaKey_Free + \sa wc_MlDsaKey_SetParams + \sa wc_MlDsaKey_MakeKey +*/ +int wc_MlDsaKey_Init(wc_MlDsaKey* key, void* heap, int devId); + +/*! + \ingroup ML_DSA + + \brief Allocates and initializes a new wc_MlDsaKey on the heap. + The returned pointer must be released with wc_MlDsaKey_Delete(). + Only available when wolfSSL is built without WC_NO_CONSTRUCTORS. + + \return Pointer to a freshly allocated wc_MlDsaKey on success. + \return NULL on allocation failure. + + \param [in] heap Heap hint for dynamic memory allocation. May be + NULL. + \param [in] devId Device identifier for hardware crypto callbacks. + Use INVALID_DEVID for software-only. + + _Example_ + \code + wc_MlDsaKey* key = wc_MlDsaKey_New(NULL, INVALID_DEVID); + if (key == NULL) { + // allocation failed + } + // ... use key ... + wc_MlDsaKey_Delete(key, &key); + \endcode + + \sa wc_MlDsaKey_Delete + \sa wc_MlDsaKey_Init +*/ +wc_MlDsaKey* wc_MlDsaKey_New(void* heap, int devId); + +/*! + \ingroup ML_DSA + + \brief Frees and zeros a heap-allocated wc_MlDsaKey previously + returned by wc_MlDsaKey_New(). On success the caller's pointer + variable is set to NULL via key_p when key_p is not NULL. Only + available when wolfSSL is built without WC_NO_CONSTRUCTORS. + + \return 0 on success. + \return BAD_FUNC_ARG if key is NULL. + + \param [in,out] key The wc_MlDsaKey to free. + \param [in,out] key_p Optional address of the caller's pointer + variable; when not NULL, it is set to NULL on success. + + \sa wc_MlDsaKey_New +*/ +int wc_MlDsaKey_Delete(wc_MlDsaKey* key, wc_MlDsaKey** key_p); + +/*! + \ingroup ML_DSA + + \brief Initializes a wc_MlDsaKey with a device-side key + identifier. Equivalent to wc_MlDsaKey_Init() but also stashes a + binary id that a crypto callback can use to look up the underlying + key material on the device. Only available when wolfSSL is built + with WOLF_PRIVATE_KEY_ID. + + The id is copied into the key object; the caller may free its + buffer immediately after this call returns. + + \return 0 on success. + \return BAD_FUNC_ARG if key is NULL. + \return BUFFER_E if len is negative or exceeds MLDSA_MAX_ID_LEN. + + \param [in,out] key Pointer to the wc_MlDsaKey to initialize. + \param [in] id Pointer to the device-side key identifier bytes. + May be NULL when len is 0. + \param [in] len Number of bytes in id; must be in + [0, MLDSA_MAX_ID_LEN]. + \param [in] heap Heap hint for dynamic memory allocation. May be + NULL. + \param [in] devId Device identifier for the crypto callback. + Should be a registered cb devId, not INVALID_DEVID. + + \sa wc_MlDsaKey_Init + \sa wc_MlDsaKey_InitLabel + \sa wc_MlDsaKey_Free +*/ +int wc_MlDsaKey_InitId(wc_MlDsaKey* key, const unsigned char* id, int len, + void* heap, int devId); + +/*! + \ingroup ML_DSA + + \brief Initializes a wc_MlDsaKey with a device-side key label. + Equivalent to wc_MlDsaKey_Init() but also stashes a label string + that a crypto callback can use to look up the underlying key + material on the device. Only available when wolfSSL is built with + WOLF_PRIVATE_KEY_ID. + + The label length is taken via XSTRLEN, so embedded NUL bytes + terminate the label. + + \return 0 on success. + \return BAD_FUNC_ARG if key or label is NULL. + \return BUFFER_E if label is empty or longer than + MLDSA_MAX_LABEL_LEN. + + \param [in,out] key Pointer to the wc_MlDsaKey to initialize. + \param [in] label NUL-terminated device-side key label string. + \param [in] heap Heap hint for dynamic memory allocation. May be + NULL. + \param [in] devId Device identifier for the crypto callback. + + \sa wc_MlDsaKey_Init + \sa wc_MlDsaKey_InitId + \sa wc_MlDsaKey_Free +*/ +int wc_MlDsaKey_InitLabel(wc_MlDsaKey* key, const char* label, void* heap, + int devId); + +/*! + \ingroup ML_DSA + + \brief Selects the ML-DSA parameter set for this key. Must be + called after wc_MlDsaKey_Init() and before key generation, signing + or verifying. + + \return 0 on success. + \return BAD_FUNC_ARG if key is NULL or level is not a recognized + parameter set. + \return NOT_COMPILED_IN if level names a parameter set that was + disabled at build time. + + \param [in,out] key Pointer to an initialized wc_MlDsaKey. + \param [in] level Parameter set: WC_ML_DSA_44, WC_ML_DSA_65 or + WC_ML_DSA_87. + + \sa wc_MlDsaKey_GetParams + \sa wc_MlDsaKey_Init +*/ +int wc_MlDsaKey_SetParams(wc_MlDsaKey* key, byte level); + +/*! + \ingroup ML_DSA + + \brief Retrieves the ML-DSA parameter set currently selected on + this key. + + \return 0 on success. + \return BAD_FUNC_ARG if key or level is NULL. + + \param [in] key Pointer to an initialized wc_MlDsaKey. + \param [out] level Receives WC_ML_DSA_44, WC_ML_DSA_65 or + WC_ML_DSA_87. + + \sa wc_MlDsaKey_SetParams +*/ +int wc_MlDsaKey_GetParams(wc_MlDsaKey* key, byte* level); + +/*! + \ingroup ML_DSA + + \brief Releases resources held by a wc_MlDsaKey. After this call + the object must be re-initialized with wc_MlDsaKey_Init() before + it can be used again. Safe to call with a NULL pointer. + + \param [in,out] key Pointer to the wc_MlDsaKey to free. + + \sa wc_MlDsaKey_Init +*/ +void wc_MlDsaKey_Free(wc_MlDsaKey* key); + +/*! + \ingroup ML_DSA + + \brief Generates a new ML-DSA key pair using the provided RNG. + The parameter set must already be set with wc_MlDsaKey_SetParams(). + Both the public and private key components are populated on + success. + + \return 0 on success. + \return BAD_FUNC_ARG if key or rng is NULL. + \return MEMORY_E on allocation failure. + + \param [in,out] key Pointer to a wc_MlDsaKey with parameters set. + \param [in] rng Pointer to an initialized WC_RNG. + + _Example_ + \code + wc_MlDsaKey key; + WC_RNG rng; + + wc_MlDsaKey_Init(&key, NULL, INVALID_DEVID); + wc_MlDsaKey_SetParams(&key, WC_ML_DSA_65); + wc_InitRng(&rng); + + if (wc_MlDsaKey_MakeKey(&key, &rng) != 0) { + // error generating key pair + } + \endcode + + \sa wc_MlDsaKey_MakeKeyFromSeed + \sa wc_MlDsaKey_SetParams +*/ +int wc_MlDsaKey_MakeKey(wc_MlDsaKey* key, WC_RNG* rng); + +/*! + \ingroup ML_DSA + + \brief Deterministically generates an ML-DSA key pair from a + 32-byte seed. Useful for known-answer tests and for applications + that derive the seed from another secret. The seed buffer must + contain exactly 32 bytes. + + \return 0 on success. + \return BAD_FUNC_ARG if key or seed is NULL. + + \param [in,out] key Pointer to a wc_MlDsaKey with parameters set. + \param [in] seed Pointer to a 32-byte seed buffer. + + \sa wc_MlDsaKey_MakeKey +*/ +int wc_MlDsaKey_MakeKeyFromSeed(wc_MlDsaKey* key, const byte* seed); + +/*! + \ingroup ML_DSA + + \brief Signs a message with ML-DSA using the FIPS 204 + randomized-with-context signing API. Pass ctx=NULL and ctxLen=0 + for an empty context. + + On entry *sigLen is the size of the sig buffer; on success it is + updated to the number of bytes written. Use wc_MlDsaKey_SigSize() + or wc_MlDsaKey_GetSigLen() to determine the required buffer size. + + \return 0 on success. + \return BAD_FUNC_ARG if any required pointer is NULL or ctxLen is + invalid. + \return BUFFER_E if the sig buffer is too small. + + \param [in,out] key Pointer to a wc_MlDsaKey with the private key. + \param [in] ctx Optional context string (may be NULL when + ctxLen=0). + \param [in] ctxLen Length of ctx in bytes; must be 0 when ctx is + NULL, and no greater than 255. + \param [out] sig Buffer that receives the signature. + \param [in,out] sigLen In: size of sig. Out: bytes written. + \param [in] msg Message to sign. + \param [in] msgLen Length of msg in bytes. + \param [in] rng Pointer to an initialized WC_RNG. + + \sa wc_MlDsaKey_VerifyCtx + \sa wc_MlDsaKey_SignCtxWithSeed + \sa wc_MlDsaKey_SignCtxHash +*/ +int wc_MlDsaKey_SignCtx(wc_MlDsaKey* key, const byte* ctx, byte ctxLen, + byte* sig, word32* sigLen, const byte* msg, word32 msgLen, WC_RNG* rng); + +/*! + \ingroup ML_DSA + + \brief HashML-DSA signing variant: signs a pre-hashed message. + The caller supplies the hash bytes and identifies the hash + algorithm. This is the "pre-hash" mode of FIPS 204. + + \return 0 on success. + \return BAD_FUNC_ARG if any required pointer is NULL, ctxLen is + invalid, or hashAlg is not supported. + \return BUFFER_E if the sig buffer is too small. + + \param [in,out] key Pointer to a wc_MlDsaKey with the private key. + \param [in] ctx Optional context string (NULL when ctxLen=0). + \param [in] ctxLen Length of ctx in bytes; no greater than 255. + \param [out] sig Buffer that receives the signature. + \param [in,out] sigLen In: size of sig. Out: bytes written. + \param [in] hash The message digest to sign. + \param [in] hashLen Length of hash in bytes. + \param [in] hashAlg Hash algorithm identifier (e.g. WC_HASH_TYPE_SHA256). + \param [in] rng Pointer to an initialized WC_RNG. + + \sa wc_MlDsaKey_SignCtx + \sa wc_MlDsaKey_VerifyCtxHash +*/ +int wc_MlDsaKey_SignCtxHash(wc_MlDsaKey* key, const byte* ctx, byte ctxLen, + byte* sig, word32* sigLen, const byte* hash, word32 hashLen, + int hashAlg, WC_RNG* rng); + +/*! + \ingroup ML_DSA + + \brief Legacy ML-DSA signing API without a context parameter. + Only available when wolfSSL is built with WOLFSSL_MLDSA_NO_CTX. + New code should call wc_MlDsaKey_SignCtx() with ctx=NULL and + ctxLen=0 for a FIPS 204 compliant empty-context signature. + + \return See wc_MlDsaKey_SignCtx(). + + \param [in,out] key Pointer to a wc_MlDsaKey with the private key. + \param [out] sig Buffer that receives the signature. + \param [in,out] sigLen In: size of sig. Out: bytes written. + \param [in] msg Message to sign. + \param [in] msgLen Length of msg in bytes. + \param [in] rng Pointer to an initialized WC_RNG. + + \sa wc_MlDsaKey_SignCtx + \sa wc_MlDsaKey_Verify +*/ +int wc_MlDsaKey_Sign(wc_MlDsaKey* key, byte* sig, word32* sigLen, + const byte* msg, word32 msgLen, WC_RNG* rng); + +/*! + \ingroup ML_DSA + + \brief Deterministic signing variant of wc_MlDsaKey_SignCtx(). The + 32-byte seed replaces the randomness an RNG would supply, so the + same key/ctx/msg/seed always produces the same signature. + + \return See wc_MlDsaKey_SignCtx(). + + \param [in,out] key Pointer to a wc_MlDsaKey with the private key. + \param [in] ctx Optional context string (NULL when ctxLen=0). + \param [in] ctxLen Length of ctx; no greater than 255. + \param [out] sig Buffer that receives the signature. + \param [in,out] sigLen In: size of sig. Out: bytes written. + \param [in] msg Message to sign. + \param [in] msgLen Length of msg in bytes. + \param [in] seed 32-byte seed bytes. + + \sa wc_MlDsaKey_SignCtx + \sa wc_MlDsaKey_SignCtxHashWithSeed +*/ +int wc_MlDsaKey_SignCtxWithSeed(wc_MlDsaKey* key, const byte* ctx, byte ctxLen, + byte* sig, word32* sigLen, const byte* msg, word32 msgLen, + const byte* seed); + +/*! + \ingroup ML_DSA + + \brief Deterministic HashML-DSA signing: like + wc_MlDsaKey_SignCtxHash() but uses the supplied 32-byte seed in + place of an RNG. + + \return See wc_MlDsaKey_SignCtxHash(). + + \param [in,out] key Pointer to a wc_MlDsaKey with the private key. + \param [in] ctx Optional context string (NULL when ctxLen=0). + \param [in] ctxLen Length of ctx; no greater than 255. + \param [out] sig Buffer that receives the signature. + \param [in,out] sigLen In: size of sig. Out: bytes written. + \param [in] hash The message digest to sign. + \param [in] hashLen Length of hash in bytes. + \param [in] hashAlg Hash algorithm identifier. + \param [in] seed 32-byte seed bytes. + + \sa wc_MlDsaKey_SignCtxHash +*/ +int wc_MlDsaKey_SignCtxHashWithSeed(wc_MlDsaKey* key, const byte* ctx, + byte ctxLen, byte* sig, word32* sigLen, const byte* hash, + word32 hashLen, int hashAlg, const byte* seed); + +/*! + \ingroup ML_DSA + + \brief Signs a pre-computed mu value (the externally derived + SHAKE256 hash of (tr || ctx || msg) per FIPS 204) using a + deterministic 32-byte seed. Used by protocols that need to split + the message-hashing step from the signing step. + + \return 0 on success. + \return BAD_FUNC_ARG if any required pointer is NULL or muLen is + not 64. + \return BUFFER_E if the sig buffer is too small. + + \param [in,out] key Pointer to a wc_MlDsaKey with the private key. + \param [out] sig Buffer that receives the signature. + \param [in,out] sigLen In: size of sig. Out: bytes written. + \param [in] mu The 64-byte mu value (SHAKE256 output). + \param [in] muLen Length of mu; must be 64. + \param [in] seed 32-byte seed bytes. + + \sa wc_MlDsaKey_VerifyMu +*/ +int wc_MlDsaKey_SignMuWithSeed(wc_MlDsaKey* key, byte* sig, word32* sigLen, + const byte* mu, word32 muLen, const byte* seed); + +/*! + \ingroup ML_DSA + + \brief Legacy seed-based signing API without a context parameter. + Only available when wolfSSL is built with WOLFSSL_MLDSA_NO_CTX. + New code should use wc_MlDsaKey_SignCtxWithSeed(). + + \return See wc_MlDsaKey_SignCtxWithSeed(). + + \param [in,out] key Pointer to a wc_MlDsaKey with the private key. + \param [out] sig Buffer that receives the signature. + \param [in,out] sigLen In: size of sig. Out: bytes written. + \param [in] msg Message to sign. + \param [in] msgLen Length of msg in bytes. + \param [in] seed 32-byte seed bytes. + + \sa wc_MlDsaKey_SignCtxWithSeed +*/ +int wc_MlDsaKey_SignWithSeed(wc_MlDsaKey* key, byte* sig, word32* sigLen, + const byte* msg, word32 msgLen, const byte* seed); + +/*! + \ingroup ML_DSA + + \brief Verifies an ML-DSA signature produced by + wc_MlDsaKey_SignCtx() or one of its variants. On entry res is set + to 0; on success it is set to 1 when the signature is valid and + left at 0 otherwise. The function's return value reports whether + verification could be carried out at all; a bad signature is NOT a + function-level error. + + \return 0 if verification completed (check res for the result). + \return BAD_FUNC_ARG if any required pointer is NULL or ctxLen is + invalid. + + \param [in,out] key Pointer to a wc_MlDsaKey with the public key. + \param [in] sig Signature bytes to verify. + \param [in] sigLen Length of sig in bytes. + \param [in] ctx Optional context string (NULL when ctxLen=0). + \param [in] ctxLen Length of ctx; no greater than 255. + \param [in] msg Message that was signed. + \param [in] msgLen Length of msg in bytes. + \param [out] res Set to 1 on a valid signature, 0 otherwise. + + \sa wc_MlDsaKey_SignCtx + \sa wc_MlDsaKey_VerifyCtxHash + \sa wc_MlDsaKey_VerifyMu +*/ +int wc_MlDsaKey_VerifyCtx(wc_MlDsaKey* key, const byte* sig, word32 sigLen, + const byte* ctx, byte ctxLen, const byte* msg, word32 msgLen, int* res); + +/*! + \ingroup ML_DSA + + \brief Verifies a HashML-DSA signature where the message digest + was supplied directly. See wc_MlDsaKey_VerifyCtx() for the + semantics of res. + + \return 0 if verification completed (check res for the result). + \return BAD_FUNC_ARG if any required pointer is NULL, ctxLen is + invalid, or hashAlg is unsupported. + + \param [in,out] key Pointer to a wc_MlDsaKey with the public key. + \param [in] sig Signature bytes to verify. + \param [in] sigLen Length of sig in bytes. + \param [in] ctx Optional context string (NULL when ctxLen=0). + \param [in] ctxLen Length of ctx; no greater than 255. + \param [in] hash The message digest that was signed. + \param [in] hashLen Length of hash in bytes. + \param [in] hashAlg Hash algorithm identifier. + \param [out] res Set to 1 on a valid signature, 0 otherwise. + + \sa wc_MlDsaKey_SignCtxHash + \sa wc_MlDsaKey_VerifyCtx +*/ +int wc_MlDsaKey_VerifyCtxHash(wc_MlDsaKey* key, const byte* sig, word32 sigLen, + const byte* ctx, byte ctxLen, const byte* hash, word32 hashLen, + int hashAlg, int* res); + +/*! + \ingroup ML_DSA + + \brief Verifies a signature over a pre-computed 64-byte mu value + (see wc_MlDsaKey_SignMuWithSeed()). See wc_MlDsaKey_VerifyCtx() + for the semantics of res. + + \return 0 if verification completed (check res for the result). + \return BAD_FUNC_ARG if any required pointer is NULL or muLen is + not 64. + + \param [in,out] key Pointer to a wc_MlDsaKey with the public key. + \param [in] sig Signature bytes to verify. + \param [in] sigLen Length of sig in bytes. + \param [in] mu The 64-byte mu value. + \param [in] muLen Length of mu; must be 64. + \param [out] res Set to 1 on a valid signature, 0 otherwise. + + \sa wc_MlDsaKey_SignMuWithSeed +*/ +int wc_MlDsaKey_VerifyMu(wc_MlDsaKey* key, const byte* sig, word32 sigLen, + const byte* mu, word32 muLen, int* res); + +/*! + \ingroup ML_DSA + + \brief Legacy ML-DSA verify API without a context parameter. Only + available when wolfSSL is built with WOLFSSL_MLDSA_NO_CTX. New + code should use wc_MlDsaKey_VerifyCtx() with ctx=NULL and + ctxLen=0. + + \return See wc_MlDsaKey_VerifyCtx(). + + \param [in,out] key Pointer to a wc_MlDsaKey with the public key. + \param [in] sig Signature bytes to verify. + \param [in] sigLen Length of sig in bytes. + \param [in] msg Message that was signed. + \param [in] msgLen Length of msg in bytes. + \param [out] res Set to 1 on a valid signature, 0 otherwise. + + \sa wc_MlDsaKey_VerifyCtx + \sa wc_MlDsaKey_Sign +*/ +int wc_MlDsaKey_Verify(wc_MlDsaKey* key, const byte* sig, word32 sigLen, + const byte* msg, word32 msgLen, int* res); + +/*! + \ingroup ML_DSA + + \brief Returns the size in bytes of the encoded private key for + the parameter set selected on this key. Equivalent to + wc_MlDsaKey_PrivSize() and provided for API compatibility. + + \return Encoded private key size in bytes on success (positive + value). + \return BAD_FUNC_ARG if key is NULL or no parameter set is + selected. + + \param [in] key Pointer to a wc_MlDsaKey with parameters set. + + \sa wc_MlDsaKey_PrivSize + \sa wc_MlDsaKey_PubSize + \sa wc_MlDsaKey_SigSize +*/ +int wc_MlDsaKey_Size(wc_MlDsaKey* key); + +/*! + \ingroup ML_DSA + + \brief Returns the size in bytes of the encoded private key for + the parameter set selected on this key. + + \return Encoded private key size on success (positive value). + \return BAD_FUNC_ARG if key is NULL or no parameter set is + selected. + + \param [in] key Pointer to a wc_MlDsaKey with parameters set. + + \sa wc_MlDsaKey_PubSize + \sa wc_MlDsaKey_GetPrivLen +*/ +int wc_MlDsaKey_PrivSize(wc_MlDsaKey* key); + +/*! + \ingroup ML_DSA + + \brief Returns the size in bytes of the encoded public key for the + parameter set selected on this key. + + \return Encoded public key size on success (positive value). + \return BAD_FUNC_ARG if key is NULL or no parameter set is + selected. + + \param [in] key Pointer to a wc_MlDsaKey with parameters set. + + \sa wc_MlDsaKey_PrivSize + \sa wc_MlDsaKey_GetPubLen +*/ +int wc_MlDsaKey_PubSize(wc_MlDsaKey* key); + +/*! + \ingroup ML_DSA + + \brief Returns the size in bytes of the signature produced by + this key's parameter set. + + \return Signature size on success (positive value). + \return BAD_FUNC_ARG if key is NULL or no parameter set is + selected. + + \param [in] key Pointer to a wc_MlDsaKey with parameters set. + + \sa wc_MlDsaKey_GetSigLen + \sa wc_MlDsaKey_SignCtx +*/ +int wc_MlDsaKey_SigSize(wc_MlDsaKey* key); + +/*! + \ingroup ML_DSA + + \brief Writes the encoded private key size into *len. Equivalent + information to wc_MlDsaKey_PrivSize() but uses an out-parameter + style. + + \return 0 on success. + \return BAD_FUNC_ARG if key or len is NULL, or no parameter set is + selected. + + \param [in] key Pointer to a wc_MlDsaKey with parameters set. + \param [out] len Receives the private key size in bytes. + + \sa wc_MlDsaKey_PrivSize +*/ +int wc_MlDsaKey_GetPrivLen(wc_MlDsaKey* key, int* len); + +/*! + \ingroup ML_DSA + + \brief Writes the encoded public key size into *len. Equivalent + information to wc_MlDsaKey_PubSize() but uses an out-parameter + style. + + \return 0 on success. + \return BAD_FUNC_ARG if key or len is NULL, or no parameter set is + selected. + + \param [in] key Pointer to a wc_MlDsaKey with parameters set. + \param [out] len Receives the public key size in bytes. + + \sa wc_MlDsaKey_PubSize +*/ +int wc_MlDsaKey_GetPubLen(wc_MlDsaKey* key, int* len); + +/*! + \ingroup ML_DSA + + \brief Writes the signature size into *len. Equivalent + information to wc_MlDsaKey_SigSize() but uses an out-parameter + style. + + \return 0 on success. + \return BAD_FUNC_ARG if key or len is NULL, or no parameter set is + selected. + + \param [in] key Pointer to a wc_MlDsaKey with parameters set. + \param [out] len Receives the signature size in bytes. + + \sa wc_MlDsaKey_SigSize +*/ +int wc_MlDsaKey_GetSigLen(wc_MlDsaKey* key, int* len); + +/*! + \ingroup ML_DSA + + \brief Self-checks an ML-DSA key by recomputing the public key + from the private and comparing against the stored public. Only + available when wolfSSL is built with WOLFSSL_MLDSA_CHECK_KEY. + + \return 0 if the key is consistent. + \return BAD_FUNC_ARG if key is NULL. + \return PUBLIC_KEY_E if the recomputed public does not match. + + \param [in] key Pointer to a wc_MlDsaKey with both public and + private parts populated. +*/ +int wc_MlDsaKey_CheckKey(wc_MlDsaKey* key); + +/*! + \ingroup ML_DSA + + \brief Imports a raw ML-DSA public key. The parameter set must + already be selected on the key. inLen must match the size returned + by wc_MlDsaKey_PubSize() for the selected parameter set. + + \return 0 on success. + \return BAD_FUNC_ARG if key or in is NULL. + \return BUFFER_E if inLen does not match the expected public key + size. + + \param [in,out] key Pointer to a wc_MlDsaKey with parameters set. + \param [in] in Raw public key bytes. + \param [in] inLen Length of in in bytes. + + \sa wc_MlDsaKey_ExportPubRaw + \sa wc_MlDsaKey_ImportPrivRaw +*/ +int wc_MlDsaKey_ImportPubRaw(wc_MlDsaKey* key, const byte* in, word32 inLen); + +/*! + \ingroup ML_DSA + + \brief Imports a raw ML-DSA private key. The parameter set must + already be selected. privSz must match the size returned by + wc_MlDsaKey_PrivSize(). + + \return 0 on success. + \return BAD_FUNC_ARG if key or priv is NULL. + \return BUFFER_E if privSz does not match the expected private key + size. + + \param [in,out] key Pointer to a wc_MlDsaKey with parameters set. + \param [in] priv Raw private key bytes. + \param [in] privSz Length of priv in bytes. + + \sa wc_MlDsaKey_ExportPrivRaw + \sa wc_MlDsaKey_ImportKey +*/ +int wc_MlDsaKey_ImportPrivRaw(wc_MlDsaKey* key, const byte* priv, + word32 privSz); + +/*! + \ingroup ML_DSA + + \brief Imports a raw ML-DSA key pair (private and public parts + together). The parameter set must already be selected. + + \return 0 on success. + \return BAD_FUNC_ARG if any required pointer is NULL. + \return BUFFER_E if privSz or pubSz does not match the expected + sizes. + + \param [in,out] key Pointer to a wc_MlDsaKey with parameters set. + \param [in] priv Raw private key bytes. + \param [in] privSz Length of priv. + \param [in] pub Raw public key bytes. + \param [in] pubSz Length of pub. + + \sa wc_MlDsaKey_ExportKey +*/ +int wc_MlDsaKey_ImportKey(wc_MlDsaKey* key, const byte* priv, word32 privSz, + const byte* pub, word32 pubSz); + +/*! + \ingroup ML_DSA + + \brief Exports the raw ML-DSA public key. On entry *outLen is the + size of out; on success it is updated to the bytes written. + + \return 0 on success. + \return BAD_FUNC_ARG if any required pointer is NULL. + \return BUFFER_E if *outLen is smaller than the public key size. + + \param [in] key Pointer to a wc_MlDsaKey with a public key. + \param [out] out Buffer that receives the public key. + \param [in,out] outLen In: size of out. Out: bytes written. + + \sa wc_MlDsaKey_ImportPubRaw +*/ +int wc_MlDsaKey_ExportPubRaw(wc_MlDsaKey* key, byte* out, word32* outLen); + +/*! + \ingroup ML_DSA + + \brief Exports the raw ML-DSA private key. On entry *outLen is the + size of out; on success it is updated to the bytes written. + + \return 0 on success. + \return BAD_FUNC_ARG if any required pointer is NULL. + \return BUFFER_E if *outLen is smaller than the private key size. + + \param [in] key Pointer to a wc_MlDsaKey with a private key. + \param [out] out Buffer that receives the private key. + \param [in,out] outLen In: size of out. Out: bytes written. + + \sa wc_MlDsaKey_ImportPrivRaw +*/ +int wc_MlDsaKey_ExportPrivRaw(wc_MlDsaKey* key, byte* out, word32* outLen); + +/*! + \ingroup ML_DSA + + \brief Exports both raw public and private ML-DSA key components + in one call. + + \return 0 on success. + \return BAD_FUNC_ARG if any required pointer is NULL. + \return BUFFER_E if either buffer is too small. + + \param [in] key Pointer to a wc_MlDsaKey with both key parts. + \param [out] priv Buffer that receives the private key. + \param [in,out] privSz In: size of priv. Out: bytes written. + \param [out] pub Buffer that receives the public key. + \param [in,out] pubSz In: size of pub. Out: bytes written. + + \sa wc_MlDsaKey_ImportKey +*/ +int wc_MlDsaKey_ExportKey(wc_MlDsaKey* key, byte* priv, word32 *privSz, + byte* pub, word32 *pubSz); + +/*! + \ingroup ML_DSA + + \brief Parses an ML-DSA private key from a DER/ASN.1 encoded + buffer (PKCS#8 OneAsymmetricKey). The parameter set is inferred + from the algorithm identifier in the encoding, so it does NOT + need to be set beforehand. On success *inOutIdx is advanced past + the consumed bytes. + + Only available when WOLFSSL_MLDSA_NO_ASN1 is not defined. + + \return 0 on success. + \return BAD_FUNC_ARG if any required pointer is NULL. + \return ASN_PARSE_E on malformed encoding. + + \param [in,out] key Pointer to an initialized wc_MlDsaKey. + \param [in] input DER-encoded private key bytes. + \param [in] inSz Length of input in bytes. + \param [in,out] inOutIdx In: offset into input where decoding + starts. Out: offset past the consumed bytes. + + \sa wc_MlDsaKey_PrivateKeyToDer + \sa wc_MlDsaKey_PublicKeyDecode +*/ +int wc_MlDsaKey_PrivateKeyDecode(wc_MlDsaKey* key, const byte* input, + word32 inSz, word32* inOutIdx); + +/*! + \ingroup ML_DSA + + \brief Parses an ML-DSA public key from a DER/ASN.1 encoded + buffer (SubjectPublicKeyInfo). The parameter set is inferred from + the algorithm identifier. On success *inOutIdx is advanced past + the consumed bytes. + + \return 0 on success. + \return BAD_FUNC_ARG if any required pointer is NULL. + \return ASN_PARSE_E on malformed encoding. + + \param [in,out] key Pointer to an initialized wc_MlDsaKey. + \param [in] input DER-encoded SPKI bytes. + \param [in] inSz Length of input in bytes. + \param [in,out] inOutIdx In: offset into input where decoding + starts. Out: offset past the consumed bytes. + + \sa wc_MlDsaKey_PublicKeyToDer +*/ +int wc_MlDsaKey_PublicKeyDecode(wc_MlDsaKey* key, const byte* input, + word32 inSz, word32* inOutIdx); + +/*! + \ingroup ML_DSA + + \brief Encodes an ML-DSA public key to DER. When withAlg is + non-zero the output is a full SubjectPublicKeyInfo (with + AlgorithmIdentifier); when zero the output is the raw public key + bytes. + + Pass NULL as output to query the required buffer size. + + \return Size of the encoded DER in bytes on success. + \return BAD_FUNC_ARG if key is NULL or no parameter set is + selected. + \return BUFFER_E if output is non-NULL and inLen is smaller than + the required size. + + \param [in] key Pointer to a wc_MlDsaKey with a public key. + \param [out] output Buffer that receives the DER encoding, or + NULL to query size. + \param [in] inLen Size of output (ignored when output is NULL). + \param [in] withAlg Non-zero to emit SubjectPublicKeyInfo, zero + for the raw public key only. + + \sa wc_MlDsaKey_PublicKeyDecode + \sa wc_MlDsaKey_KeyToDer +*/ +int wc_MlDsaKey_PublicKeyToDer(wc_MlDsaKey* key, byte* output, + word32 inLen, int withAlg); + +/*! + \ingroup ML_DSA + + \brief Encodes an ML-DSA key pair (public + private) to DER as a + PKCS#8 OneAsymmetricKey structure. Pass NULL as output to query + the required buffer size. + + \return Size of the encoded DER in bytes on success. + \return BAD_FUNC_ARG if key is NULL or no parameter set is + selected. + \return MISSING_KEY if the private key has not been set. + \return BUFFER_E if output is non-NULL and inLen is too small. + + \param [in] key Pointer to a wc_MlDsaKey with the private key. + \param [out] output Buffer that receives the DER encoding, or + NULL to query size. + \param [in] inLen Size of output (ignored when output is NULL). + + \sa wc_MlDsaKey_PrivateKeyDecode + \sa wc_MlDsaKey_PrivateKeyToDer + \sa wc_MlDsaKey_PublicKeyToDer +*/ +int wc_MlDsaKey_KeyToDer(wc_MlDsaKey* key, byte* output, word32 inLen); + +/*! + \ingroup ML_DSA + + \brief Encodes the ML-DSA private key to DER. Per FIPS 204 the + private key encoding includes the public component, so this + function is currently an alias of wc_MlDsaKey_KeyToDer() kept for + API parity with other algorithms. + + \return Size of the encoded DER in bytes on success. + \return Inherited error codes from wc_MlDsaKey_KeyToDer(). + + \param [in] key Pointer to a wc_MlDsaKey with the private key. + \param [out] output Buffer that receives the DER encoding, or + NULL to query size. + \param [in] inLen Size of output (ignored when output is NULL). + + \sa wc_MlDsaKey_KeyToDer + \sa wc_MlDsaKey_PrivateKeyDecode +*/ +int wc_MlDsaKey_PrivateKeyToDer(wc_MlDsaKey* key, byte* output, + word32 inLen); diff --git a/doc/dox_comments/header_files/wc_mlkem.h b/doc/dox_comments/header_files/wc_mlkem.h new file mode 100644 index 0000000000..08aac84050 --- /dev/null +++ b/doc/dox_comments/header_files/wc_mlkem.h @@ -0,0 +1,472 @@ +/*! + \ingroup ML_KEM + + \brief Allocates and initializes a new MlKemKey on the heap. The + returned pointer must be released with wc_MlKemKey_Delete(). + + ML-KEM (FIPS 203) is a quantum-resistant key encapsulation + mechanism. The type parameter selects the variant: WC_ML_KEM_512 + (NIST security level 1), WC_ML_KEM_768 (level 3) or + WC_ML_KEM_1024 (level 5). + + \return Pointer to a freshly allocated MlKemKey on success. + \return NULL on allocation failure or if type is invalid. + + \param [in] type ML-KEM variant: WC_ML_KEM_512, WC_ML_KEM_768 or + WC_ML_KEM_1024. + \param [in] heap Heap hint for dynamic memory allocation. May be + NULL. + \param [in] devId Device identifier for hardware crypto callbacks. + Use INVALID_DEVID for software-only. + + _Example_ + \code + MlKemKey* key = wc_MlKemKey_New(WC_ML_KEM_768, NULL, + INVALID_DEVID); + if (key == NULL) { + // allocation failed + } + // ... use key ... + wc_MlKemKey_Delete(key, &key); + \endcode + + \sa wc_MlKemKey_Delete + \sa wc_MlKemKey_Init +*/ +MlKemKey* wc_MlKemKey_New(int type, void* heap, int devId); + +/*! + \ingroup ML_KEM + + \brief Frees and zeros a heap-allocated MlKemKey previously + returned by wc_MlKemKey_New(). On success the caller's pointer + variable is set to NULL via key_p when key_p is not NULL. + + \return 0 on success. + \return BAD_FUNC_ARG if key is NULL. + + \param [in,out] key The MlKemKey to free. + \param [in,out] key_p Optional address of the caller's pointer + variable; when not NULL, it is set to NULL on success. + + \sa wc_MlKemKey_New +*/ +int wc_MlKemKey_Delete(MlKemKey* key, MlKemKey** key_p); + +/*! + \ingroup ML_KEM + + \brief Initializes an MlKemKey object in place. The type parameter + selects the ML-KEM variant and must be one of WC_ML_KEM_512, + WC_ML_KEM_768 or WC_ML_KEM_1024. + + \return 0 on success. + \return BAD_FUNC_ARG if key is NULL or type is invalid. + \return NOT_COMPILED_IN if type names a variant that was disabled + at build time. + + \param [in,out] key Pointer to the MlKemKey to initialize. + \param [in] type ML-KEM variant: WC_ML_KEM_512, WC_ML_KEM_768 or + WC_ML_KEM_1024. + \param [in] heap Heap hint for dynamic memory allocation. May be + NULL. + \param [in] devId Device identifier for hardware crypto callbacks. + + _Example_ + \code + MlKemKey key; + int ret; + + ret = wc_MlKemKey_Init(&key, WC_ML_KEM_768, NULL, INVALID_DEVID); + if (ret != 0) { + // error initializing key + } + // ... use key ... + wc_MlKemKey_Free(&key); + \endcode + + \sa wc_MlKemKey_Free + \sa wc_MlKemKey_MakeKey +*/ +int wc_MlKemKey_Init(MlKemKey* key, int type, void* heap, int devId); + +/*! + \ingroup ML_KEM + + \brief Releases resources held by an MlKemKey. After this call + the object must be re-initialized with wc_MlKemKey_Init() before + it can be used again. Safe to call with a NULL pointer. + + \return 0 on success, including when key is NULL. + + \param [in,out] key Pointer to the MlKemKey to free. + + \sa wc_MlKemKey_Init +*/ +int wc_MlKemKey_Free(MlKemKey* key); + +/*! + \ingroup ML_KEM + + \brief Initializes an MlKemKey with a device-side key identifier. + Equivalent to wc_MlKemKey_Init() but also stashes a binary id that + a crypto callback can use to look up the underlying key material + on the device. Only available when wolfSSL is built with + WOLF_PRIVATE_KEY_ID. + + The id is copied into the key object; the caller may free its + buffer immediately after this call returns. + + \return 0 on success. + \return BAD_FUNC_ARG if key is NULL, if id is NULL while len is + non-zero, or if type is invalid. + \return BUFFER_E if len is negative or exceeds MLKEM_MAX_ID_LEN. + + \param [in,out] key Pointer to the MlKemKey to initialize. + \param [in] type ML-KEM variant identifier. + \param [in] id Pointer to the device-side key identifier bytes. + May be NULL when len is 0. + \param [in] len Number of bytes in id. Must be in the range + [0, MLKEM_MAX_ID_LEN]. + \param [in] heap Heap hint for dynamic memory allocation. + \param [in] devId Device identifier for the crypto callback. + + \sa wc_MlKemKey_Init + \sa wc_MlKemKey_Init_Label + \sa wc_MlKemKey_Free +*/ +int wc_MlKemKey_Init_Id(MlKemKey* key, int type, const unsigned char* id, + int len, void* heap, int devId); + +/*! + \ingroup ML_KEM + + \brief Initializes an MlKemKey with a device-side key label. + Equivalent to wc_MlKemKey_Init() but also stashes a label string + that a crypto callback can use to look up the underlying key + material on the device. Only available when wolfSSL is built with + WOLF_PRIVATE_KEY_ID. + + \return 0 on success. + \return BAD_FUNC_ARG if key or label is NULL or type is invalid. + + \param [in,out] key Pointer to the MlKemKey to initialize. + \param [in] type ML-KEM variant identifier. + \param [in] label NUL-terminated device-side key label. + \param [in] heap Heap hint for dynamic memory allocation. + \param [in] devId Device identifier for the crypto callback. + + \sa wc_MlKemKey_Init + \sa wc_MlKemKey_Init_Id + \sa wc_MlKemKey_Free +*/ +int wc_MlKemKey_Init_Label(MlKemKey* key, int type, const char* label, + void* heap, int devId); + +/*! + \ingroup ML_KEM + + \brief Generates a new ML-KEM key pair using the provided RNG. + Both the public and private components are populated on success. + + \return 0 on success. + \return BAD_FUNC_ARG if key or rng is NULL. + \return MEMORY_E on allocation failure. + + \param [in,out] key Pointer to an initialized MlKemKey. + \param [in] rng Pointer to an initialized WC_RNG. + + _Example_ + \code + MlKemKey key; + WC_RNG rng; + + wc_MlKemKey_Init(&key, WC_ML_KEM_768, NULL, INVALID_DEVID); + wc_InitRng(&rng); + + if (wc_MlKemKey_MakeKey(&key, &rng) != 0) { + // error generating key pair + } + \endcode + + \sa wc_MlKemKey_MakeKeyWithRandom + \sa wc_MlKemKey_Encapsulate + \sa wc_MlKemKey_Decapsulate +*/ +int wc_MlKemKey_MakeKey(MlKemKey* key, WC_RNG* rng); + +/*! + \ingroup ML_KEM + + \brief Deterministic key generation: produces an ML-KEM key pair + from the supplied 64 bytes of randomness instead of an RNG. Useful + for known-answer tests and for applications that derive key + randomness from another secret. + + \return 0 on success. + \return BAD_FUNC_ARG if any required pointer is NULL or len is + not 64. + + \param [in,out] key Pointer to an initialized MlKemKey. + \param [in] rand Pointer to a buffer of randomness. + \param [in] len Length of rand in bytes; must be 64. + + \sa wc_MlKemKey_MakeKey +*/ +int wc_MlKemKey_MakeKeyWithRandom(MlKemKey* key, const unsigned char* rand, + int len); + +/*! + \ingroup ML_KEM + + \brief Returns the ciphertext size in bytes for the variant + selected on this key. + + \return 0 on success. + \return BAD_FUNC_ARG if key or len is NULL. + + \param [in] key Pointer to an initialized MlKemKey. + \param [out] len Receives the ciphertext size in bytes. + + \sa wc_MlKemKey_SharedSecretSize + \sa wc_MlKemKey_Encapsulate +*/ +int wc_MlKemKey_CipherTextSize(MlKemKey* key, word32* len); + +/*! + \ingroup ML_KEM + + \brief Returns the shared-secret size in bytes for ML-KEM. The + value is the same (32 bytes) across all parameter sets but is + queried programmatically for symmetry with + wc_MlKemKey_CipherTextSize(). + + \return 0 on success. + \return BAD_FUNC_ARG if key or len is NULL. + + \param [in] key Pointer to an initialized MlKemKey. + \param [out] len Receives the shared-secret size in bytes. + + \sa wc_MlKemKey_CipherTextSize +*/ +int wc_MlKemKey_SharedSecretSize(MlKemKey* key, word32* len); + +/*! + \ingroup ML_KEM + + \brief Encapsulates a fresh shared secret against the public key + held in key. Produces a ciphertext that the holder of the + corresponding private key can pass to wc_MlKemKey_Decapsulate() to + recover the same shared secret. + + The ct buffer must be at least wc_MlKemKey_CipherTextSize() bytes + and ss must be at least wc_MlKemKey_SharedSecretSize() bytes. + + \return 0 on success. + \return BAD_FUNC_ARG if any required pointer is NULL. + \return BAD_STATE_E if the public key has not been set. + \return NOT_COMPILED_IN if wolfSSL was built with WC_NO_RNG. + \return MEMORY_E on allocation failure inside the encapsulation + routine. + + \param [in,out] key Pointer to an MlKemKey containing a public key. + \param [out] ct Buffer that receives the ciphertext. + \param [out] ss Buffer that receives the 32-byte shared secret. + \param [in] rng Pointer to an initialized WC_RNG. + + _Example_ + \code + MlKemKey key; + unsigned char ct[WC_ML_KEM_768_CIPHER_TEXT_SIZE]; + unsigned char ss[WC_ML_KEM_SS_SZ]; + + // ... key holds the recipient's public key ... + if (wc_MlKemKey_Encapsulate(&key, ct, ss, &rng) != 0) { + // error during encapsulation + } + // Send ct to the holder of the matching private key. + \endcode + + \sa wc_MlKemKey_EncapsulateWithRandom + \sa wc_MlKemKey_Decapsulate +*/ +int wc_MlKemKey_Encapsulate(MlKemKey* key, unsigned char* ct, + unsigned char* ss, WC_RNG* rng); + +/*! + \ingroup ML_KEM + + \brief Deterministic variant of wc_MlKemKey_Encapsulate(). Uses + the supplied 32 bytes of randomness instead of consuming output + from an RNG. + + \return 0 on success. + \return BAD_FUNC_ARG if any required pointer is NULL or len is + not 32. + + \param [in,out] key Pointer to an MlKemKey containing a public key. + \param [out] ct Buffer that receives the ciphertext. + \param [out] ss Buffer that receives the 32-byte shared secret. + \param [in] rand Buffer of randomness. + \param [in] len Length of rand in bytes; must be 32. + + \sa wc_MlKemKey_Encapsulate +*/ +int wc_MlKemKey_EncapsulateWithRandom(MlKemKey* key, unsigned char* ct, + unsigned char* ss, const unsigned char* rand, int len); + +/*! + \ingroup ML_KEM + + \brief Decapsulates a ciphertext using the private key held in key + and recovers the shared secret produced by + wc_MlKemKey_Encapsulate(). ML-KEM decapsulation is constant time + and includes an implicit-rejection check on malformed ciphertexts + (an attacker cannot learn the validity of ct from the runtime). + + The ss buffer must be at least wc_MlKemKey_SharedSecretSize() + bytes and ct must be exactly wc_MlKemKey_CipherTextSize() bytes. + + \return 0 on success (a shared secret was written to ss). + \return BAD_FUNC_ARG if any required pointer is NULL. + \return BAD_STATE_E if the private key has not been set. + \return BUFFER_E if len does not match the expected ciphertext + size for the configured ML-KEM variant. + \return NOT_COMPILED_IN if the key's ML-KEM variant was disabled + at build time. + \return MEMORY_E on allocation failure. + + \param [in,out] key Pointer to an MlKemKey with the private key. + \param [out] ss Buffer that receives the 32-byte shared secret. + \param [in] ct The ciphertext to decapsulate. + \param [in] len Length of ct in bytes. + + \sa wc_MlKemKey_Encapsulate + \sa wc_MlKemKey_CipherTextSize +*/ +int wc_MlKemKey_Decapsulate(MlKemKey* key, unsigned char* ss, + const unsigned char* ct, word32 len); + +/*! + \ingroup ML_KEM + + \brief Decodes a raw ML-KEM private key into key. The variant must + already be selected on the key (typically via wc_MlKemKey_Init() + or wc_MlKemKey_New()) and len must match the private key size for + that variant. + + \return 0 on success. + \return BAD_FUNC_ARG if any required pointer is NULL or len does + not match the expected size. + + \param [in,out] key Pointer to an initialized MlKemKey. + \param [in] in Raw private key bytes. + \param [in] len Length of in in bytes. + + \sa wc_MlKemKey_EncodePrivateKey + \sa wc_MlKemKey_PrivateKeySize +*/ +int wc_MlKemKey_DecodePrivateKey(MlKemKey* key, const unsigned char* in, + word32 len); + +/*! + \ingroup ML_KEM + + \brief Decodes a raw ML-KEM public key into key. The variant must + already be selected on the key and len must match the public key + size for that variant. + + \return 0 on success. + \return BAD_FUNC_ARG if any required pointer is NULL or len does + not match the expected size. + + \param [in,out] key Pointer to an initialized MlKemKey. + \param [in] in Raw public key bytes. + \param [in] len Length of in in bytes. + + \sa wc_MlKemKey_EncodePublicKey + \sa wc_MlKemKey_PublicKeySize +*/ +int wc_MlKemKey_DecodePublicKey(MlKemKey* key, const unsigned char* in, + word32 len); + +/*! + \ingroup ML_KEM + + \brief Returns the encoded private key size in bytes for the + variant selected on this key. + + \return 0 on success. + \return BAD_FUNC_ARG if key or len is NULL. + + \param [in] key Pointer to an initialized MlKemKey. + \param [out] len Receives the private key size in bytes. + + \sa wc_MlKemKey_PublicKeySize +*/ +int wc_MlKemKey_PrivateKeySize(MlKemKey* key, word32* len); + +/*! + \ingroup ML_KEM + + \brief Returns the encoded public key size in bytes for the + variant selected on this key. + + \return 0 on success. + \return BAD_FUNC_ARG if key or len is NULL. + + \param [in] key Pointer to an initialized MlKemKey. + \param [out] len Receives the public key size in bytes. + + \sa wc_MlKemKey_PrivateKeySize +*/ +int wc_MlKemKey_PublicKeySize(MlKemKey* key, word32* len); + +/*! + \ingroup ML_KEM + + \brief Encodes the ML-KEM private key into out. The out buffer + length must be exactly wc_MlKemKey_PrivateKeySize() bytes. + + \return 0 on success. + \return BAD_FUNC_ARG if any required pointer is NULL. + \return BAD_STATE_E if the private and public keys are not both + set on the key object. + \return BUFFER_E if len does not exactly equal the encoded + private key size for the configured ML-KEM variant. + \return NOT_COMPILED_IN if the key's ML-KEM variant was disabled + at build time. + + \param [in] key Pointer to an MlKemKey with a private key. + \param [out] out Buffer that receives the encoded private key. + \param [in] len Length of out in bytes. + + \sa wc_MlKemKey_DecodePrivateKey + \sa wc_MlKemKey_PrivateKeySize +*/ +int wc_MlKemKey_EncodePrivateKey(MlKemKey* key, unsigned char* out, + word32 len); + +/*! + \ingroup ML_KEM + + \brief Encodes the ML-KEM public key into out. The out buffer + length must be exactly wc_MlKemKey_PublicKeySize() bytes. + + \return 0 on success. + \return BAD_FUNC_ARG if any required pointer is NULL. + \return BAD_STATE_E if the public key has not been set. + \return BUFFER_E if len does not exactly equal the encoded public + key size for the configured ML-KEM variant. + \return NOT_COMPILED_IN if the key's ML-KEM variant was disabled + at build time. + + \param [in] key Pointer to an MlKemKey with a public key. + \param [out] out Buffer that receives the encoded public key. + \param [in] len Length of out in bytes. + + \sa wc_MlKemKey_DecodePublicKey + \sa wc_MlKemKey_PublicKeySize +*/ +int wc_MlKemKey_EncodePublicKey(MlKemKey* key, unsigned char* out, + word32 len); diff --git a/doc/dox_comments/header_files/wc_xmss.h b/doc/dox_comments/header_files/wc_xmss.h new file mode 100644 index 0000000000..7af2666ed7 --- /dev/null +++ b/doc/dox_comments/header_files/wc_xmss.h @@ -0,0 +1,530 @@ +/*! + \ingroup XMSS + + \brief Initializes an XmssKey object. Must be called before any + other XMSS/XMSS^MT operation. Use wc_XmssKey_Free() to release + resources when done. + + XMSS (eXtended Merkle Signature Scheme) and its multi-tree + variant XMSS^MT (RFC 8391, NIST SP 800-208) are STATEFUL + hash-based signature schemes: each call to wc_XmssKey_Sign() + consumes a one-time component of the private key, and reusing a + one-time key destroys the security of the scheme. Applications + MUST persist the private key state between sign calls; see + wc_XmssKey_SetWriteCb() and wc_XmssKey_SetReadCb(). + + After init the key is in state WC_XMSS_STATE_INITED. The + parameter set must be selected by name with + wc_XmssKey_SetParamStr() before generating or reloading a key. + + \return 0 on success. + \return BAD_FUNC_ARG if key is NULL. + + \param [in,out] key Pointer to the XmssKey to initialize. + \param [in] heap Heap hint for dynamic memory allocation. May be + NULL. + \param [in] devId Device identifier for hardware crypto callbacks. + Use INVALID_DEVID for software-only. + + _Example_ + \code + XmssKey key; + int ret; + + ret = wc_XmssKey_Init(&key, NULL, INVALID_DEVID); + if (ret != 0) { + // error initializing key + } + wc_XmssKey_SetParamStr(&key, "XMSS-SHA2_10_256"); + // ... use key ... + wc_XmssKey_Free(&key); + \endcode + + \sa wc_XmssKey_Free + \sa wc_XmssKey_SetParamStr + \sa wc_XmssKey_MakeKey +*/ +int wc_XmssKey_Init(XmssKey* key, void* heap, int devId); + +/*! + \ingroup XMSS + + \brief Initializes an XmssKey with a device-side key identifier. + Equivalent to wc_XmssKey_Init() but also stashes a binary id that + a crypto callback can use to look up the underlying key material + on the device. Only available when wolfSSL is built with + WOLF_PRIVATE_KEY_ID. + + The id is copied into the key object; the caller may free its + buffer immediately after this call returns. + + \return 0 on success. + \return BAD_FUNC_ARG if key is NULL, or id is NULL while len > 0. + \return BUFFER_E if len is negative or greater than + XMSS_MAX_ID_LEN. + + \param [in,out] key Pointer to the XmssKey to initialize. + \param [in] id Pointer to the device-side key identifier bytes. + \param [in] len Number of bytes in id; must be in + [0, XMSS_MAX_ID_LEN]. + \param [in] heap Heap hint for dynamic memory allocation. + \param [in] devId Device identifier for the crypto callback. + + \sa wc_XmssKey_Init + \sa wc_XmssKey_InitLabel + \sa wc_XmssKey_Free +*/ +int wc_XmssKey_InitId(XmssKey* key, const unsigned char* id, int len, + void* heap, int devId); + +/*! + \ingroup XMSS + + \brief Initializes an XmssKey with a device-side key label. + Equivalent to wc_XmssKey_Init() but also stashes a label string + that a crypto callback can use to look up the underlying key + material on the device. Only available when wolfSSL is built with + WOLF_PRIVATE_KEY_ID. + + \return 0 on success. + \return BAD_FUNC_ARG if key or label is NULL. + \return BUFFER_E if label is empty or longer than + XMSS_MAX_LABEL_LEN. + + \param [in,out] key Pointer to the XmssKey to initialize. + \param [in] label NUL-terminated device-side key label. + \param [in] heap Heap hint for dynamic memory allocation. + \param [in] devId Device identifier for the crypto callback. + + \sa wc_XmssKey_Init + \sa wc_XmssKey_InitId +*/ +int wc_XmssKey_InitLabel(XmssKey* key, const char* label, void* heap, + int devId); + +/*! + \ingroup XMSS + + \brief Selects an XMSS or XMSS^MT parameter set by its RFC 8391 + name. Accepted names take the form + "XMSS-__" (single-tree) or + "XMSSMT-_/_" (multi-tree), for + example "XMSS-SHA2_10_256" or "XMSSMT-SHA2_20/2_256". The set of + names actually accepted depends on the hash families and tree + heights enabled at build time. + + \return 0 on success. + \return BAD_FUNC_ARG if key or str is NULL, or if the named + parameter set is unknown or not compiled in. + \return BAD_STATE_E if key is not in state WC_XMSS_STATE_INITED. + + \param [in,out] key Pointer to an XmssKey in state + WC_XMSS_STATE_INITED. + \param [in] str Parameter set name (NUL-terminated). + + _Example_ + \code + XmssKey key; + + wc_XmssKey_Init(&key, NULL, INVALID_DEVID); + wc_XmssKey_SetParamStr(&key, "XMSS-SHA2_10_256"); + \endcode + + \sa wc_XmssKey_GetParamStr + \sa wc_XmssKey_MakeKey +*/ +int wc_XmssKey_SetParamStr(XmssKey* key, const char* str); + +/*! + \ingroup XMSS + + \brief Retrieves the parameter set name currently selected on + this key. The returned pointer is a static string and must not be + freed by the caller. + + \return 0 on success. + \return BAD_FUNC_ARG if key or str is NULL, or no parameter set + has been selected. + + \param [in] key Pointer to an XmssKey with a parameter set + selected. + \param [out] str Receives a pointer to a static parameter name + string. + + \sa wc_XmssKey_SetParamStr +*/ +int wc_XmssKey_GetParamStr(const XmssKey* key, const char** str); + +/*! + \ingroup XMSS + + \brief Registers the callback that wolfSSL invokes to persist + updated private key state. Because XMSS/XMSS^MT is stateful, the + application MUST persist the private key after each successful + sign before the signature is released; otherwise a crash or + restart can lead to one-time key reuse and break the scheme. + + The callback returns one of the wc_XmssRc codes; + WC_XMSS_RC_SAVED_TO_NV_MEMORY signals a durable write. + + \return 0 on success. + \return BAD_FUNC_ARG if key or write_cb is NULL. + + \param [in,out] key Pointer to an XmssKey. + \param [in] write_cb Callback invoked to persist the private key. + + \sa wc_XmssKey_SetReadCb + \sa wc_XmssKey_SetContext + \sa wc_XmssKey_Sign +*/ +int wc_XmssKey_SetWriteCb(XmssKey* key, wc_xmss_write_private_key_cb write_cb); + +/*! + \ingroup XMSS + + \brief Registers the callback that wolfSSL invokes to load + persisted private key state. Used by wc_XmssKey_Reload() to bring + a saved key back into memory for further signing. + + \return 0 on success. + \return BAD_FUNC_ARG if key or read_cb is NULL. + + \param [in,out] key Pointer to an XmssKey. + \param [in] read_cb Callback invoked to load the private key. + + \sa wc_XmssKey_SetWriteCb + \sa wc_XmssKey_Reload +*/ +int wc_XmssKey_SetReadCb(XmssKey* key, wc_xmss_read_private_key_cb read_cb); + +/*! + \ingroup XMSS + + \brief Sets the opaque context pointer passed to both the read + and write private-key callbacks. + + \return 0 on success. + \return BAD_FUNC_ARG if key is NULL. + + \param [in,out] key Pointer to an XmssKey. + \param [in] context Application-defined pointer; may be NULL. + + \sa wc_XmssKey_SetReadCb + \sa wc_XmssKey_SetWriteCb +*/ +int wc_XmssKey_SetContext(XmssKey* key, void* context); + +/*! + \ingroup XMSS + + \brief Generates a fresh XMSS/XMSS^MT key pair. The parameter set + must already be selected via wc_XmssKey_SetParamStr() and the + read/write callbacks must be registered. The newly generated + private key is persisted via the write callback before the + function returns; on success the key transitions to state + WC_XMSS_STATE_OK. + + Key generation can be slow for large tree heights; XMSS^MT + variants amortize the cost over multiple smaller trees and + generate noticeably faster than equivalent single-tree XMSS + parameter sets. + + \return 0 on success. + \return BAD_FUNC_ARG if any required pointer is NULL. + \return MEMORY_E on allocation failure. + + \param [in,out] key Pointer to an XmssKey in state + WC_XMSS_STATE_PARMSET with callbacks set. + \param [in] rng Pointer to an initialized WC_RNG. + + _Example_ + \code + XmssKey key; + WC_RNG rng; + + wc_XmssKey_Init(&key, NULL, INVALID_DEVID); + wc_XmssKey_SetParamStr(&key, "XMSS-SHA2_10_256"); + wc_XmssKey_SetWriteCb(&key, my_write_cb); + wc_XmssKey_SetReadCb(&key, my_read_cb); + wc_XmssKey_SetContext(&key, &my_storage); + wc_InitRng(&rng); + + if (wc_XmssKey_MakeKey(&key, &rng) != 0) { + // error generating key + } + \endcode + + \sa wc_XmssKey_Sign + \sa wc_XmssKey_Reload +*/ +int wc_XmssKey_MakeKey(XmssKey* key, WC_RNG* rng); + +/*! + \ingroup XMSS + + \brief Reloads a previously generated XMSS/XMSS^MT private key + from persistent storage using the registered read callback, + restoring the key to a state where it can sign further messages. + On success the key is in state WC_XMSS_STATE_OK. + + The same parameter set selected at key-generation time must be + reapplied with wc_XmssKey_SetParamStr() before calling Reload. + + \return 0 on success. + \return BAD_FUNC_ARG if any required pointer is NULL. + \return WC_XMSS_RC_* mapped error if the read callback fails. + + \param [in,out] key Pointer to an XmssKey with parameters and + read callback set. + + \sa wc_XmssKey_MakeKey + \sa wc_XmssKey_SetReadCb +*/ +int wc_XmssKey_Reload(XmssKey* key); + +/*! + \ingroup XMSS + + \brief Returns the size in bytes of the encoded private key for + the parameter set selected on this key. + + \return 0 on success. + \return BAD_FUNC_ARG if key or len is NULL. + + \param [in] key Pointer to an XmssKey with parameters set. + \param [out] len Receives the private key size in bytes. + + \sa wc_XmssKey_GetPubLen + \sa wc_XmssKey_GetSigLen +*/ +int wc_XmssKey_GetPrivLen(const XmssKey* key, word32* len); + +/*! + \ingroup XMSS + + \brief Returns the size in bytes of the XMSS/XMSS^MT public key + for the parameter set selected on this key. + + \return 0 on success. + \return BAD_FUNC_ARG if key or len is NULL. + + \param [in] key Pointer to an XmssKey with parameters set. + \param [out] len Receives the public key size in bytes. + + \sa wc_XmssKey_ExportPubRaw +*/ +int wc_XmssKey_GetPubLen(const XmssKey* key, word32* len); + +/*! + \ingroup XMSS + + \brief Returns the signature size in bytes for the parameter set + selected on this key. + + \return 0 on success. + \return BAD_FUNC_ARG if key or len is NULL. + + \param [in] key Pointer to an XmssKey with parameters set. + \param [out] len Receives the signature size in bytes. + + \sa wc_XmssKey_Sign +*/ +int wc_XmssKey_GetSigLen(const XmssKey* key, word32* len); + +/*! + \ingroup XMSS + + \brief Signs msg with the XMSS/XMSS^MT private key in key. On + entry *sigSz is the size of the sig buffer; on success it is + updated to the bytes written. + + Each successful sign call consumes a one-time component of the + private key. The updated key state is persisted via the + registered write callback BEFORE the new signature is returned to + the caller. If the write callback fails the sign call fails and + the signature is not released. When the supply of one-time keys + is exhausted the key transitions to state WC_XMSS_STATE_NOSIGS + and further sign attempts fail -- query wc_XmssKey_SigsLeft() to + detect this condition in advance. + + \return 0 on success. + \return BAD_FUNC_ARG if any required pointer is NULL. + \return BUFFER_E if *sigSz is smaller than the signature size. + \return Negative error if all one-time keys have been used. + + \param [in,out] key Pointer to an XmssKey in state + WC_XMSS_STATE_OK. + \param [out] sig Buffer that receives the signature. + \param [in,out] sigSz In: size of sig. Out: bytes written. + \param [in] msg Message to sign. + \param [in] msgSz Length of msg in bytes. + + \sa wc_XmssKey_Verify + \sa wc_XmssKey_SigsLeft + \sa wc_XmssKey_SetWriteCb +*/ +int wc_XmssKey_Sign(XmssKey* key, byte* sig, word32* sigSz, const byte* msg, + int msgSz); + +/*! + \ingroup XMSS + + \brief Returns the number of one-time signatures still available + from this key. When the count reaches zero the key can no longer + sign and should be retired. + + \return Non-negative number of remaining signatures on success. + \return Negative error code on failure (e.g. BAD_FUNC_ARG if key + is NULL). + + \param [in,out] key Pointer to an XmssKey in state + WC_XMSS_STATE_OK. + + \sa wc_XmssKey_Sign +*/ +int wc_XmssKey_SigsLeft(XmssKey* key); + +/*! + \ingroup XMSS + + \brief Releases resources held by an XmssKey. Safe to call with a + NULL pointer. After this call the key is in state + WC_XMSS_STATE_FREED and must be re-initialized before reuse. + + \param [in,out] key Pointer to the XmssKey to free. + + \sa wc_XmssKey_Init +*/ +void wc_XmssKey_Free(XmssKey* key); + +/*! + \ingroup XMSS + + \brief Copies the public part of keySrc into keyDst. The + destination key inherits the same parameter set and may be used + for verification; it does not carry the private key state and + cannot sign. Useful for handing a verifier the minimal data it + needs. + + \return 0 on success. + \return BAD_FUNC_ARG if keyDst or keySrc is NULL. + + \param [in,out] keyDst Pointer to an initialized destination + XmssKey. + \param [in] keySrc Pointer to an XmssKey with the public key. + + \sa wc_XmssKey_ExportPub_ex + \sa wc_XmssKey_ExportPubRaw +*/ +int wc_XmssKey_ExportPub(XmssKey* keyDst, const XmssKey* keySrc); + +/*! + \ingroup XMSS + + \brief Like wc_XmssKey_ExportPub() but the destination key is + initialized fresh with the supplied heap and devId. + + \return 0 on success. + \return BAD_FUNC_ARG if keyDst or keySrc is NULL. + + \param [in,out] keyDst Pointer to an XmssKey to populate. + \param [in] keySrc Pointer to an XmssKey with the public key. + \param [in] heap Heap hint for keyDst. + \param [in] devId Device identifier for keyDst. + + \sa wc_XmssKey_ExportPub +*/ +int wc_XmssKey_ExportPub_ex(XmssKey* keyDst, const XmssKey* keySrc, + void* heap, int devId); + +/*! + \ingroup XMSS + + \brief Exports the XMSS/XMSS^MT public key as a raw byte string. + On entry *outLen is the size of out; on success it is updated to + the bytes written. + + \return 0 on success. + \return BAD_FUNC_ARG if any required pointer is NULL. + \return BUFFER_E if *outLen is smaller than the public key size. + + \param [in] key Pointer to an XmssKey. + \param [out] out Buffer that receives the public key. + \param [in,out] outLen In: size of out. Out: bytes written. + + \sa wc_XmssKey_ImportPubRaw + \sa wc_XmssKey_GetPubLen +*/ +int wc_XmssKey_ExportPubRaw(const XmssKey* key, byte* out, word32* outLen); + +/*! + \ingroup XMSS + + \brief Imports a raw XMSS public key into key. The key must be in + state WC_XMSS_STATE_INITED and the parameter set must already be + selected (the raw encoding does NOT carry the parameter set, so + the caller must apply it via wc_XmssKey_SetParamStr() first). On + success the key transitions to state WC_XMSS_STATE_VERIFYONLY. + + \return 0 on success. + \return BAD_FUNC_ARG if any required pointer is NULL. + \return BUFFER_E if inLen does not match the expected public key + size. + + \param [in,out] key Pointer to an XmssKey with a parameter set. + \param [in] in Raw public key bytes. + \param [in] inLen Length of in in bytes. + + \sa wc_XmssKey_ImportPubRaw_ex + \sa wc_XmssKey_ExportPubRaw + \sa wc_XmssKey_Verify +*/ +int wc_XmssKey_ImportPubRaw(XmssKey* key, const byte* in, word32 inLen); + +/*! + \ingroup XMSS + + \brief Like wc_XmssKey_ImportPubRaw() but explicitly declares + whether the encoded key is single-tree XMSS or multi-tree XMSS^MT + (pass non-zero for XMSS^MT, zero for XMSS). + + \return 0 on success. + \return BAD_FUNC_ARG if any required pointer is NULL. + \return BUFFER_E if inLen does not match the expected public key + size. + + \param [in,out] key Pointer to an XmssKey with a parameter set. + \param [in] in Raw public key bytes. + \param [in] inLen Length of in in bytes. + \param [in] is_xmssmt Non-zero if the key is XMSS^MT, zero if + plain XMSS. + + \sa wc_XmssKey_ImportPubRaw +*/ +int wc_XmssKey_ImportPubRaw_ex(XmssKey* key, const byte* in, word32 inLen, + int is_xmssmt); + +/*! + \ingroup XMSS + + \brief Verifies an XMSS/XMSS^MT signature against msg using the + public key held in key. The function returns 0 only when the + signature is valid; any other value indicates the signature was + rejected. + + \return 0 on a valid signature. + \return BAD_FUNC_ARG if any required pointer is NULL. + \return SIG_VERIFY_E (or similar) if the signature is invalid or + malformed. + + \param [in,out] key Pointer to an XmssKey with the public key. + \param [in] sig Signature bytes to verify. + \param [in] sigSz Length of sig in bytes. + \param [in] msg Message that was signed. + \param [in] msgSz Length of msg in bytes. + + \sa wc_XmssKey_Sign + \sa wc_XmssKey_ImportPubRaw +*/ +int wc_XmssKey_Verify(XmssKey* key, const byte* sig, word32 sigSz, + const byte* msg, int msgSz); diff --git a/examples/configs/user_settings_arduino.h b/examples/configs/user_settings_arduino.h index 65b8ebcc64..2639bfc584 100644 --- a/examples/configs/user_settings_arduino.h +++ b/examples/configs/user_settings_arduino.h @@ -186,6 +186,11 @@ * Use the smaller ECC-256 built-in cert set to keep the examples fitting. */ #define USE_CERT_BUFFERS_256 + + /* ECC-256 certs alone no longer fit. Drop the error reason string + * tables to reclaim flash; only wolfSSL_ERR_*_string() text is lost, + * TLS/crypto and DEBUG_WOLFSSL traces are unchanged. */ + #define NO_ERROR_STRINGS #elif defined (__AVR__) || defined(__AVR_ARCH__) || defined(__MEGAAVR__) /* Do not enable TLS on platforms without networking */ diff --git a/linuxkm/module_hooks.c b/linuxkm/module_hooks.c index e5b94ba278..88a1e97d8d 100644 --- a/linuxkm/module_hooks.c +++ b/linuxkm/module_hooks.c @@ -1325,13 +1325,11 @@ size_t wc_linuxkm_malloc_usable_size(void *ptr) #ifdef CONFIG_HAVE_KPROBES static typeof(find_vm_area) *find_vm_area_ptr = NULL; if (find_vm_area_ptr == NULL) { - if (! wc_linuxkm_can_block()) - return 0; find_vm_area_ptr = my_kallsyms_lookup_name("find_vm_area"); + if (find_vm_area_ptr == NULL) + return 0; } - if (find_vm_area_ptr == NULL) - return 0; - else if (ptr == NULL) + if (ptr == NULL) return 0; else { struct vm_struct *vm = find_vm_area_ptr(ptr); @@ -1950,6 +1948,10 @@ static WC_MAYBE_UNUSED void *my_kallsyms_lookup_name(const char *name) { if (! kallsyms_lookup_name_ptr) { int ret; + + if (! wc_linuxkm_can_block()) + return NULL; + kallsyms_lookup_name_kp.addr = NULL; if ((ret = register_kprobe(&kallsyms_lookup_name_kp)) != 0) { #ifdef WOLFSSL_LINUXKM_VERBOSE_DEBUG diff --git a/scripts/ocsp-stapling.test b/scripts/ocsp-stapling.test index 55ead3e27f..bd62868cf6 100755 --- a/scripts/ocsp-stapling.test +++ b/scripts/ocsp-stapling.test @@ -363,8 +363,8 @@ fi # purposes! openssl ocsp -port "$port2" -nmin 1 \ -index certs/ocsp/index-intermediate1-ca-issued-certs.txt \ - -rsigner certs/ocsp/ocsp-responder-cert.pem \ - -rkey certs/ocsp/ocsp-responder-key.pem \ + -rsigner certs/ocsp/ocsp-responder-int1-cert.pem \ + -rkey certs/ocsp/ocsp-responder-int1-key.pem \ -CA certs/ocsp/intermediate1-ca-cert.pem \ "$@" & diff --git a/scripts/ocsp-stapling2.test b/scripts/ocsp-stapling2.test index b3808e48e1..c79dcae279 100755 --- a/scripts/ocsp-stapling2.test +++ b/scripts/ocsp-stapling2.test @@ -335,8 +335,8 @@ openssl ocsp -port "$port1" -nmin 1 \ # purposes! openssl ocsp -port "$port2" -nmin 1 \ -index certs/ocsp/index-intermediate2-ca-issued-certs.txt \ - -rsigner certs/ocsp/ocsp-responder-cert.pem \ - -rkey certs/ocsp/ocsp-responder-key.pem \ + -rsigner certs/ocsp/intermediate2-ca-cert.pem \ + -rkey certs/ocsp/intermediate2-ca-key.pem \ -CA certs/ocsp/intermediate2-ca-cert.pem \ "$@" \ & @@ -346,8 +346,8 @@ openssl ocsp -port "$port2" -nmin 1 \ # purposes! openssl ocsp -port "$port3" -nmin 1 \ -index certs/ocsp/index-intermediate3-ca-issued-certs.txt \ - -rsigner certs/ocsp/ocsp-responder-cert.pem \ - -rkey certs/ocsp/ocsp-responder-key.pem \ + -rsigner certs/ocsp/intermediate3-ca-cert.pem \ + -rkey certs/ocsp/intermediate3-ca-key.pem \ -CA certs/ocsp/intermediate3-ca-cert.pem \ "$@" \ & diff --git a/scripts/ocsp-stapling_tls13multi.test b/scripts/ocsp-stapling_tls13multi.test index 4ae44cfc67..ce49ba13c7 100755 --- a/scripts/ocsp-stapling_tls13multi.test +++ b/scripts/ocsp-stapling_tls13multi.test @@ -353,8 +353,8 @@ openssl ocsp -port "$port1" -nmin 1 \ # purposes! openssl ocsp -port "$port2" -nmin 1 \ -index certs/ocsp/index-intermediate2-ca-issued-certs.txt \ - -rsigner certs/ocsp/ocsp-responder-cert.pem \ - -rkey certs/ocsp/ocsp-responder-key.pem \ + -rsigner certs/ocsp/intermediate2-ca-cert.pem \ + -rkey certs/ocsp/intermediate2-ca-key.pem \ -CA certs/ocsp/intermediate2-ca-cert.pem \ "$@" \ & @@ -364,8 +364,8 @@ openssl ocsp -port "$port2" -nmin 1 \ # purposes! openssl ocsp -port "$port3" -nmin 1 \ -index certs/ocsp/index-intermediate3-ca-issued-certs.txt \ - -rsigner certs/ocsp/ocsp-responder-cert.pem \ - -rkey certs/ocsp/ocsp-responder-key.pem \ + -rsigner certs/ocsp/intermediate3-ca-cert.pem \ + -rkey certs/ocsp/intermediate3-ca-key.pem \ -CA certs/ocsp/intermediate3-ca-cert.pem \ "$@" \ & diff --git a/src/crl.c b/src/crl.c index 3adc15889f..ed32de3f36 100644 --- a/src/crl.c +++ b/src/crl.c @@ -849,7 +849,7 @@ int BufferLoadCRL(WOLFSSL_CRL* crl, const byte* buff, long sz, int type, WOLFSSL_ENTER("BufferLoadCRL"); - if (crl == NULL || buff == NULL || sz == 0) + if (crl == NULL || buff == NULL || sz <= 0) return BAD_FUNC_ARG; if (type == WOLFSSL_FILETYPE_PEM) { @@ -1175,7 +1175,7 @@ int GetCRLInfo(WOLFSSL_CRL* crl, CrlInfo* info, const byte* buff, WOLFSSL_ENTER("GetCRLInfo"); - if (crl == NULL || info == NULL || buff == NULL || sz == 0) + if (crl == NULL || info == NULL || buff == NULL || sz <= 0) return BAD_FUNC_ARG; if (type == WOLFSSL_FILETYPE_PEM) { diff --git a/src/dtls.c b/src/dtls.c index ef8a5f9ef7..61929cd7a8 100644 --- a/src/dtls.c +++ b/src/dtls.c @@ -1317,6 +1317,14 @@ int TLSX_ConnectionID_Parse(WOLFSSL* ssl, const byte* input, word16 length, XMEMCPY(id->id, input + OPAQUE8_LEN, cidSz); id->length = cidSz; info->tx = id; + /* Invalidate the cached AEAD record overhead because the TX CID + * changes record framing. Today this only fires during the initial + * extension exchange (before the cache can be populated). When + * mid-connection CID change is added (DTLS 1.3), add a regression + * test that primes the cache, changes the CID, and re-asserts that + * wolfssl_local_GetRecordSize() agrees with BuildMessage(sizeOnly=1) + * after the change. */ + ssl->recordSzOverhead = 0; } info->negotiated = 1; diff --git a/src/dtls13.c b/src/dtls13.c index 995d144119..0de419def8 100644 --- a/src/dtls13.c +++ b/src/dtls13.c @@ -2369,7 +2369,6 @@ static Dtls13Epoch* Dtls13NewEpochSlot(WOLFSSL* ssl) w64wrapper oldestNumber; int i; - /* FIXME: add max function */ oldestNumber = w64From32((word32)-1, (word32)-1); oldest = NULL; @@ -2380,8 +2379,10 @@ static Dtls13Epoch* Dtls13NewEpochSlot(WOLFSSL* ssl) if (!w64Equal(e->epochNumber, ssl->dtls13Epoch) && !w64Equal(e->epochNumber, ssl->dtls13PeerEpoch) && - w64LT(e->epochNumber, oldestNumber)) + w64LT(e->epochNumber, oldestNumber)) { oldest = e; + oldestNumber = e->epochNumber; + } } if (oldest == NULL) @@ -2720,17 +2721,27 @@ static int Dtls13RtxIsTrackedByRn(const Dtls13RtxRecord* r, w64wrapper epoch, static int Dtls13KeyUpdateAckReceived(WOLFSSL* ssl) { int ret; + /* Validate on a local copy so ssl->dtls13Epoch is left untouched when a + * check fails. */ + w64wrapper newEpoch = ssl->dtls13Epoch; ret = DeriveTls13Keys(ssl, update_traffic_key, ENCRYPT_SIDE_ONLY, 1); if (ret != 0) return ret; - w64Increment(&ssl->dtls13Epoch); + w64Increment(&newEpoch); /* Epoch wrapped up */ - if (w64IsZero(ssl->dtls13Epoch)) + if (w64IsZero(newEpoch)) return BAD_STATE_E; + /* RFC 9147 Section 4.2.1: the epoch must not exceed 2^48-1. */ + if (w64GT(newEpoch, + w64From32(DTLS13_EPOCH_MAX_HI32, DTLS13_EPOCH_MAX_LO32))) + return BAD_STATE_E; + + ssl->dtls13Epoch = newEpoch; + return Dtls13SetEpochKeys(ssl, ssl->dtls13Epoch, ENCRYPT_SIDE_ONLY); } diff --git a/src/include.am b/src/include.am index df6d59c8f7..4b80e149ba 100644 --- a/src/include.am +++ b/src/include.am @@ -21,6 +21,8 @@ EXTRA_DIST += src/pk_rsa.c EXTRA_DIST += src/pk_ec.c EXTRA_DIST += src/ssl_api_cert.c EXTRA_DIST += src/ssl_api_crl_ocsp.c +EXTRA_DIST += src/ssl_api_dtls.c +EXTRA_DIST += src/ssl_api_ext.c EXTRA_DIST += src/ssl_api_pk.c EXTRA_DIST += src/ssl_asn1.c EXTRA_DIST += src/ssl_bn.c diff --git a/src/internal.c b/src/internal.c index 31fd94354d..4237d42b89 100644 --- a/src/internal.c +++ b/src/internal.c @@ -535,6 +535,12 @@ void wolfssl_priv_der_unblind_free(DerBuffer* key) #define SSC_TLS13_EES "EARLY_EXPORTER_SECRET" /* Label string for exporter secret. */ #define SSC_TLS13_ES "EXPORTER_SECRET" +#ifdef HAVE_ECH + /* Label string for ECH KEM shared secret. */ + #define SSC_TLS13_ECH_S "ECH_SECRET" + /* Label string for ECHConfig used to construct ECH. */ + #define SSC_TLS13_ECH_C "ECH_CONFIG" +#endif /* * This function builds up string for key-logging then call user's @@ -594,6 +600,18 @@ void wolfssl_priv_der_unblind_free(DerBuffer* key) label = SSC_TLS13_ES; break; +#ifdef HAVE_ECH + case ECH_SECRET: + labelSz = sizeof(SSC_TLS13_ECH_S); + label = SSC_TLS13_ECH_S; + break; + + case ECH_CONFIG: + labelSz = sizeof(SSC_TLS13_ECH_C); + label = SSC_TLS13_ECH_C; + break; +#endif + default: return BAD_FUNC_ARG; } @@ -3282,6 +3300,7 @@ static void FreeCiphersSide(Ciphers *cipher, void* heap) cipher->aria = NULL; #endif #ifdef HAVE_CAMELLIA + wc_CamelliaFree(cipher->cam); XFREE(cipher->cam, heap, DYNAMIC_TYPE_CIPHER); cipher->cam = NULL; #endif @@ -7329,6 +7348,9 @@ int SetSSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup) #endif #else if (ctx->privateKey != NULL) { + if (ssl->buffers.key != NULL) { + FreeDer(&ssl->buffers.key); + } ret = AllocCopyDer(&ssl->buffers.key, ctx->privateKey->buffer, ctx->privateKey->length, ctx->privateKey->type, ctx->privateKey->heap); @@ -14227,8 +14249,10 @@ int CopyDecodedToX509(WOLFSSL_X509* x509, DecodedCert* dCert) #endif } - if (dCert->signature != NULL && dCert->sigLength != 0 && - dCert->sigLength <= MAX_ENCODED_SIG_SZ) { + /* Store a copy of the signature for later retrieval. The buffer is sized + * to the exact parsed length (itself bounded by the cert DER), so no fixed + * ceiling is applied -- a ceiling would drop large LMS/XMSS signatures. */ + if (dCert->signature != NULL && dCert->sigLength != 0) { x509->sig.buffer = (byte*)XMALLOC( dCert->sigLength, x509->heap, DYNAMIC_TYPE_SIGNATURE); if (x509->sig.buffer == NULL) { @@ -14572,9 +14596,9 @@ int CopyDecodedAcertToX509(WOLFSSL_X509_ACERT* x509, DecodedAcert* dAcert) CopyDateToASN1_TIME(dAcert->afterDate, dAcert->afterDateLen, &x509->notAfter); - /* Copy the signature. */ - if (dAcert->signature != NULL && dAcert->sigLength != 0 && - dAcert->sigLength <= MAX_ENCODED_SIG_SZ) { + /* Copy the signature. Sized to the exact parsed length (bounded by the + * cert DER); no fixed ceiling, so large LMS/XMSS signatures are kept. */ + if (dAcert->signature != NULL && dAcert->sigLength != 0) { x509->sig.buffer = (byte*)XMALLOC( dAcert->sigLength, x509->heap, DYNAMIC_TYPE_SIGNATURE); if (x509->sig.buffer == NULL) { @@ -18797,7 +18821,7 @@ int DoHandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, if (ssl->options.handShakeState == HANDSHAKE_DONE && type == client_hello && ssl->options.side == WOLFSSL_SERVER_END) { WOLFSSL_MSG("Renegotiation request rejected"); - SendAlert(ssl, alert_fatal, no_renegotiation); + SendAlert(ssl, alert_warning, no_renegotiation); WOLFSSL_ERROR_VERBOSE(SECURE_RENEGOTIATION_E); return SECURE_RENEGOTIATION_E; } @@ -22468,6 +22492,9 @@ static int DoAlert(WOLFSSL* ssl, byte* input, word32* inOutIdx, int* type) byte level; byte code; word32 dataSz = (word32)ssl->curSize; +#ifdef WOLFSSL_TLS13_IGNORE_PT_ALERT_ON_ENC + int ignorePtAlert; +#endif #if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA) if (ssl->hsInfoOn) @@ -22496,9 +22523,19 @@ static int DoAlert(WOLFSSL* ssl, byte* input, word32* inOutIdx, int* type) code = input[(*inOutIdx)++]; *type = code; #ifdef WOLFSSL_TLS13_IGNORE_PT_ALERT_ON_ENC - /* Don't process alert when TLS 1.3 and encrypting but plaintext alert. */ - if (!IsAtLeastTLSv1_3(ssl->version) || !IsEncryptionOn(ssl, 0) || - ssl->keys.decryptedCur) + /* A plaintext alert received in TLS 1.3 once we are decrypting is only + * tolerated while still in the handshake and before the peer has sent an + * encrypted message. The peer sequence number is reset to zero each time + * decryption keys are installed and incremented for each record decrypted, + * so a non-zero value means the peer has sent an encrypted message and a + * plaintext alert is treated as an error. */ + ignorePtAlert = IsAtLeastTLSv1_3(ssl->version) && IsEncryptionOn(ssl, 0) && + !ssl->keys.decryptedCur && !ssl->options.handShakeDone && + ssl->keys.peer_sequence_number_hi == 0 && + ssl->keys.peer_sequence_number_lo == 0; + + /* Don't record an ignored plaintext alert in the alert history. */ + if (!ignorePtAlert) #endif { ssl->alert_history.last_rx.code = code; @@ -22529,16 +22566,21 @@ static int DoAlert(WOLFSSL* ssl, byte* input, word32* inOutIdx, int* type) !ssl->keys.decryptedCur) { #ifdef WOLFSSL_TLS13_IGNORE_PT_ALERT_ON_ENC - /* Ignore alert if TLS 1.3 and encrypting but was plaintext alert. */ - *type = invalid_alert; - level = alert_none; - -#else - /* Unexpected message when encryption is on and alert not encrypted. */ - SendAlert(ssl, alert_fatal, unexpected_message); - WOLFSSL_ERROR_VERBOSE(PARSE_ERROR); - return PARSE_ERROR; + if (ignorePtAlert) { + /* Ignore plaintext alert: TLS 1.3, decrypting, and the peer has + * not yet sent an encrypted handshake message. */ + *type = invalid_alert; + level = alert_none; + } + else #endif + { + /* Unexpected message when encryption is on and alert not + * encrypted. */ + SendAlert(ssl, alert_fatal, unexpected_message); + WOLFSSL_ERROR_VERBOSE(PARSE_ERROR); + return PARSE_ERROR; + } } else { if (*type == close_notify) { @@ -25848,6 +25890,153 @@ int SendCertificate(WOLFSSL* ssl) #if !defined(NO_TLS) +/* Returns the certificate_types this server advertises in its + * CertificateRequest. The list is broader than the negotiated cipher suite's + * own signature algorithm so a client may authenticate with a certificate of + * a different type (e.g. an RSA client on an ECDHE-ECDSA suite). */ +WC_MAYBE_UNUSED static int GetServerCertReqCertTypes(const WOLFSSL* ssl, + byte* certTypes) +{ + int n = 0; + (void)ssl; + (void)certTypes; +#ifdef HAVE_ECC + if ((ssl->options.cipherSuite0 == ECC_BYTE || + ssl->options.cipherSuite0 == CHACHA_BYTE) && + ssl->specs.sig_algo == ecc_dsa_sa_algo) { + certTypes[n++] = ecdsa_sign; + #ifndef NO_RSA + certTypes[n++] = rsa_sign; + #endif + } + else +#if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) && \ + (defined(WOLFSSL_SM4_CBC) || defined(WOLFSSL_SM4_GCM) || \ + defined(WOLFSSL_SM4_CCM)) + if (ssl->options.cipherSuite0 == SM_BYTE && (0 + #ifdef BUILD_TLS_ECDHE_ECDSA_WITH_SM4_CBC_SM3 + || ssl->options.cipherSuite == TLS_ECDHE_ECDSA_WITH_SM4_CBC_SM3 + #endif + #ifdef BUILD_TLS_ECDHE_ECDSA_WITH_SM4_GCM_SM3 + || ssl->options.cipherSuite == TLS_ECDHE_ECDSA_WITH_SM4_GCM_SM3 + #endif + #ifdef BUILD_TLS_ECDHE_ECDSA_WITH_SM4_CCM_SM3 + || ssl->options.cipherSuite == TLS_ECDHE_ECDSA_WITH_SM4_CCM_SM3 + #endif + )) { + certTypes[n++] = ecdsa_sign; + } + else +#endif +#endif /* HAVE_ECC */ + { +#ifndef NO_RSA + certTypes[n++] = rsa_sign; +#endif +#ifdef HAVE_ECC + certTypes[n++] = ecdsa_sign; +#endif + } + return n; +} + +/* Returns the set of sig families covered by the given hash/sig algorithm + * list, as a bitmask of SIG_* values. Uses DecodeSigAlg so the NEW_SA_MAJOR + * encoding (ED25519/ED448/RSA-PSS-PSS/brainpool) is classified correctly. */ +WC_MAYBE_UNUSED static int HashSigAlgoCoverage(const byte* hashSigAlgo, + word16 hashSigAlgoSz) +{ + int coverage = 0; + word16 j; + byte hashAlgo; + byte sigAlgo; + for (j = 0; (j + 1) < hashSigAlgoSz; j += HELLO_EXT_SIGALGO_SZ) { + DecodeSigAlg(&hashSigAlgo[j], &hashAlgo, &sigAlgo); + (void)hashAlgo; + switch (sigAlgo) { + case rsa_sa_algo: + #ifdef WC_RSA_PSS + case rsa_pss_sa_algo: + case rsa_pss_pss_algo: + #endif + coverage |= SIG_RSA; + break; + #ifdef HAVE_ECC + case ecc_dsa_sa_algo: + #ifdef HAVE_ECC_BRAINPOOL + case ecc_brainpool_sa_algo: + #endif + #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) + case sm2_sa_algo: + #endif + coverage |= SIG_ECDSA; + break; + #endif + default: + break; + } + } + return coverage; +} + +/* Builds the signature_algorithms this server advertises in its + * CertificateRequest. Respects a user-configured suites->hashSigAlgo (e.g. + * via wolfSSL_set1_sigalgs_list) and only broadens the list when one of the + * advertised certificate_types has no matching signature algorithm in the + * configured list. The result is written to the caller's buffer; no SSL + * state is modified. */ +WC_MAYBE_UNUSED static void GetServerCertReqHashSigAlgo(const WOLFSSL* ssl, + byte* hashSigAlgo, word16* hashSigAlgoSz) +{ + const Suites* suites = WOLFSSL_SUITES(ssl); + byte certTypes[MAX_CERT_REQ_CERT_TYPE_CNT]; + int typeTotal; + int need = 0; + int have; + int j; + word16 localSz = 0; + + typeTotal = GetServerCertReqCertTypes(ssl, certTypes); + for (j = 0; j < typeTotal; j++) { + if (certTypes[j] == rsa_sign) + need |= SIG_RSA; + else if (certTypes[j] == ecdsa_sign) + need |= SIG_ECDSA; + } + have = HashSigAlgoCoverage(suites->hashSigAlgo, suites->hashSigAlgoSz); + + if ((need & ~have) != 0) { + /* The configured list is missing signature algorithms for at least + * one of the advertised certificate_types. Build a broader list + * locally that covers every advertised type. */ + InitSuitesHashSigAlgo(hashSigAlgo, need | have, 1, 0, + ssl->buffers.keySz, &localSz); + *hashSigAlgoSz = localSz; + return; + } + + XMEMCPY(hashSigAlgo, suites->hashSigAlgo, suites->hashSigAlgoSz); + *hashSigAlgoSz = suites->hashSigAlgoSz; +} + +/* Returns 1 if algo (2 bytes) is in the server's CertificateRequest + * signature_algorithms list, 0 otherwise. Used to validate the client's + * CertificateVerify against what we actually advertised. */ +WC_MAYBE_UNUSED static int InServerCertReqHashSigAlgo(const WOLFSSL* ssl, + const byte* algo) +{ + byte list[WOLFSSL_MAX_SIGALGO]; + word16 listSz = 0; + word16 j; + + GetServerCertReqHashSigAlgo(ssl, list, &listSz); + for (j = 0; (j + 1) < listSz; j += HELLO_EXT_SIGALGO_SZ) { + if (XMEMCMP(&list[j], algo, HELLO_EXT_SIGALGO_SZ) == 0) + return 1; + } + return 0; +} + /* handle generation of certificate_request (13) */ int SendCertificateRequest(WOLFSSL* ssl) { @@ -25859,16 +26048,24 @@ int SendCertificateRequest(WOLFSSL* ssl) #ifndef WOLFSSL_NO_CA_NAMES WOLF_STACK_OF(WOLFSSL_X509_NAME)* names; #endif - const Suites* suites = WOLFSSL_SUITES(ssl); - - int typeTotal = 1; /* only 1 for now */ - int reqSz = ENUM_LEN + typeTotal + REQ_HEADER_SZ; /* add auth later */ + byte certTypes[MAX_CERT_REQ_CERT_TYPE_CNT]; + int typeTotal; + int t; + byte localHashSigAlgo[WOLFSSL_MAX_SIGALGO]; + word16 localHashSigAlgoSz = 0; + int reqSz; WOLFSSL_START(WC_FUNC_CERTIFICATE_REQUEST_SEND); WOLFSSL_ENTER("SendCertificateRequest"); + typeTotal = GetServerCertReqCertTypes(ssl, certTypes); if (IsAtLeastTLSv1_2(ssl)) - reqSz += LENGTH_SZ + suites->hashSigAlgoSz; + GetServerCertReqHashSigAlgo(ssl, localHashSigAlgo, &localHashSigAlgoSz); + + reqSz = ENUM_LEN + typeTotal + REQ_HEADER_SZ; /* add auth later */ + + if (IsAtLeastTLSv1_2(ssl)) + reqSz += LENGTH_SZ + localHashSigAlgoSz; #ifndef WOLFSSL_NO_CA_NAMES /* Certificate Authorities */ @@ -25921,43 +26118,16 @@ int SendCertificateRequest(WOLFSSL* ssl) /* write to output */ output[i++] = (byte)typeTotal; /* # of types */ -#ifdef HAVE_ECC - if ((ssl->options.cipherSuite0 == ECC_BYTE || - ssl->options.cipherSuite0 == CHACHA_BYTE) && - ssl->specs.sig_algo == ecc_dsa_sa_algo) { - output[i++] = ecdsa_sign; - } - else -#if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) && \ - (defined(WOLFSSL_SM4_CBC) || defined(WOLFSSL_SM4_GCM) || \ - defined(WOLFSSL_SM4_CCM)) - if (ssl->options.cipherSuite0 == SM_BYTE && (0 - #ifdef BUILD_TLS_ECDHE_ECDSA_WITH_SM4_CBC_SM3 - || ssl->options.cipherSuite == TLS_ECDHE_ECDSA_WITH_SM4_CBC_SM3 - #endif - #ifdef BUILD_TLS_ECDHE_ECDSA_WITH_SM4_GCM_SM3 - || ssl->options.cipherSuite == TLS_ECDHE_ECDSA_WITH_SM4_GCM_SM3 - #endif - #ifdef BUILD_TLS_ECDHE_ECDSA_WITH_SM4_CCM_SM3 - || ssl->options.cipherSuite == TLS_ECDHE_ECDSA_WITH_SM4_CCM_SM3 - #endif - )) { - output[i++] = ecdsa_sign; - } - else -#endif -#endif /* HAVE_ECC */ - { - output[i++] = rsa_sign; - } + for (t = 0; t < typeTotal; t++) + output[i++] = certTypes[t]; /* supported hash/sig */ if (IsAtLeastTLSv1_2(ssl)) { - c16toa(suites->hashSigAlgoSz, &output[i]); + c16toa(localHashSigAlgoSz, &output[i]); i += OPAQUE16_LEN; - XMEMCPY(&output[i], suites->hashSigAlgo, suites->hashSigAlgoSz); - i += suites->hashSigAlgoSz; + XMEMCPY(&output[i], localHashSigAlgo, localHashSigAlgoSz); + i += localHashSigAlgoSz; } /* Certificate Authorities */ @@ -32335,6 +32505,14 @@ static void MakePSKPreMasterSecret(Arrays* arrays, byte use_psk_key) if ((len > size) || ((*inOutIdx - begin) + len > size)) return BUFFER_ERROR; + /* Signature algorithm list is a sequence of 2-byte pairs; an odd + * length is malformed and must be rejected (matches TLS 1.3 + * signature_algorithms extension parsing). */ + if ((len % HELLO_EXT_SIGALGO_SZ) != 0) { + WOLFSSL_ERROR_VERBOSE(BUFFER_ERROR); + return BUFFER_ERROR; + } + if (PickHashSigAlgo(ssl, input + *inOutIdx, len, 0) != 0 && ssl->buffers.certificate && ssl->buffers.certificate->buffer) { @@ -33648,12 +33826,14 @@ static int DoServerKeyExchange(WOLFSSL* ssl, const byte* input, } #endif if (IsAtLeastTLSv1_2(ssl)) { + /* DigestInfo encoding for RSA, never a PQC + * signature -- size to the classic tier. */ WC_DECLARE_VAR(encodedSig, byte, - MAX_ENCODED_SIG_SZ, 0); + MAX_ENCODED_CLASSIC_SIG_SZ, 0); word32 encSigSz; WC_ALLOC_VAR_EX(encodedSig, byte, - MAX_ENCODED_SIG_SZ, ssl->heap, + MAX_ENCODED_CLASSIC_SIG_SZ, ssl->heap, DYNAMIC_TYPE_SIGNATURE, ERROR_OUT(MEMORY_E,exit_dske)); @@ -33663,7 +33843,9 @@ static int DoServerKeyExchange(WOLFSSL* ssl, const byte* input, TypeHash(ssl->options.peerHashAlgo)); if (encSigSz != args->sigSz || !args->output || XMEMCMP(args->output, encodedSig, - min(encSigSz, MAX_ENCODED_SIG_SZ)) != 0) { + min(encSigSz, + MAX_ENCODED_CLASSIC_SIG_SZ)) + != 0) { ret = VERIFY_SIGN_ERROR; } WC_FREE_VAR_EX(encodedSig, ssl->heap, @@ -34964,9 +35146,14 @@ int SendCertificateVerify(WOLFSSL* ssl) args->verify = &args->output[RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ]; args->extraSz = 0; /* tls 1.2 hash/sig */ - /* build encoded signature buffer */ - ssl->buffers.sig.length = MAX_ENCODED_SIG_SZ; - ssl->buffers.sig.buffer = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, + /* Build encoded signature buffer. This is TLS 1.2 and earlier + * (TLS 1.3 uses SendTls13CertificateVerify), so the signature is + * always classic (RSA/ECC/EdDSA), never PQC -- size to the classic + * tier rather than the (potentially huge) PQC worst case. This + * comfortably holds an ECC/EdDSA signature written directly, or the + * PKCS#1 DigestInfo that is the input to RsaSign. */ + ssl->buffers.sig.length = MAX_ENCODED_CLASSIC_SIG_SZ; + ssl->buffers.sig.buffer = (byte*)XMALLOC(MAX_ENCODED_CLASSIC_SIG_SZ, ssl->heap, DYNAMIC_TYPE_SIGNATURE); if (ssl->buffers.sig.buffer == NULL) { ERROR_OUT(MEMORY_E, exit_scv); @@ -36177,8 +36364,9 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) static int ReEncodeSig(WOLFSSL* ssl) { /* For TLS 1.2 re-encode signature */ if (IsAtLeastTLSv1_2(ssl)) { - byte* encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, ssl->heap, - DYNAMIC_TYPE_DIGEST); + /* DigestInfo encoding for RSA, never a PQC signature. */ + byte* encodedSig = (byte*)XMALLOC(MAX_ENCODED_CLASSIC_SIG_SZ, + ssl->heap, DYNAMIC_TYPE_DIGEST); if (encodedSig == NULL) return MEMORY_E; ssl->buffers.digest.length = @@ -38135,6 +38323,32 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) ssl->options.resuming = 0; return ret; } +#if defined(HAVE_SESSION_TICKET) && \ + (defined(HAVE_SNI) || defined(HAVE_ALPN)) + /* Do not resume session if sniHash/alpnHash do not match. */ + if (!ssl->options.useTicket) { + byte curHash[TICKET_BINDING_HASH_SZ]; +#ifdef HAVE_SNI + if (TicketSniHash(ssl, curHash) != 0 || + XMEMCMP(curHash, session->sniHash, + TICKET_BINDING_HASH_SZ) != 0) { + WOLFSSL_MSG("Resumed session SNI mismatch, full handshake"); + ssl->options.resuming = 0; + return ret; + } +#endif +#ifdef HAVE_ALPN + if (ssl->options.resuming && + (TicketAlpnHash(ssl, curHash) != 0 || + XMEMCMP(curHash, session->alpnHash, + TICKET_BINDING_HASH_SZ) != 0)) { + WOLFSSL_MSG("Resumed session ALPN mismatch, full handshake"); + ssl->options.resuming = 0; + return ret; + } +#endif + } +#endif /* HAVE_SESSION_TICKET && (HAVE_SNI || HAVE_ALPN) */ #if !defined(WOLFSSL_NO_TICKET_EXPIRE) && !defined(NO_ASN_TIME) /* check if the ticket is valid */ if (LowResTimer() > session->bornOn + ssl->timeout) { @@ -38660,6 +38874,14 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) *inOutIdx = i; +#if defined(HAVE_TLS_EXTENSIONS) && defined(HAVE_SUPPORTED_CURVES) + /* Reset per-ClientHello extension state before (re)parsing so a stale + * value from an earlier handshake on this object (e.g. secure + * renegotiation, where Options is not zeroed) cannot trigger a spurious + * RFC 8422 abort below. */ + ssl->options.peerNoUncompPF = 0; +#endif + /* tls extensions */ if ((i - begin) < helloSz) { #ifdef HAVE_TLS_EXTENSIONS @@ -38716,8 +38938,22 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) #endif #if defined(HAVE_SESSION_TICKET) && \ (defined(HAVE_SNI) || defined(HAVE_ALPN)) - if((ret=VerifyTicketBinding(ssl))) - goto out; + /* Only verify here for TLS 1.2 ticket-based resumption. + * For stateful (session-ID) resumption ssl->session is + * not loaded until HandleTlsResumption runs below, which + * performs its own binding check against the cached + * session. On mismatch decline the resumption (RFC 6066 + * Section 3) but proceed with a full handshake; leave + * useTicket set so the server still issues a fresh + * ticket to the client. */ + if (ssl->options.useTicket && + VerifyTicketBinding(ssl) != 0) { + WOLFSSL_MSG("Ticket binding mismatch, " + "declining resumption and falling back " + "to full handshake"); + ssl->options.resuming = 0; + ssl->options.peerAuthGood = 0; + } #endif i += totalExtSz; @@ -38858,6 +39094,25 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) if (ret == 0) ret = MatchSuite(ssl, ssl->clSuites); +#if defined(HAVE_TLS_EXTENSIONS) && defined(HAVE_SUPPORTED_CURVES) + /* RFC 8422 Section 5.1.2: abort only when an ECC suite was actually + * negotiated and the client's ec_point_formats omitted the uncompressed + * (0) format (peerNoUncompPF, set in TLSX_PointFormat_Parse). Checked + * after MatchSuite so it keys off the chosen suite, not advertised + * groups. */ + if (ret == 0 && ssl->options.peerNoUncompPF && + (ssl->specs.kea == ecc_diffie_hellman_kea || + ssl->specs.kea == ecc_static_diffie_hellman_kea || + ssl->specs.kea == ecdhe_psk_kea)) { + WOLFSSL_MSG("Client ec_point_formats extension missing " + "uncompressed format for negotiated ECC suite"); + SendAlert(ssl, alert_fatal, illegal_parameter); + ret = INVALID_PARAMETER; + WOLFSSL_ERROR_VERBOSE(ret); + goto out; + } +#endif + #if defined(HAVE_TLS_EXTENSIONS) && defined(HAVE_ENCRYPT_THEN_MAC) && \ !defined(WOLFSSL_AEAD_ONLY) if (ret == 0 && ssl->options.encThenMac && @@ -38980,9 +39235,9 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) ERROR_OUT(BUFFER_ERROR, exit_dcv); } - /* Check if hashSigAlgo in CertificateVerify is supported - * in our ssl->suites or ssl->ctx->suites. */ - if (!SupportedHashSigAlgo(ssl, &input[args->idx])) { + /* Check the algorithm in CertificateVerify against the + * list we actually advertised in our CertificateRequest. */ + if (!InServerCertReqHashSigAlgo(ssl, &input[args->idx])) { WOLFSSL_MSG("Signature algorithm was not in " "CertificateRequest"); ERROR_OUT(INVALID_PARAMETER, exit_dcv); @@ -39272,10 +39527,12 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) else #endif { + /* DigestInfo encoding for RSA */ #ifndef WOLFSSL_SMALL_STACK - byte encodedSig[MAX_ENCODED_SIG_SZ]; + byte encodedSig[MAX_ENCODED_CLASSIC_SIG_SZ]; #else - byte* encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, + byte* encodedSig = + (byte*)XMALLOC(MAX_ENCODED_CLASSIC_SIG_SZ, ssl->heap, DYNAMIC_TYPE_SIGNATURE); if (encodedSig == NULL) { ERROR_OUT(MEMORY_E, exit_dcv); @@ -39290,7 +39547,7 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) if (args->sendSz != args->sigSz || !args->output || XMEMCMP(args->output, encodedSig, - min(args->sigSz, MAX_ENCODED_SIG_SZ)) != 0) { + min(args->sigSz, MAX_ENCODED_CLASSIC_SIG_SZ)) != 0) { ret = VERIFY_CERT_ERROR; } @@ -39499,7 +39756,7 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) #ifdef HAVE_SNI /* Hash server-selected SNI; zeros dst when none. */ - static int TicketSniHash(WOLFSSL* ssl, byte* dst) + int TicketSniHash(WOLFSSL* ssl, byte* dst) { char* name = NULL; word16 nameLen; @@ -39519,16 +39776,23 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) #ifdef HAVE_ALPN /* Hash negotiated ALPN; zeros dst when none. */ - static int TicketAlpnHash(WOLFSSL* ssl, byte* dst) + int TicketAlpnHash(WOLFSSL* ssl, byte* dst) { - char* proto = NULL; - word16 protoLen = 0; + TLSX* extension; + ALPN* alpn; - if (TLSX_ALPN_GetRequest(ssl->extensions, (void**)&proto, - &protoLen) == WOLFSSL_SUCCESS && - proto != NULL && protoLen > 0) { - return wc_Hash(TICKET_BINDING_HASH_TYPE, (const byte*)proto, - protoLen, dst, TICKET_BINDING_HASH_SZ); + extension = TLSX_Find(ssl->extensions, TLSX_APPLICATION_LAYER_PROTOCOL); + if (extension != NULL) { + alpn = (ALPN*)extension->data; + if (alpn != NULL && alpn->negotiated == 1 && + alpn->protocol_name != NULL) { + word32 protoLen = (word32)XSTRLEN(alpn->protocol_name); + if (protoLen > 0) { + return wc_Hash(TICKET_BINDING_HASH_TYPE, + (const byte*)alpn->protocol_name, + protoLen, dst, TICKET_BINDING_HASH_SZ); + } + } } XMEMSET(dst, 0, TICKET_BINDING_HASH_SZ); @@ -39537,15 +39801,30 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) #endif #if defined(HAVE_SNI) || defined(HAVE_ALPN) - /* Server-side: verify the SNI/ALPN bindings carried on a resumed - * session match what was negotiated for the current connection. - * Must be called after extension parsing and ALPN_Select. - * Returns 0 on match, WOLFSSL_FATAL_ERROR on mismatch. */ + /* Server-side TLS 1.2 ticket-resumption binding check. Confirms the + * SNI/ALPN bound to the resumed session matches what was negotiated + * for the current connection. Must be called after extension + * parsing and ALPN_Select so the negotiated values are available, + * and only once DoClientTicketFinalize has populated + * ssl->session->sniHash/alpnHash from the decrypted ticket. + * + * Other resumption paths handle the same check themselves and do + * not use this function: + * - TLS 1.2 session-ID (stateful): HandleTlsResumption compares + * against the cached session at lookup time. + * - TLS 1.3 PSK: DoPreSharedKeys compares against each candidate + * ticket's bound hashes before committing, allowing the server + * to skip mismatching PSKs and pick the next one. + * + * Returns 0 on match, WOLFSSL_FATAL_ERROR on mismatch. The caller + * is responsible for the policy on mismatch -- RFC 6066 Section 3 + * mandates declining the resumption and proceeding with a full + * handshake rather than aborting. */ int VerifyTicketBinding(WOLFSSL* ssl) { byte curHash[TICKET_BINDING_HASH_SZ]; - if (!ssl->options.resuming || !ssl->options.useTicket) + if (!ssl->options.resuming) return 0; #ifdef HAVE_SNI @@ -40054,8 +40333,9 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) ssl->sessionCtxSz) != 0)) return WOLFSSL_FATAL_ERROR; #endif - /* SNI/ALPN binding is verified after ALPN_Select via - * VerifyTicketBinding(). */ + /* SNI/ALPN binding is checked by the per-PSK loop in + * DoPreSharedKeys, not here, so that mismatching PSKs can be + * skipped in favor of the next candidate. */ return 0; } #endif /* WOLFSSL_SLT13 */ @@ -40151,8 +40431,13 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) } } #endif - /* Carry the ticket bindings on the session for the deferred - * VerifyTicketBinding() check. */ + /* Carry the ticket bindings on the session. TLS 1.2 uses these + * for the deferred VerifyTicketBinding() check in DoClientHello + * (SNI/ALPN aren't known when DoClientTicket runs during + * extension parsing). TLS 1.3 checks bindings per-PSK before + * reaching this point, but still copies them so a subsequent + * SetupSession on a resumed session preserves them in the cache + * for future resumptions. */ #ifdef HAVE_SNI XMEMCPY(ssl->session->sniHash, it->sniHash, TICKET_BINDING_HASH_SZ); #endif @@ -40518,8 +40803,9 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) goto cleanup; } - /* SNI/ALPN binding is verified after ALPN_Select via - * VerifyTicketBinding(). */ + /* SNI/ALPN binding is verified later in DoClientHello via + * VerifyTicketBinding(), once extension parsing and ALPN_Select + * have run and the negotiated values are available. */ DoClientTicketFinalize(ssl, it, NULL); cleanup: @@ -42643,6 +42929,27 @@ int wolfssl_local_GetRecordSize(WOLFSSL *ssl, int payloadSz, int isEncrypted) return BAD_FUNC_ARG; if (isEncrypted) { + /* AEAD overhead is constant per cache key (cipher, version, CID, DTLS + * 1.3 epoch); use the cached value when available. DTLS 1.3 pads + * records up to Dtls13MinimumRecordLength() (RFC 9147 5.5), so: + * - on read: only return the cached overhead when the resulting + * record would not be padded; + * - on populate: only store the overhead when BuildMessage returned + * a record strictly above the minimum, which guarantees no + * padding was applied. */ +#ifdef WOLFSSL_DTLS13 + int isDtls13 = ssl->options.dtls && ssl->options.tls1_3; +#endif + + if (ssl->specs.cipher_type == aead && ssl->recordSzOverhead != 0 +#ifdef WOLFSSL_DTLS13 + && (!isDtls13 || payloadSz + (int)ssl->recordSzOverhead + >= Dtls13MinimumRecordLength(ssl)) +#endif + ) { + return payloadSz + (int)ssl->recordSzOverhead; + } + recordSz = BuildMessage(ssl, NULL, 0, NULL, payloadSz, application_data, 0, 1, 0, CUR_ORDER); /* use a safe upper bound in case of error */ @@ -42653,6 +42960,14 @@ int wolfssl_local_GetRecordSize(WOLFSSL *ssl, int payloadSz, int isEncrypted) recordSz += DTLS_RECORD_EXTRA; } } + else if (ssl->specs.cipher_type == aead && recordSz > payloadSz +#ifdef WOLFSSL_DTLS13 + && (!isDtls13 || recordSz > Dtls13MinimumRecordLength(ssl)) +#endif + ) { + /* Populate cache only on success; never from the fallback. */ + ssl->recordSzOverhead = (word32)(recordSz - payloadSz); + } } else { recordSz = payloadSz + RECORD_HEADER_SZ; diff --git a/src/keys.c b/src/keys.c index 3a980b9ce3..f9e7d3b7b3 100644 --- a/src/keys.c +++ b/src/keys.c @@ -3499,6 +3499,12 @@ int SetKeysSide(WOLFSSL* ssl, enum encrypt_side side) (void)copy; + /* Cipher activation invalidates the cached AEAD record overhead. Covers + * TLS 1.2 / TLS 1.3 handshake completion, secure renegotiation, early + * data flips, and DTLS 1.3 epoch transitions (Dtls13SetEpochKeys() calls + * SetKeysSide() at the bottom). */ + ssl->recordSzOverhead = 0; + #ifdef HAVE_SECURE_RENEGOTIATION if (ssl->secure_renegotiation && ssl->secure_renegotiation->cache_status != SCR_CACHE_NULL) { diff --git a/src/ocsp.c b/src/ocsp.c index c84eebc5e5..221fbd6cca 100644 --- a/src/ocsp.c +++ b/src/ocsp.c @@ -21,15 +21,6 @@ #include - /* Name change compatibility layer no longer needs to be included here */ - -/* - * WOLFSSL_NO_OCSP_ISSUER_CHAIN_CHECK: - * Disable looking for an authorized responder in the verification path of - * the issuer. This will make the authorized responder only look at the - * OCSP response signer and direct issuer. - */ - /* * OCSP responder missing features: * - Support for multiple requests and responses in a single OCSP exchange @@ -590,80 +581,13 @@ int CheckOcspRequest(WOLFSSL_OCSP* ocsp, OcspRequest* ocspRequest, return ret; } -#ifndef WOLFSSL_NO_OCSP_ISSUER_CHAIN_CHECK -static int CheckOcspResponderChain(OcspEntry* single, byte* issuerNameHash, - byte* issuerKeyHash, void* vp, Signer* pendingCAs) { - /* Attempt to build a chain up to cert's issuer */ - WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)vp; - Signer* ca = NULL; - Signer* prev = NULL; - int passed = 0; - - /* - * Relation between certs: - * CA - * / \ - * intermediate(s) cert in OCSP response - * | with OCSP key usage ext - * issuer of cert - * in OCSP request - */ - - if (issuerKeyHash == NULL) - return 0; - - /* Select CertID issuer by key hash so a same-DN / different-key trust - * anchor cannot hijack the starting point. */ - ca = GetCAByKeyHash(cm, single->issuerKeyHash); - if (ca != NULL && XMEMCMP(ca->subjectNameHash, single->issuerHash, - OCSP_DIGEST_SIZE) != 0) { - ca = NULL; - } -#if defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) - if (ca == NULL && pendingCAs != NULL) { - ca = findSignerByKeyHash(pendingCAs, single->issuerKeyHash); - if (ca != NULL && XMEMCMP(ca->subjectNameHash, single->issuerHash, - OCSP_DIGEST_SIZE) != 0) { - ca = NULL; - } - } -#else - (void)pendingCAs; -#endif - for (; ca != NULL && ca != prev; - prev = ca) { - Signer* parent = GetCAByName(cm, ca->issuerNameHash); -#if defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) - if (parent == NULL && pendingCAs != NULL) { - parent = findSignerByName(pendingCAs, ca->issuerNameHash); - } -#endif - if (parent == NULL || parent == ca) - break; - - if (XMEMCMP(parent->subjectNameHash, issuerNameHash, - OCSP_DIGEST_SIZE) == 0 && - XMEMCMP(parent->subjectKeyHash, issuerKeyHash, - KEYID_SIZE) == 0) { - WOLFSSL_MSG("\tOCSP Response signed by authorized " - "responder delegated by issuer " - "(found in chain)"); - passed = 1; - break; - } - ca = parent; - } - return passed; -} -#endif - /* Enforce https://www.rfc-editor.org/rfc/rfc6960#section-4.2.2.2. Both halves * of CertID (issuerNameHash and issuerKeyHash) must match; name-only matching * would authorize a same-DN / different-key CA. issuerKeyHash may be NULL when * unavailable, which disables the delegated branch. */ int CheckOcspResponder(OcspResponse *bs, byte* subjectNameHash, byte* subjectKeyHash, byte extExtKeyUsage, byte* issuerNameHash, - byte* issuerKeyHash, void* vp) + byte* issuerKeyHash) { int ret = 0; OcspEntry* single; @@ -671,8 +595,6 @@ int CheckOcspResponder(OcspResponse *bs, byte* subjectNameHash, /* Both evaluate to enum values so can't use a pre-processor check */ WOLFSSL_ASSERT_EQ(OCSP_DIGEST_SIZE, SIGNER_DIGEST_SIZE); - (void)vp; - WOLFSSL_ENTER("CheckOcspResponder"); /* In the future if this API is used more then it could be beneficial to @@ -702,12 +624,6 @@ int CheckOcspResponder(OcspResponse *bs, byte* subjectNameHash, "delegated by issuer"); passed = 1; } -#ifndef WOLFSSL_NO_OCSP_ISSUER_CHAIN_CHECK - else if (vp != NULL) { - passed = CheckOcspResponderChain(single, issuerNameHash, - issuerKeyHash, vp, bs->pendingCAs); - } -#endif } if (!passed) { @@ -1112,8 +1028,7 @@ static int OcspVerifySigner(WOLFSSL_OCSP_BASICRESP *resp, DecodedCert *cert, if ((flags & WOLFSSL_OCSP_NOCHECKS) == 0) { ret = CheckOcspResponder(resp, c->subjectHash, c->subjectKeyHash, c->extExtKeyUsage, c->issuerHash, - (c->ca != NULL) ? c->ca->subjectKeyHash : NULL, - st->cm); + (c->ca != NULL) ? c->ca->subjectKeyHash : NULL); } else { ret = 0; @@ -1273,6 +1188,10 @@ OcspResponse* wolfSSL_d2i_OCSP_RESPONSE(OcspResponse** response, if (data == NULL || *data == NULL || len <= 0) return NULL; + if (*data == NULL) + return NULL; + if (len <= 0) + return NULL; if (response != NULL) resp = *response; diff --git a/src/pk.c b/src/pk.c index 131e1367e0..bfc039e5d0 100644 --- a/src/pk.c +++ b/src/pk.c @@ -4977,8 +4977,7 @@ static int _DH_compute_key(unsigned char* key, const WOLFSSL_BIGNUM* otherPub, * correctly. */ if (keySz < padded_keySz) { - XMEMMOVE(key, key + (padded_keySz - keySz), - padded_keySz - keySz); + XMEMMOVE(key + (padded_keySz - keySz), key, keySz); XMEMSET(key, 0, padded_keySz - keySz); keySz = padded_keySz; } diff --git a/src/pk_ec.c b/src/pk_ec.c index 883f758150..fc22ce163d 100644 --- a/src/pk_ec.c +++ b/src/pk_ec.c @@ -449,6 +449,8 @@ static WOLFSSL_EC_GROUP* wolfssl_ec_group_d2i(WOLFSSL_EC_GROUP** group, if (in_pp == NULL || *in_pp == NULL) return NULL; + if (inSz <= 0) + return NULL; in = *in_pp; @@ -4998,7 +5000,10 @@ WOLFSSL_ECDSA_SIG* wolfSSL_d2i_ECDSA_SIG(WOLFSSL_ECDSA_SIG** sig, WOLFSSL_ECDSA_SIG *s = NULL; /* Validate parameter. */ - if (pp == NULL) { + if (pp == NULL || *pp == NULL) { + err = 1; + } + if ((!err) && (len <= 0)) { err = 1; } if (!err) { diff --git a/src/pk_rsa.c b/src/pk_rsa.c index ba68929bfa..63ab70abd2 100644 --- a/src/pk_rsa.c +++ b/src/pk_rsa.c @@ -454,6 +454,10 @@ WOLFSSL_RSA *wolfSSL_d2i_RSAPublicKey(WOLFSSL_RSA **out, WOLFSSL_ERROR_MSG("Bad argument"); err = 1; } + if ((!err) && (derSz <= 0)) { + WOLFSSL_ERROR_MSG("Bad argument"); + err = 1; + } /* Create a new RSA key to return. */ if ((!err) && ((rsa = wolfSSL_RSA_new()) == NULL)) { WOLFSSL_ERROR_MSG("RSA_new failed"); @@ -503,6 +507,10 @@ WOLFSSL_RSA *wolfSSL_d2i_RSAPrivateKey(WOLFSSL_RSA **out, WOLFSSL_ERROR_MSG("Bad argument"); err = 1; } + if ((!err) && (derSz <= 0)) { + WOLFSSL_ERROR_MSG("Bad argument"); + err = 1; + } /* Create a new RSA key to return. */ if ((!err) && ((rsa = wolfSSL_RSA_new()) == NULL)) { WOLFSSL_ERROR_MSG("RSA_new failed"); @@ -3109,7 +3117,7 @@ int wolfSSL_RSA_sign_mgf(int hashAlg, const unsigned char* hash, #else WC_RNG _tmpRng[1]; WC_RNG* tmpRng = _tmpRng; - byte encodedSig[MAX_ENCODED_SIG_SZ]; + byte encodedSig[MAX_ENCODED_CLASSIC_SIG_SZ]; #endif unsigned int encSz = 0; @@ -3150,7 +3158,7 @@ int wolfSSL_RSA_sign_mgf(int hashAlg, const unsigned char* hash, #ifdef WOLFSSL_SMALL_STACK if (ret == 1) { /* Allocate encoded signature buffer if doing PKCS#1 padding. */ - encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, NULL, + encodedSig = (byte*)XMALLOC(MAX_ENCODED_CLASSIC_SIG_SZ, NULL, DYNAMIC_TYPE_SIGNATURE); if (encodedSig == NULL) { ret = 0; @@ -3306,10 +3314,10 @@ int wolfSSL_RSA_verify_mgf(int hashAlg, const unsigned char* hash, #ifdef WOLFSSL_SMALL_STACK unsigned char* encodedSig = NULL; #else - unsigned char encodedSig[MAX_ENCODED_SIG_SZ]; + unsigned char encodedSig[MAX_ENCODED_CLASSIC_SIG_SZ]; #endif unsigned char* sigDec = NULL; - unsigned int len = MAX_ENCODED_SIG_SZ; + unsigned int len = MAX_ENCODED_CLASSIC_SIG_SZ; int verLen = 0; #if (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5, 1)) && !defined(HAVE_SELFTEST) enum wc_HashType hType = WC_HASH_TYPE_NONE; diff --git a/src/ssl.c b/src/ssl.c index b7fe52ddde..e3f4114ec1 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -149,6 +149,12 @@ #endif #endif /* !WOLFCRYPT_ONLY || OPENSSL_EXTRA */ +#if !defined(WOLFCRYPT_ONLY) && defined(WOLFSSL_SYS_CRYPTO_POLICY) +/* The system wide crypto-policy. Configured by wolfSSL_crypto_policy_enable. + * */ +static struct SystemCryptoPolicy crypto_policy; +#endif /* !WOLFCRYPT_ONLY && WOLFSSL_SYS_CRYPTO_POLICY */ + /* * ssl.c Build Options: * @@ -318,12 +324,6 @@ int wc_OBJ_sn2nid(const char *sn) #ifndef WOLFCRYPT_ONLY -#if defined(WOLFSSL_SYS_CRYPTO_POLICY) -/* The system wide crypto-policy. Configured by wolfSSL_crypto_policy_enable. - * */ -static struct SystemCryptoPolicy crypto_policy; -#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - #if !defined(NO_RSA) || !defined(NO_DH) || defined(HAVE_ECC) || \ (defined(OPENSSL_EXTRA) && defined(WOLFSSL_KEY_GEN) && !defined(NO_DSA)) @@ -1114,25 +1114,6 @@ int wolfSSL_set_fd(WOLFSSL* ssl, int fd) return ret; } -#ifdef WOLFSSL_DTLS -int wolfSSL_set_dtls_fd_connected(WOLFSSL* ssl, int fd) -{ - int ret; - - WOLFSSL_ENTER("wolfSSL_set_dtls_fd_connected"); - - if (ssl == NULL) { - return BAD_FUNC_ARG; - } - - ret = wolfSSL_set_fd(ssl, fd); - if (ret == WOLFSSL_SUCCESS) - ssl->buffers.dtlsCtx.connected = 1; - - return ret; -} -#endif - int wolfSSL_set_read_fd(WOLFSSL* ssl, int fd) { @@ -1295,10 +1276,12 @@ const char* wolfSSL_get_shared_ciphers(WOLFSSL* ssl, char* buf, int len) { const char* cipher; - if (ssl == NULL || len <= 0) + if (ssl == NULL || buf == NULL || len <= 0) return NULL; cipher = wolfSSL_get_cipher_name_iana(ssl); + if (cipher == NULL) + return NULL; len = (int)min((word32)len, (word32)(XSTRLEN(cipher) + 1)); XMEMCPY(buf, cipher, (size_t)len); return buf; @@ -1327,14 +1310,6 @@ int wolfSSL_get_wfd(const WOLFSSL* ssl) } -int wolfSSL_dtls(WOLFSSL* ssl) -{ - int dtlsOpt = 0; - if (ssl) - dtlsOpt = ssl->options.dtls; - return dtlsOpt; -} - #ifdef WOLFSSL_WOLFSENTRY_HOOKS int wolfSSL_CTX_set_AcceptFilter( @@ -1387,729 +1362,6 @@ int wolfSSL_set_ConnectFilter( #endif /* WOLFSSL_WOLFSENTRY_HOOKS */ -#ifndef WOLFSSL_LEANPSK -#if defined(WOLFSSL_DTLS) && defined(XINET_PTON) && \ - !defined(WOLFSSL_NO_SOCK) && defined(HAVE_SOCKADDR) -void* wolfSSL_dtls_create_peer(int port, char* ip) -{ - SOCKADDR_IN *addr; - addr = (SOCKADDR_IN*)XMALLOC(sizeof(*addr), NULL, - DYNAMIC_TYPE_SOCKADDR); - if (addr == NULL) { - return NULL; - } - - addr->sin_family = AF_INET; - addr->sin_port = XHTONS((word16)port); - if (XINET_PTON(AF_INET, ip, &addr->sin_addr) < 1) { - XFREE(addr, NULL, DYNAMIC_TYPE_SOCKADDR); - return NULL; - } - - return addr; -} - -int wolfSSL_dtls_free_peer(void* addr) -{ - XFREE(addr, NULL, DYNAMIC_TYPE_SOCKADDR); - return WOLFSSL_SUCCESS; -} -#endif - -#ifdef WOLFSSL_DTLS -static int SockAddrSet(WOLFSSL_SOCKADDR* sockAddr, void* peer, - unsigned int peerSz, void* heap) -{ - if (peer == NULL || peerSz == 0) { - if (sockAddr->sa != NULL) - XFREE(sockAddr->sa, heap, DYNAMIC_TYPE_SOCKADDR); - sockAddr->sa = NULL; - sockAddr->sz = 0; - sockAddr->bufSz = 0; - return WOLFSSL_SUCCESS; - } - - if (peerSz > sockAddr->bufSz) { - if (sockAddr->sa != NULL) - XFREE(sockAddr->sa, heap, DYNAMIC_TYPE_SOCKADDR); - sockAddr->sa = - (void*)XMALLOC(peerSz, heap, DYNAMIC_TYPE_SOCKADDR); - if (sockAddr->sa == NULL) { - sockAddr->sz = 0; - sockAddr->bufSz = 0; - return WOLFSSL_FAILURE; - } - sockAddr->bufSz = peerSz; - } - XMEMCPY(sockAddr->sa, peer, peerSz); - sockAddr->sz = peerSz; - return WOLFSSL_SUCCESS; -} -#endif - -int wolfSSL_dtls_set_peer(WOLFSSL* ssl, void* peer, unsigned int peerSz) -{ -#ifdef WOLFSSL_DTLS - int ret; - - if (ssl == NULL) - return WOLFSSL_FAILURE; -#ifdef WOLFSSL_RW_THREADED - if (wc_LockRwLock_Wr(&ssl->buffers.dtlsCtx.peerLock) != 0) - return WOLFSSL_FAILURE; -#endif - ret = SockAddrSet(&ssl->buffers.dtlsCtx.peer, peer, peerSz, ssl->heap); - if (ret == WOLFSSL_SUCCESS && !(peer == NULL || peerSz == 0)) - ssl->buffers.dtlsCtx.userSet = 1; - else - ssl->buffers.dtlsCtx.userSet = 0; -#ifdef WOLFSSL_RW_THREADED - if (wc_UnLockRwLock(&ssl->buffers.dtlsCtx.peerLock) != 0) - ret = WOLFSSL_FAILURE; -#endif - return ret; -#else - (void)ssl; - (void)peer; - (void)peerSz; - return WOLFSSL_NOT_IMPLEMENTED; -#endif -} - -#if defined(WOLFSSL_DTLS_CID) && !defined(WOLFSSL_NO_SOCK) -int wolfSSL_dtls_set_pending_peer(WOLFSSL* ssl, void* peer, unsigned int peerSz) -{ -#ifdef WOLFSSL_DTLS - int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); - - if (ssl == NULL) - return WOLFSSL_FAILURE; -#ifdef WOLFSSL_RW_THREADED - if (wc_LockRwLock_Rd(&ssl->buffers.dtlsCtx.peerLock) != 0) - return WOLFSSL_FAILURE; -#endif - if (ssl->buffers.dtlsCtx.peer.sa != NULL && - ssl->buffers.dtlsCtx.peer.sz == peerSz && - sockAddrEqual((SOCKADDR_S*)ssl->buffers.dtlsCtx.peer.sa, - (XSOCKLENT)ssl->buffers.dtlsCtx.peer.sz, (SOCKADDR_S*)peer, - (XSOCKLENT)peerSz)) { - /* Already the current peer. */ - if (ssl->buffers.dtlsCtx.pendingPeer.sa != NULL) { - /* Clear any other pendingPeer */ - XFREE(ssl->buffers.dtlsCtx.pendingPeer.sa, ssl->heap, - DYNAMIC_TYPE_SOCKADDR); - ssl->buffers.dtlsCtx.pendingPeer.sa = NULL; - ssl->buffers.dtlsCtx.pendingPeer.sz = 0; - ssl->buffers.dtlsCtx.pendingPeer.bufSz = 0; - } - ret = WOLFSSL_SUCCESS; - } - else { - ret = SockAddrSet(&ssl->buffers.dtlsCtx.pendingPeer, peer, peerSz, - ssl->heap); - } - if (ret == WOLFSSL_SUCCESS) - ssl->buffers.dtlsCtx.processingPendingRecord = 0; -#ifdef WOLFSSL_RW_THREADED - if (wc_UnLockRwLock(&ssl->buffers.dtlsCtx.peerLock) != 0) - ret = WOLFSSL_FAILURE; -#endif - return ret; -#else - (void)ssl; - (void)peer; - (void)peerSz; - return WOLFSSL_NOT_IMPLEMENTED; -#endif -} -#endif /* WOLFSSL_DTLS_CID && !WOLFSSL_NO_SOCK */ - -int wolfSSL_dtls_get_peer(WOLFSSL* ssl, void* peer, unsigned int* peerSz) -{ -#ifdef WOLFSSL_DTLS - int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); - if (ssl == NULL) - return WOLFSSL_FAILURE; -#ifdef WOLFSSL_RW_THREADED - if (wc_LockRwLock_Rd(&ssl->buffers.dtlsCtx.peerLock) != 0) - return WOLFSSL_FAILURE; -#endif - if (peer != NULL && peerSz != NULL - && *peerSz >= ssl->buffers.dtlsCtx.peer.sz - && ssl->buffers.dtlsCtx.peer.sa != NULL) { - *peerSz = ssl->buffers.dtlsCtx.peer.sz; - XMEMCPY(peer, ssl->buffers.dtlsCtx.peer.sa, *peerSz); - ret = WOLFSSL_SUCCESS; - } -#ifdef WOLFSSL_RW_THREADED - if (wc_UnLockRwLock(&ssl->buffers.dtlsCtx.peerLock) != 0) - ret = WOLFSSL_FAILURE; -#endif - return ret; -#else - (void)ssl; - (void)peer; - (void)peerSz; - return WOLFSSL_NOT_IMPLEMENTED; -#endif -} - -int wolfSSL_dtls_get0_peer(WOLFSSL* ssl, const void** peer, - unsigned int* peerSz) -{ -#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_RW_THREADED) - if (ssl == NULL) - return WOLFSSL_FAILURE; - - if (peer == NULL || peerSz == NULL) - return WOLFSSL_FAILURE; - - *peer = ssl->buffers.dtlsCtx.peer.sa; - *peerSz = ssl->buffers.dtlsCtx.peer.sz; - return WOLFSSL_SUCCESS; -#else - (void)ssl; - (void)peer; - (void)peerSz; - return WOLFSSL_NOT_IMPLEMENTED; -#endif -} - - -#if defined(WOLFSSL_SCTP) && defined(WOLFSSL_DTLS) - -int wolfSSL_CTX_dtls_set_sctp(WOLFSSL_CTX* ctx) -{ - WOLFSSL_ENTER("wolfSSL_CTX_dtls_set_sctp"); - - if (ctx == NULL) - return BAD_FUNC_ARG; - - ctx->dtlsSctp = 1; - return WOLFSSL_SUCCESS; -} - - -int wolfSSL_dtls_set_sctp(WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_dtls_set_sctp"); - - if (ssl == NULL) - return BAD_FUNC_ARG; - - ssl->options.dtlsSctp = 1; - return WOLFSSL_SUCCESS; -} - -#endif /* WOLFSSL_DTLS && WOLFSSL_SCTP */ - -#if (defined(WOLFSSL_SCTP) || defined(WOLFSSL_DTLS_MTU)) && \ - defined(WOLFSSL_DTLS) - -int wolfSSL_CTX_dtls_set_mtu(WOLFSSL_CTX* ctx, word16 newMtu) -{ - if (ctx == NULL || newMtu > MAX_RECORD_SIZE) - return BAD_FUNC_ARG; - - ctx->dtlsMtuSz = newMtu; - return WOLFSSL_SUCCESS; -} - - -int wolfSSL_dtls_set_mtu(WOLFSSL* ssl, word16 newMtu) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - - if (newMtu > MAX_RECORD_SIZE) { - ssl->error = BAD_FUNC_ARG; - return WOLFSSL_FAILURE; - } - - ssl->dtlsMtuSz = newMtu; - return WOLFSSL_SUCCESS; -} - -#ifdef OPENSSL_EXTRA -/* Maps to compatibility API SSL_set_mtu and is same as wolfSSL_dtls_set_mtu, - * but expects only success or failure returns. */ -int wolfSSL_set_mtu_compat(WOLFSSL* ssl, unsigned short mtu) -{ - if (wolfSSL_dtls_set_mtu(ssl, mtu) == WOLFSSL_SUCCESS) - return WOLFSSL_SUCCESS; - else - return WOLFSSL_FAILURE; -} -#endif /* OPENSSL_EXTRA */ - -#endif /* WOLFSSL_DTLS && (WOLFSSL_SCTP || WOLFSSL_DTLS_MTU) */ - -#ifdef WOLFSSL_SRTP - -static const WOLFSSL_SRTP_PROTECTION_PROFILE gSrtpProfiles[] = { - /* AES CCM 128, Salt:112-bits, Auth HMAC-SHA1 Tag: 80-bits - * (master_key:128bits + master_salt:112bits) * 2 = 480 bits (60) */ - {"SRTP_AES128_CM_SHA1_80", SRTP_AES128_CM_SHA1_80, - (((128 + 112) * 2) / 8) }, - /* AES CCM 128, Salt:112-bits, Auth HMAC-SHA1 Tag: 32-bits - * (master_key:128bits + master_salt:112bits) * 2 = 480 bits (60) */ - {"SRTP_AES128_CM_SHA1_32", SRTP_AES128_CM_SHA1_32, - (((128 + 112) * 2) / 8) }, - /* NULL Cipher, Salt:112-bits, Auth HMAC-SHA1 Tag 80-bits */ - {"SRTP_NULL_SHA1_80", SRTP_NULL_SHA1_80, ((112 * 2) / 8)}, - /* NULL Cipher, Salt:112-bits, Auth HMAC-SHA1 Tag 32-bits */ - {"SRTP_NULL_SHA1_32", SRTP_NULL_SHA1_32, ((112 * 2) / 8)}, - /* AES GCM 128, Salt: 96-bits, Auth GCM Tag 128-bits - * (master_key:128bits + master_salt:96bits) * 2 = 448 bits (56) */ - {"SRTP_AEAD_AES_128_GCM", SRTP_AEAD_AES_128_GCM, (((128 + 96) * 2) / 8) }, - /* AES GCM 256, Salt: 96-bits, Auth GCM Tag 128-bits - * (master_key:256bits + master_salt:96bits) * 2 = 704 bits (88) */ - {"SRTP_AEAD_AES_256_GCM", SRTP_AEAD_AES_256_GCM, (((256 + 96) * 2) / 8) }, -}; - -static const WOLFSSL_SRTP_PROTECTION_PROFILE* DtlsSrtpFindProfile( - const char* profile_str, word32 profile_str_len, unsigned long id) -{ - int i; - const WOLFSSL_SRTP_PROTECTION_PROFILE* profile = NULL; - for (i=0; - i<(int)(sizeof(gSrtpProfiles)/sizeof(WOLFSSL_SRTP_PROTECTION_PROFILE)); - i++) { - if (profile_str != NULL) { - word32 srtp_profile_len = (word32)XSTRLEN(gSrtpProfiles[i].name); - if (srtp_profile_len == profile_str_len && - XMEMCMP(gSrtpProfiles[i].name, profile_str, profile_str_len) - == 0) { - profile = &gSrtpProfiles[i]; - break; - } - } - else if (id != 0 && gSrtpProfiles[i].id == id) { - profile = &gSrtpProfiles[i]; - break; - } - } - return profile; -} - -/* profile_str: accepts ":" colon separated list of SRTP profiles */ -static int DtlsSrtpSelProfiles(word16* id, const char* profile_str) -{ - const WOLFSSL_SRTP_PROTECTION_PROFILE* profile; - const char *current, *next = NULL; - word32 length = 0, current_length; - - *id = 0; /* reset destination ID's */ - - if (profile_str == NULL) { - return WOLFSSL_FAILURE; - } - - /* loop on end of line or colon ":" */ - next = profile_str; - length = (word32)XSTRLEN(profile_str); - do { - current = next; - next = XSTRSTR(current, ":"); - if (next) { - current_length = (word32)(next - current); - ++next; /* ++ needed to skip ':' */ - } else { - current_length = (word32)XSTRLEN(current); - } - if (current_length < length) - length = current_length; - profile = DtlsSrtpFindProfile(current, current_length, 0); - if (profile != NULL) { - *id |= (1 << profile->id); /* selected bit based on ID */ - } - } while (next != NULL); - return WOLFSSL_SUCCESS; -} - -/** - * @brief Set the SRTP protection profiles for DTLS. - * - * @param ctx Pointer to the WOLFSSL_CTX structure representing the SSL/TLS - * context. - * @param profile_str A colon-separated string of SRTP profile names. - * @return 0 on success to match OpenSSL - * @return 1 on error to match OpenSSL - */ -int wolfSSL_CTX_set_tlsext_use_srtp(WOLFSSL_CTX* ctx, const char* profile_str) -{ - int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); - if (ctx != NULL) { - ret = DtlsSrtpSelProfiles(&ctx->dtlsSrtpProfiles, profile_str); - } - - if (ret == WC_NO_ERR_TRACE(WOLFSSL_FAILURE)) { - ret = 1; - } else { - ret = 0; - } - - return ret; -} - -/** - * @brief Set the SRTP protection profiles for DTLS. - * - * @param ssl Pointer to the WOLFSSL structure representing the SSL/TLS - * session. - * @param profile_str A colon-separated string of SRTP profile names. - * @return 0 on success to match OpenSSL - * @return 1 on error to match OpenSSL - */ -int wolfSSL_set_tlsext_use_srtp(WOLFSSL* ssl, const char* profile_str) -{ - int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); - if (ssl != NULL) { - ret = DtlsSrtpSelProfiles(&ssl->dtlsSrtpProfiles, profile_str); - } - - if (ret == WC_NO_ERR_TRACE(WOLFSSL_FAILURE)) { - ret = 1; - } else { - ret = 0; - } - - return ret; -} - -const WOLFSSL_SRTP_PROTECTION_PROFILE* wolfSSL_get_selected_srtp_profile( - WOLFSSL* ssl) -{ - const WOLFSSL_SRTP_PROTECTION_PROFILE* profile = NULL; - if (ssl) { - profile = DtlsSrtpFindProfile(NULL, 0, ssl->dtlsSrtpId); - } - return profile; -} -#ifndef NO_WOLFSSL_STUB -WOLF_STACK_OF(WOLFSSL_SRTP_PROTECTION_PROFILE)* wolfSSL_get_srtp_profiles( - WOLFSSL* ssl) -{ - /* Not yet implemented - should return list of available SRTP profiles - * ssl->dtlsSrtpProfiles */ - (void)ssl; - return NULL; -} -#endif - -#define DTLS_SRTP_KEYING_MATERIAL_LABEL "EXTRACTOR-dtls_srtp" - -int wolfSSL_export_dtls_srtp_keying_material(WOLFSSL* ssl, - unsigned char* out, size_t* olen) -{ - const WOLFSSL_SRTP_PROTECTION_PROFILE* profile = NULL; - - if (ssl == NULL || olen == NULL) { - return BAD_FUNC_ARG; - } - - profile = DtlsSrtpFindProfile(NULL, 0, ssl->dtlsSrtpId); - if (profile == NULL) { - WOLFSSL_MSG("Not using DTLS SRTP"); - return EXT_MISSING; - } - if (out == NULL) { - *olen = (size_t)profile->kdfBits; - return WC_NO_ERR_TRACE(LENGTH_ONLY_E); - } - - if (*olen < (size_t)profile->kdfBits) { - return BUFFER_E; - } - - return wolfSSL_export_keying_material(ssl, out, (size_t)profile->kdfBits, - DTLS_SRTP_KEYING_MATERIAL_LABEL, - XSTR_SIZEOF(DTLS_SRTP_KEYING_MATERIAL_LABEL), NULL, 0, 0); -} - -#endif /* WOLFSSL_SRTP */ - - -#ifdef WOLFSSL_DTLS_DROP_STATS - -int wolfSSL_dtls_get_drop_stats(WOLFSSL* ssl, - word32* macDropCount, word32* replayDropCount) -{ - int ret; - - WOLFSSL_ENTER("wolfSSL_dtls_get_drop_stats"); - - if (ssl == NULL) - ret = BAD_FUNC_ARG; - else { - ret = WOLFSSL_SUCCESS; - if (macDropCount != NULL) - *macDropCount = ssl->macDropCount; - if (replayDropCount != NULL) - *replayDropCount = ssl->replayDropCount; - } - - WOLFSSL_LEAVE("wolfSSL_dtls_get_drop_stats", ret); - return ret; -} - -#endif /* WOLFSSL_DTLS_DROP_STATS */ - - -#if defined(WOLFSSL_MULTICAST) - -int wolfSSL_CTX_mcast_set_member_id(WOLFSSL_CTX* ctx, word16 id) -{ - int ret = 0; - - WOLFSSL_ENTER("wolfSSL_CTX_mcast_set_member_id"); - - if (ctx == NULL || id > WOLFSSL_MAX_8BIT) - ret = BAD_FUNC_ARG; - - if (ret == 0) { - ctx->haveEMS = 0; - ctx->haveMcast = 1; - ctx->mcastID = (byte)id; -#ifndef WOLFSSL_USER_IO - ctx->CBIORecv = EmbedReceiveFromMcast; -#endif /* WOLFSSL_USER_IO */ - - ret = WOLFSSL_SUCCESS; - } - WOLFSSL_LEAVE("wolfSSL_CTX_mcast_set_member_id", ret); - return ret; -} - -int wolfSSL_mcast_get_max_peers(void) -{ - return WOLFSSL_MULTICAST_PEERS; -} - -#ifdef WOLFSSL_DTLS -static WC_INLINE word32 UpdateHighwaterMark(word32 cur, word32 first, - word32 second, word32 high) -{ - word32 newCur = 0; - - if (cur < first) - newCur = first; - else if (cur < second) - newCur = second; - else if (cur < high) - newCur = high; - - return newCur; -} -#endif /* WOLFSSL_DTLS */ - - -int wolfSSL_set_secret(WOLFSSL* ssl, word16 epoch, - const byte* preMasterSecret, word32 preMasterSz, - const byte* clientRandom, const byte* serverRandom, - const byte* suite) -{ - int ret = 0; - - WOLFSSL_ENTER("wolfSSL_set_secret"); - - if (ssl == NULL || preMasterSecret == NULL || - preMasterSz == 0 || preMasterSz > ENCRYPT_LEN || - clientRandom == NULL || serverRandom == NULL || suite == NULL) { - - ret = BAD_FUNC_ARG; - } - - if (ret == 0 && ssl->arrays->preMasterSecret == NULL) { - ssl->arrays->preMasterSz = ENCRYPT_LEN; - ssl->arrays->preMasterSecret = (byte*)XMALLOC(ENCRYPT_LEN, ssl->heap, - DYNAMIC_TYPE_SECRET); - if (ssl->arrays->preMasterSecret == NULL) { - ret = MEMORY_E; - } - } - - if (ret == 0) { - XMEMCPY(ssl->arrays->preMasterSecret, preMasterSecret, preMasterSz); - XMEMSET(ssl->arrays->preMasterSecret + preMasterSz, 0, - ENCRYPT_LEN - preMasterSz); - ssl->arrays->preMasterSz = preMasterSz; - XMEMCPY(ssl->arrays->clientRandom, clientRandom, RAN_LEN); - XMEMCPY(ssl->arrays->serverRandom, serverRandom, RAN_LEN); - ssl->options.cipherSuite0 = suite[0]; - ssl->options.cipherSuite = suite[1]; - - ret = SetCipherSpecs(ssl); - } - - if (ret == 0) - ret = MakeTlsMasterSecret(ssl); - - if (ret == 0) { - ssl->keys.encryptionOn = 1; - ret = SetKeysSide(ssl, ENCRYPT_AND_DECRYPT_SIDE); - } - - if (ret == 0) { - if (ssl->options.dtls) { - #ifdef WOLFSSL_DTLS - WOLFSSL_DTLS_PEERSEQ* peerSeq; - int i; - - ssl->keys.dtls_epoch = epoch; - for (i = 0, peerSeq = ssl->keys.peerSeq; - i < WOLFSSL_DTLS_PEERSEQ_SZ; - i++, peerSeq++) { - - peerSeq->nextEpoch = epoch; - peerSeq->prevSeq_lo = peerSeq->nextSeq_lo; - peerSeq->prevSeq_hi = peerSeq->nextSeq_hi; - peerSeq->nextSeq_lo = 0; - peerSeq->nextSeq_hi = 0; - XMEMCPY(peerSeq->prevWindow, peerSeq->window, DTLS_SEQ_SZ); - XMEMSET(peerSeq->window, 0, DTLS_SEQ_SZ); - peerSeq->highwaterMark = UpdateHighwaterMark(0, - ssl->ctx->mcastFirstSeq, - ssl->ctx->mcastSecondSeq, - ssl->ctx->mcastMaxSeq); - } - #else - (void)epoch; - #endif - } - FreeHandshakeResources(ssl); - ret = WOLFSSL_SUCCESS; - } - else { - if (ssl) - ssl->error = ret; - ret = WOLFSSL_FATAL_ERROR; - } - WOLFSSL_LEAVE("wolfSSL_set_secret", ret); - return ret; -} - - -#ifdef WOLFSSL_DTLS - -int wolfSSL_mcast_peer_add(WOLFSSL* ssl, word16 peerId, int sub) -{ - WOLFSSL_DTLS_PEERSEQ* p = NULL; - int ret = WOLFSSL_SUCCESS; - int i; - - WOLFSSL_ENTER("wolfSSL_mcast_peer_add"); - if (ssl == NULL || peerId > WOLFSSL_MAX_8BIT) - return BAD_FUNC_ARG; - - if (!sub) { - /* Make sure it isn't already present, while keeping the first - * open spot. */ - for (i = 0; i < WOLFSSL_DTLS_PEERSEQ_SZ; i++) { - if (ssl->keys.peerSeq[i].peerId == INVALID_PEER_ID) - p = &ssl->keys.peerSeq[i]; - if (ssl->keys.peerSeq[i].peerId == peerId) { - WOLFSSL_MSG("Peer ID already in multicast peer list."); - p = NULL; - } - } - - if (p != NULL) { - XMEMSET(p, 0, sizeof(WOLFSSL_DTLS_PEERSEQ)); - p->peerId = peerId; - p->highwaterMark = UpdateHighwaterMark(0, - ssl->ctx->mcastFirstSeq, - ssl->ctx->mcastSecondSeq, - ssl->ctx->mcastMaxSeq); - } - else { - WOLFSSL_MSG("No room in peer list."); - ret = WOLFSSL_FATAL_ERROR; - } - } - else { - for (i = 0; i < WOLFSSL_DTLS_PEERSEQ_SZ; i++) { - if (ssl->keys.peerSeq[i].peerId == peerId) - p = &ssl->keys.peerSeq[i]; - } - - if (p != NULL) { - p->peerId = INVALID_PEER_ID; - } - else { - WOLFSSL_MSG("Peer not found in list."); - } - } - - WOLFSSL_LEAVE("wolfSSL_mcast_peer_add", ret); - return ret; -} - - -/* If peerId is in the list of peers and its last sequence number is non-zero, - * return 1, otherwise return 0. */ -int wolfSSL_mcast_peer_known(WOLFSSL* ssl, unsigned short peerId) -{ - int known = 0; - int i; - - WOLFSSL_ENTER("wolfSSL_mcast_peer_known"); - - if (ssl == NULL || peerId > WOLFSSL_MAX_8BIT) { - return BAD_FUNC_ARG; - } - - for (i = 0; i < WOLFSSL_DTLS_PEERSEQ_SZ; i++) { - if (ssl->keys.peerSeq[i].peerId == peerId) { - if (ssl->keys.peerSeq[i].nextSeq_hi || - ssl->keys.peerSeq[i].nextSeq_lo) { - - known = 1; - } - break; - } - } - - WOLFSSL_LEAVE("wolfSSL_mcast_peer_known", known); - return known; -} - - -int wolfSSL_CTX_mcast_set_highwater_cb(WOLFSSL_CTX* ctx, word32 maxSeq, - word32 first, word32 second, - CallbackMcastHighwater cb) -{ - if (ctx == NULL || (second && first > second) || - first > maxSeq || second > maxSeq || cb == NULL) { - - return BAD_FUNC_ARG; - } - - ctx->mcastHwCb = cb; - ctx->mcastFirstSeq = first; - ctx->mcastSecondSeq = second; - ctx->mcastMaxSeq = maxSeq; - - return WOLFSSL_SUCCESS; -} - - -int wolfSSL_mcast_set_highwater_ctx(WOLFSSL* ssl, void* ctx) -{ - if (ssl == NULL || ctx == NULL) - return BAD_FUNC_ARG; - - ssl->mcastHwCbCtx = ctx; - - return WOLFSSL_SUCCESS; -} - -#endif /* WOLFSSL_DTLS */ - -#endif /* WOLFSSL_MULTICAST */ - - -#endif /* WOLFSSL_LEANPSK */ #ifndef NO_TLS /* return underlying connect or accept, WOLFSSL_SUCCESS on ok */ @@ -2369,218 +1621,6 @@ int wolfSSL_GetOutputSize(WOLFSSL* ssl, int inSz) } -#ifdef HAVE_ECC -int wolfSSL_CTX_SetMinEccKey_Sz(WOLFSSL_CTX* ctx, short keySz) -{ - short keySzBytes; - - WOLFSSL_ENTER("wolfSSL_CTX_SetMinEccKey_Sz"); - if (ctx == NULL || keySz < 0) { - WOLFSSL_MSG("Key size must be positive value or ctx was null"); - return BAD_FUNC_ARG; - } - - if (keySz % 8 == 0) { - keySzBytes = keySz / 8; - } - else { - keySzBytes = (keySz / 8) + 1; - } - -#if defined(WOLFSSL_SYS_CRYPTO_POLICY) - if (crypto_policy.enabled) { - if (ctx->minEccKeySz > (keySzBytes)) { - return CRYPTO_POLICY_FORBIDDEN; - } - } -#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - - ctx->minEccKeySz = keySzBytes; -#ifndef NO_CERTS - ctx->cm->minEccKeySz = keySzBytes; -#endif - return WOLFSSL_SUCCESS; -} - - -int wolfSSL_SetMinEccKey_Sz(WOLFSSL* ssl, short keySz) -{ - short keySzBytes; - - WOLFSSL_ENTER("wolfSSL_SetMinEccKey_Sz"); - if (ssl == NULL || keySz < 0) { - WOLFSSL_MSG("Key size must be positive value or ctx was null"); - return BAD_FUNC_ARG; - } - - if (keySz % 8 == 0) { - keySzBytes = keySz / 8; - } - else { - keySzBytes = (keySz / 8) + 1; - } - -#if defined(WOLFSSL_SYS_CRYPTO_POLICY) - if (crypto_policy.enabled) { - if (ssl->options.minEccKeySz > (keySzBytes)) { - return CRYPTO_POLICY_FORBIDDEN; - } - } -#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - - ssl->options.minEccKeySz = keySzBytes; - return WOLFSSL_SUCCESS; -} - -#endif /* HAVE_ECC */ - -#ifndef NO_RSA -int wolfSSL_CTX_SetMinRsaKey_Sz(WOLFSSL_CTX* ctx, short keySz) -{ - if (ctx == NULL || keySz < 0 || keySz % 8 != 0) { - WOLFSSL_MSG("Key size must be divisible by 8 or ctx was null"); - return BAD_FUNC_ARG; - } - -#if defined(WOLFSSL_SYS_CRYPTO_POLICY) - if (crypto_policy.enabled) { - if (ctx->minRsaKeySz > (keySz / 8)) { - return CRYPTO_POLICY_FORBIDDEN; - } - } -#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - - ctx->minRsaKeySz = keySz / 8; - ctx->cm->minRsaKeySz = keySz / 8; - return WOLFSSL_SUCCESS; -} - - -int wolfSSL_SetMinRsaKey_Sz(WOLFSSL* ssl, short keySz) -{ - if (ssl == NULL || keySz < 0 || keySz % 8 != 0) { - WOLFSSL_MSG("Key size must be divisible by 8 or ssl was null"); - return BAD_FUNC_ARG; - } - -#if defined(WOLFSSL_SYS_CRYPTO_POLICY) - if (crypto_policy.enabled) { - if (ssl->options.minRsaKeySz > (keySz / 8)) { - return CRYPTO_POLICY_FORBIDDEN; - } - } -#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - - ssl->options.minRsaKeySz = keySz / 8; - return WOLFSSL_SUCCESS; -} -#endif /* !NO_RSA */ - -#ifndef NO_DH - -#if !defined(WOLFSSL_OLD_PRIME_CHECK) && !defined(HAVE_FIPS) && \ - !defined(HAVE_SELFTEST) -/* Enables or disables the session's DH key prime test. */ -int wolfSSL_SetEnableDhKeyTest(WOLFSSL* ssl, int enable) -{ - WOLFSSL_ENTER("wolfSSL_SetEnableDhKeyTest"); - - if (ssl == NULL) - return BAD_FUNC_ARG; - - if (!enable) - ssl->options.dhDoKeyTest = 0; - else - ssl->options.dhDoKeyTest = 1; - - WOLFSSL_LEAVE("wolfSSL_SetEnableDhKeyTest", WOLFSSL_SUCCESS); - return WOLFSSL_SUCCESS; -} -#endif - -int wolfSSL_CTX_SetMinDhKey_Sz(WOLFSSL_CTX* ctx, word16 keySz_bits) -{ - if (ctx == NULL || keySz_bits > 16000 || keySz_bits % 8 != 0) - return BAD_FUNC_ARG; - -#if defined(WOLFSSL_SYS_CRYPTO_POLICY) - if (crypto_policy.enabled) { - if (ctx->minDhKeySz > (keySz_bits / 8)) { - return CRYPTO_POLICY_FORBIDDEN; - } - } -#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - - ctx->minDhKeySz = keySz_bits / 8; - return WOLFSSL_SUCCESS; -} - - -int wolfSSL_SetMinDhKey_Sz(WOLFSSL* ssl, word16 keySz_bits) -{ - if (ssl == NULL || keySz_bits > 16000 || keySz_bits % 8 != 0) - return BAD_FUNC_ARG; - -#if defined(WOLFSSL_SYS_CRYPTO_POLICY) - if (crypto_policy.enabled) { - if (ssl->options.minDhKeySz > (keySz_bits / 8)) { - return CRYPTO_POLICY_FORBIDDEN; - } - } -#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - - ssl->options.minDhKeySz = keySz_bits / 8; - return WOLFSSL_SUCCESS; -} - - -int wolfSSL_CTX_SetMaxDhKey_Sz(WOLFSSL_CTX* ctx, word16 keySz_bits) -{ - if (ctx == NULL || keySz_bits > 16000 || keySz_bits % 8 != 0) - return BAD_FUNC_ARG; - -#if defined(WOLFSSL_SYS_CRYPTO_POLICY) - if (crypto_policy.enabled) { - if (ctx->minDhKeySz > (keySz_bits / 8)) { - return CRYPTO_POLICY_FORBIDDEN; - } - } -#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - - ctx->maxDhKeySz = keySz_bits / 8; - return WOLFSSL_SUCCESS; -} - - -int wolfSSL_SetMaxDhKey_Sz(WOLFSSL* ssl, word16 keySz_bits) -{ - if (ssl == NULL || keySz_bits > 16000 || keySz_bits % 8 != 0) - return BAD_FUNC_ARG; - -#if defined(WOLFSSL_SYS_CRYPTO_POLICY) - if (crypto_policy.enabled) { - if (ssl->options.minDhKeySz > (keySz_bits / 8)) { - return CRYPTO_POLICY_FORBIDDEN; - } - } -#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - - ssl->options.maxDhKeySz = keySz_bits / 8; - return WOLFSSL_SUCCESS; -} - - -int wolfSSL_GetDhKey_Sz(WOLFSSL* ssl) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - - return (ssl->options.dhKeySz * 8); -} - -#endif /* !NO_DH */ - - static int wolfSSL_write_internal(WOLFSSL* ssl, const void* data, size_t sz) { int ret = 0; @@ -2977,26 +2017,11 @@ int wolfSSL_read_ex(WOLFSSL* ssl, void* data, size_t sz, size_t* rd) return ret > 0 ? 1 : 0; } -#ifdef WOLFSSL_MULTICAST - -int wolfSSL_mcast_read(WOLFSSL* ssl, word16* id, void* data, int sz) -{ - int ret = 0; - - WOLFSSL_ENTER("wolfSSL_mcast_read"); - - if ((ssl == NULL) || (sz < 0)) - return BAD_FUNC_ARG; - - ret = wolfSSL_read_internal(ssl, data, (size_t)sz, FALSE); - if (ssl->options.dtls && ssl->options.haveMcast && id != NULL) - *id = ssl->keys.curPeerId; - return ret; -} - -#endif /* WOLFSSL_MULTICAST */ #endif /* !NO_TLS */ +#define WOLFSSL_SSL_API_DTLS_INCLUDED +#include "src/ssl_api_dtls.c" + /* helpers to set the device id, WOLFSSL_SUCCESS on ok */ WOLFSSL_ABI int wolfSSL_SetDevId(WOLFSSL* ssl, int devId) @@ -3043,934 +2068,6 @@ void* wolfSSL_CTX_GetHeap(WOLFSSL_CTX* ctx, WOLFSSL* ssl) #ifndef NO_TLS -#ifdef HAVE_SNI - -WOLFSSL_ABI -int wolfSSL_UseSNI(WOLFSSL* ssl, byte type, const void* data, word16 size) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - - return TLSX_UseSNI(&ssl->extensions, type, data, size, ssl->heap); -} - - -WOLFSSL_ABI -int wolfSSL_CTX_UseSNI(WOLFSSL_CTX* ctx, byte type, const void* data, - word16 size) -{ - if (ctx == NULL) - return BAD_FUNC_ARG; - - return TLSX_UseSNI(&ctx->extensions, type, data, size, ctx->heap); -} - -#ifndef NO_WOLFSSL_SERVER - -void wolfSSL_SNI_SetOptions(WOLFSSL* ssl, byte type, byte options) -{ - if (ssl && ssl->extensions) - TLSX_SNI_SetOptions(ssl->extensions, type, options); -} - - -void wolfSSL_CTX_SNI_SetOptions(WOLFSSL_CTX* ctx, byte type, byte options) -{ - if (ctx && ctx->extensions) - TLSX_SNI_SetOptions(ctx->extensions, type, options); -} - - -byte wolfSSL_SNI_Status(WOLFSSL* ssl, byte type) -{ - return TLSX_SNI_Status(ssl ? ssl->extensions : NULL, type); -} - - -word16 wolfSSL_SNI_GetRequest(WOLFSSL* ssl, byte type, void** data) -{ - if (data) - *data = NULL; - - if (ssl && ssl->extensions) - return TLSX_SNI_GetRequest(ssl->extensions, type, data, 0); - - return 0; -} - - -int wolfSSL_SNI_GetFromBuffer(const byte* clientHello, word32 helloSz, - byte type, byte* sni, word32* inOutSz) -{ - if (clientHello && helloSz > 0 && sni && inOutSz && *inOutSz > 0) - return TLSX_SNI_GetFromBuffer(clientHello, helloSz, type, sni, inOutSz); - - return BAD_FUNC_ARG; -} - -#endif /* !NO_WOLFSSL_SERVER */ - -#endif /* HAVE_SNI */ - - -#ifdef HAVE_TRUSTED_CA - -int wolfSSL_UseTrustedCA(WOLFSSL* ssl, byte type, - const byte* certId, word32 certIdSz) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - - if (type == WOLFSSL_TRUSTED_CA_PRE_AGREED) { - if (certId != NULL || certIdSz != 0) - return BAD_FUNC_ARG; - } - else if (type == WOLFSSL_TRUSTED_CA_X509_NAME) { - if (certId == NULL || certIdSz == 0) - return BAD_FUNC_ARG; - } - #ifndef NO_SHA - else if (type == WOLFSSL_TRUSTED_CA_KEY_SHA1 || - type == WOLFSSL_TRUSTED_CA_CERT_SHA1) { - if (certId == NULL || certIdSz != WC_SHA_DIGEST_SIZE) - return BAD_FUNC_ARG; - } - #endif - else - return BAD_FUNC_ARG; - - return TLSX_UseTrustedCA(&ssl->extensions, - type, certId, certIdSz, ssl->heap); -} - -#endif /* HAVE_TRUSTED_CA */ - - -#ifdef HAVE_MAX_FRAGMENT -#ifndef NO_WOLFSSL_CLIENT - -int wolfSSL_UseMaxFragment(WOLFSSL* ssl, byte mfl) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - -#ifdef WOLFSSL_ALLOW_MAX_FRAGMENT_ADJUST - /* The following is a non-standard way to reconfigure the max packet size - post-handshake for wolfSSL_write/wolfSSL_read */ - if (ssl->options.handShakeState == HANDSHAKE_DONE) { - switch (mfl) { - case WOLFSSL_MFL_2_8 : ssl->max_fragment = 256; break; - case WOLFSSL_MFL_2_9 : ssl->max_fragment = 512; break; - case WOLFSSL_MFL_2_10: ssl->max_fragment = 1024; break; - case WOLFSSL_MFL_2_11: ssl->max_fragment = 2048; break; - case WOLFSSL_MFL_2_12: ssl->max_fragment = 4096; break; - case WOLFSSL_MFL_2_13: ssl->max_fragment = 8192; break; - default: ssl->max_fragment = MAX_RECORD_SIZE; break; - } - return WOLFSSL_SUCCESS; - } -#endif /* WOLFSSL_MAX_FRAGMENT_ADJUST */ - - /* This call sets the max fragment TLS extension, which gets sent to server. - The server_hello response is what sets the `ssl->max_fragment` in - TLSX_MFL_Parse */ - return TLSX_UseMaxFragment(&ssl->extensions, mfl, ssl->heap); -} - - -int wolfSSL_CTX_UseMaxFragment(WOLFSSL_CTX* ctx, byte mfl) -{ - if (ctx == NULL) - return BAD_FUNC_ARG; - - return TLSX_UseMaxFragment(&ctx->extensions, mfl, ctx->heap); -} - -#endif /* NO_WOLFSSL_CLIENT */ -#endif /* HAVE_MAX_FRAGMENT */ - -#ifdef HAVE_TRUNCATED_HMAC -#ifndef NO_WOLFSSL_CLIENT - -int wolfSSL_UseTruncatedHMAC(WOLFSSL* ssl) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - - return TLSX_UseTruncatedHMAC(&ssl->extensions, ssl->heap); -} - - -int wolfSSL_CTX_UseTruncatedHMAC(WOLFSSL_CTX* ctx) -{ - if (ctx == NULL) - return BAD_FUNC_ARG; - - return TLSX_UseTruncatedHMAC(&ctx->extensions, ctx->heap); -} - -#endif /* NO_WOLFSSL_CLIENT */ -#endif /* HAVE_TRUNCATED_HMAC */ - -/* Elliptic Curves */ -#if defined(HAVE_SUPPORTED_CURVES) - -static int isValidCurveGroup(word16 name) -{ - switch (name) { - case WOLFSSL_ECC_SECP160K1: - case WOLFSSL_ECC_SECP160R1: - case WOLFSSL_ECC_SECP160R2: - case WOLFSSL_ECC_SECP192K1: - case WOLFSSL_ECC_SECP192R1: - case WOLFSSL_ECC_SECP224K1: - case WOLFSSL_ECC_SECP224R1: - case WOLFSSL_ECC_SECP256K1: - case WOLFSSL_ECC_SECP256R1: - case WOLFSSL_ECC_SECP384R1: - case WOLFSSL_ECC_SECP521R1: - case WOLFSSL_ECC_BRAINPOOLP256R1: - case WOLFSSL_ECC_BRAINPOOLP384R1: - case WOLFSSL_ECC_BRAINPOOLP512R1: - case WOLFSSL_ECC_SM2P256V1: - case WOLFSSL_ECC_X25519: - case WOLFSSL_ECC_X448: - case WOLFSSL_ECC_BRAINPOOLP256R1TLS13: - case WOLFSSL_ECC_BRAINPOOLP384R1TLS13: - case WOLFSSL_ECC_BRAINPOOLP512R1TLS13: - - case WOLFSSL_FFDHE_2048: - case WOLFSSL_FFDHE_3072: - case WOLFSSL_FFDHE_4096: - case WOLFSSL_FFDHE_6144: - case WOLFSSL_FFDHE_8192: - -#ifdef WOLFSSL_HAVE_MLKEM -#ifndef WOLFSSL_NO_ML_KEM - #ifndef WOLFSSL_TLS_NO_MLKEM_STANDALONE - case WOLFSSL_ML_KEM_512: - case WOLFSSL_ML_KEM_768: - case WOLFSSL_ML_KEM_1024: - #endif /* !WOLFSSL_TLS_NO_MLKEM_STANDALONE */ - #ifdef WOLFSSL_PQC_HYBRIDS - case WOLFSSL_SECP384R1MLKEM1024: - case WOLFSSL_X25519MLKEM768: - case WOLFSSL_SECP256R1MLKEM768: - #endif /* WOLFSSL_PQC_HYBRIDS */ - #ifdef WOLFSSL_EXTRA_PQC_HYBRIDS - case WOLFSSL_SECP256R1MLKEM512: - case WOLFSSL_SECP384R1MLKEM768: - case WOLFSSL_SECP521R1MLKEM1024: - case WOLFSSL_X25519MLKEM512: - case WOLFSSL_X448MLKEM768: - #endif /* WOLFSSL_EXTRA_PQC_HYBRIDS */ -#endif /* !WOLFSSL_NO_ML_KEM */ -#ifdef WOLFSSL_MLKEM_KYBER - case WOLFSSL_KYBER_LEVEL1: - case WOLFSSL_KYBER_LEVEL3: - case WOLFSSL_KYBER_LEVEL5: - case WOLFSSL_P256_KYBER_LEVEL1: - case WOLFSSL_P384_KYBER_LEVEL3: - case WOLFSSL_P521_KYBER_LEVEL5: - case WOLFSSL_X25519_KYBER_LEVEL1: - case WOLFSSL_X448_KYBER_LEVEL3: - case WOLFSSL_X25519_KYBER_LEVEL3: - case WOLFSSL_P256_KYBER_LEVEL3: -#endif /* WOLFSSL_MLKEM_KYBER */ -#endif - return 1; - - default: - return 0; - } -} - -int wolfSSL_UseSupportedCurve(WOLFSSL* ssl, word16 name) -{ - if (ssl == NULL || !isValidCurveGroup(name)) - return BAD_FUNC_ARG; - - ssl->options.userCurves = 1; -#if defined(NO_TLS) - return WOLFSSL_FAILURE; -#else - return TLSX_UseSupportedCurve(&ssl->extensions, name, ssl->heap); -#endif /* NO_TLS */ -} - - -int wolfSSL_CTX_UseSupportedCurve(WOLFSSL_CTX* ctx, word16 name) -{ - if (ctx == NULL || !isValidCurveGroup(name)) - return BAD_FUNC_ARG; - - ctx->userCurves = 1; -#if defined(NO_TLS) - return WOLFSSL_FAILURE; -#else - return TLSX_UseSupportedCurve(&ctx->extensions, name, ctx->heap); -#endif /* NO_TLS */ -} - -#if defined(OPENSSL_EXTRA) -int wolfSSL_CTX_set1_groups(WOLFSSL_CTX* ctx, int* groups, - int count) -{ - int i; - int _groups[WOLFSSL_MAX_GROUP_COUNT]; - WOLFSSL_ENTER("wolfSSL_CTX_set1_groups"); - if (count == 0) { - WOLFSSL_MSG("Group count is zero"); - return WOLFSSL_FAILURE; - } - if (count > WOLFSSL_MAX_GROUP_COUNT) { - WOLFSSL_MSG("Group count exceeds maximum"); - return WOLFSSL_FAILURE; - } - for (i = 0; i < count; i++) { - if (isValidCurveGroup((word16)groups[i])) { - _groups[i] = groups[i]; - } -#ifdef HAVE_ECC - else { - /* groups may be populated with curve NIDs */ - int oid = (int)nid2oid(groups[i], oidCurveType); - int name = (int)GetCurveByOID(oid); - if (name == 0) { - WOLFSSL_MSG("Invalid group name"); - return WOLFSSL_FAILURE; - } - _groups[i] = name; - } -#else - else { - WOLFSSL_MSG("Invalid group name"); - return WOLFSSL_FAILURE; - } -#endif - } - return wolfSSL_CTX_set_groups(ctx, _groups, count) == WOLFSSL_SUCCESS ? - WOLFSSL_SUCCESS : WOLFSSL_FAILURE; -} - -int wolfSSL_set1_groups(WOLFSSL* ssl, int* groups, int count) -{ - int i; - int _groups[WOLFSSL_MAX_GROUP_COUNT]; - WOLFSSL_ENTER("wolfSSL_CTX_set1_groups"); - if (count == 0) { - WOLFSSL_MSG("Group count is zero"); - return WOLFSSL_FAILURE; - } - if (count > WOLFSSL_MAX_GROUP_COUNT) { - WOLFSSL_MSG("Group count exceeds maximum"); - return WOLFSSL_FAILURE; - } - for (i = 0; i < count; i++) { - if (isValidCurveGroup((word16)groups[i])) { - _groups[i] = groups[i]; - } -#ifdef HAVE_ECC - else { - /* groups may be populated with curve NIDs */ - int oid = (int)nid2oid(groups[i], oidCurveType); - int name = (int)GetCurveByOID(oid); - if (name == 0) { - WOLFSSL_MSG("Invalid group name"); - return WOLFSSL_FAILURE; - } - _groups[i] = name; - } -#else - else { - WOLFSSL_MSG("Invalid group name"); - return WOLFSSL_FAILURE; - } -#endif - } - return wolfSSL_set_groups(ssl, _groups, count) == WOLFSSL_SUCCESS ? - WOLFSSL_SUCCESS : WOLFSSL_FAILURE; -} -#endif /* OPENSSL_EXTRA */ -#endif /* HAVE_SUPPORTED_CURVES */ - -/* Application-Layer Protocol Negotiation */ -#ifdef HAVE_ALPN - -WOLFSSL_ABI -int wolfSSL_UseALPN(WOLFSSL* ssl, char *protocol_name_list, - word32 protocol_name_listSz, byte options) -{ - char *list, *ptr = NULL, **token; - word16 len; - int idx = 0; - int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); - - WOLFSSL_ENTER("wolfSSL_UseALPN"); - - if (ssl == NULL || protocol_name_list == NULL) - return BAD_FUNC_ARG; - - if (protocol_name_listSz > (WOLFSSL_MAX_ALPN_NUMBER * - WOLFSSL_MAX_ALPN_PROTO_NAME_LEN + - WOLFSSL_MAX_ALPN_NUMBER)) { - WOLFSSL_MSG("Invalid arguments, protocol name list too long"); - return BAD_FUNC_ARG; - } - - if (!(options & WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) && - !(options & WOLFSSL_ALPN_FAILED_ON_MISMATCH)) { - WOLFSSL_MSG("Invalid arguments, options not supported"); - return BAD_FUNC_ARG; - } - - - list = (char *)XMALLOC(protocol_name_listSz+1, ssl->heap, - DYNAMIC_TYPE_ALPN); - if (list == NULL) { - WOLFSSL_MSG("Memory failure"); - return MEMORY_ERROR; - } - - token = (char **)XMALLOC(sizeof(char *) * (WOLFSSL_MAX_ALPN_NUMBER+1), - ssl->heap, DYNAMIC_TYPE_ALPN); - if (token == NULL) { - XFREE(list, ssl->heap, DYNAMIC_TYPE_ALPN); - WOLFSSL_MSG("Memory failure"); - return MEMORY_ERROR; - } - XMEMSET(token, 0, sizeof(char *) * (WOLFSSL_MAX_ALPN_NUMBER+1)); - - XSTRNCPY(list, protocol_name_list, protocol_name_listSz); - list[protocol_name_listSz] = '\0'; - - /* read all protocol name from the list */ - token[idx] = XSTRTOK(list, ",", &ptr); - while (idx < WOLFSSL_MAX_ALPN_NUMBER && token[idx] != NULL) - token[++idx] = XSTRTOK(NULL, ",", &ptr); - - /* add protocol name list in the TLS extension in reverse order */ - while ((idx--) > 0) { - len = (word16)XSTRLEN(token[idx]); - - ret = TLSX_UseALPN(&ssl->extensions, token[idx], len, options, - ssl->heap); - if (ret != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("TLSX_UseALPN failure"); - break; - } - } - - XFREE(token, ssl->heap, DYNAMIC_TYPE_ALPN); - XFREE(list, ssl->heap, DYNAMIC_TYPE_ALPN); - - return ret; -} - -int wolfSSL_ALPN_GetProtocol(WOLFSSL* ssl, char **protocol_name, word16 *size) -{ - return TLSX_ALPN_GetRequest(ssl ? ssl->extensions : NULL, - (void **)protocol_name, size); -} - -int wolfSSL_ALPN_GetPeerProtocol(WOLFSSL* ssl, char **list, word16 *listSz) -{ - int i, len; - char *p; - byte *s; - - if (ssl == NULL || list == NULL || listSz == NULL) - return BAD_FUNC_ARG; - - if (ssl->alpn_peer_requested == NULL - || ssl->alpn_peer_requested_length == 0) - return BUFFER_ERROR; - - /* ssl->alpn_peer_requested are the original bytes sent in a ClientHello, - * formatted as (len-byte chars+)+. To turn n protocols into a - * comma-separated C string, one needs (n-1) commas and a final 0 byte - * which has the same length as the original. - * The returned length is the strlen() of the C string, so -1 of that. */ - *listSz = ssl->alpn_peer_requested_length-1; - *list = p = (char *)XMALLOC(ssl->alpn_peer_requested_length, ssl->heap, - DYNAMIC_TYPE_TLSX); - if (p == NULL) - return MEMORY_ERROR; - - for (i = 0, s = ssl->alpn_peer_requested; - i < ssl->alpn_peer_requested_length; - p += len, i += len) - { - if (i) - *p++ = ','; - len = s[i++]; - /* guard against bad length bytes. */ - if (i + len > ssl->alpn_peer_requested_length) { - XFREE(*list, ssl->heap, DYNAMIC_TYPE_TLSX); - *list = NULL; - return WOLFSSL_FAILURE; - } - XMEMCPY(p, s + i, (size_t)len); - } - *p = 0; - - return WOLFSSL_SUCCESS; -} - - -/* used to free memory allocated by wolfSSL_ALPN_GetPeerProtocol */ -int wolfSSL_ALPN_FreePeerProtocol(WOLFSSL* ssl, char **list) -{ - if (ssl == NULL) { - return BAD_FUNC_ARG; - } - - XFREE(*list, ssl->heap, DYNAMIC_TYPE_TLSX); - *list = NULL; - - return WOLFSSL_SUCCESS; -} - -#endif /* HAVE_ALPN */ - -/* Secure Renegotiation */ -#ifdef HAVE_SERVER_RENEGOTIATION_INFO - -/* user is forcing ability to use secure renegotiation, we discourage it */ -int wolfSSL_UseSecureRenegotiation(WOLFSSL* ssl) -{ - int ret = WC_NO_ERR_TRACE(BAD_FUNC_ARG); -#if defined(NO_TLS) - (void)ssl; -#else - if (ssl) - ret = TLSX_UseSecureRenegotiation(&ssl->extensions, ssl->heap); - else - ret = BAD_FUNC_ARG; - - if (ret == WOLFSSL_SUCCESS) { - TLSX* extension = TLSX_Find(ssl->extensions, TLSX_RENEGOTIATION_INFO); - - if (extension) - ssl->secure_renegotiation = (SecureRenegotiation*)extension->data; - } -#endif /* !NO_TLS */ - return ret; -} - -int wolfSSL_CTX_UseSecureRenegotiation(WOLFSSL_CTX* ctx) -{ - if (ctx == NULL) - return BAD_FUNC_ARG; - - ctx->useSecureReneg = 1; - return WOLFSSL_SUCCESS; -} - -#ifdef HAVE_SECURE_RENEGOTIATION -/* do a secure renegotiation handshake, user forced, we discourage */ -static int _Rehandshake(WOLFSSL* ssl) -{ - int ret; - - if (ssl == NULL) - return BAD_FUNC_ARG; - - if (IsAtLeastTLSv1_3(ssl->version)) { - WOLFSSL_MSG("Secure Renegotiation not supported in TLS 1.3"); - return SECURE_RENEGOTIATION_E; - } - - if (ssl->secure_renegotiation == NULL) { - WOLFSSL_MSG("Secure Renegotiation not forced on by user"); - return SECURE_RENEGOTIATION_E; - } - - if (ssl->secure_renegotiation->enabled == 0) { - WOLFSSL_MSG("Secure Renegotiation not enabled at extension level"); - return SECURE_RENEGOTIATION_E; - } - -#ifdef WOLFSSL_DTLS - if (ssl->options.dtls && ssl->keys.dtls_epoch == 0xFFFF) { - WOLFSSL_MSG("Secure Renegotiation not allowed. Epoch would wrap"); - return SECURE_RENEGOTIATION_E; - } -#endif - - /* If the client started the renegotiation, the server will already - * have processed the client's hello. */ - if (ssl->options.side != WOLFSSL_SERVER_END || - ssl->options.acceptState != ACCEPT_FIRST_REPLY_DONE) { - - if (ssl->options.handShakeState != HANDSHAKE_DONE) { - if (!ssl->options.handShakeDone) { - WOLFSSL_MSG("Can't renegotiate until initial " - "handshake complete"); - return SECURE_RENEGOTIATION_E; - } - else { - WOLFSSL_MSG("Renegotiation already started. " - "Moving it forward."); - ret = wolfSSL_negotiate(ssl); - if (ret == WOLFSSL_SUCCESS) - ssl->secure_rene_count++; - return ret; - } - } - - /* reset handshake states */ - ssl->options.sendVerify = 0; - ssl->options.serverState = NULL_STATE; - ssl->options.clientState = NULL_STATE; - ssl->options.connectState = CONNECT_BEGIN; - ssl->options.acceptState = ACCEPT_BEGIN_RENEG; - ssl->options.handShakeState = NULL_STATE; - ssl->options.processReply = 0; /* TODO, move states in internal.h */ - - XMEMSET(&ssl->msgsReceived, 0, sizeof(ssl->msgsReceived)); - - ssl->secure_renegotiation->cache_status = SCR_CACHE_NEEDED; - -#if !defined(NO_WOLFSSL_SERVER) && !defined(WOLFSSL_NO_TLS12) - if (ssl->options.side == WOLFSSL_SERVER_END) { - ret = SendHelloRequest(ssl); - if (ret != 0) { - ssl->error = ret; - return WOLFSSL_FATAL_ERROR; - } - } -#endif /* !NO_WOLFSSL_SERVER && !WOLFSSL_NO_TLS12 */ - - ret = InitHandshakeHashes(ssl); - if (ret != 0) { - ssl->error = ret; - return WOLFSSL_FATAL_ERROR; - } - } - ret = wolfSSL_negotiate(ssl); - if (ret == WOLFSSL_SUCCESS) - ssl->secure_rene_count++; - return ret; -} - - -/* do a secure renegotiation handshake, user forced, we discourage */ -int wolfSSL_Rehandshake(WOLFSSL* ssl) -{ - int ret; - WOLFSSL_ENTER("wolfSSL_Rehandshake"); - - if (ssl == NULL) - return WOLFSSL_FAILURE; - -#ifdef HAVE_SESSION_TICKET - ret = WOLFSSL_SUCCESS; -#endif - - if (ssl->options.side == WOLFSSL_SERVER_END) { - /* Reset option to send certificate verify. */ - ssl->options.sendVerify = 0; - /* Reset resuming flag to do full secure handshake. */ - ssl->options.resuming = 0; - } - else { - /* Reset resuming flag to do full secure handshake. */ - ssl->options.resuming = 0; - #if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_CLIENT) - /* Clearing the ticket. */ - ret = wolfSSL_UseSessionTicket(ssl); - #endif - } - /* CLIENT/SERVER: Reset peer authentication for full secure handshake. */ - ssl->options.peerAuthGood = 0; - -#ifdef HAVE_SESSION_TICKET - if (ret == WOLFSSL_SUCCESS) -#endif - ret = _Rehandshake(ssl); - - return ret; -} - - -#ifndef NO_WOLFSSL_CLIENT - -/* do a secure resumption handshake, user forced, we discourage */ -int wolfSSL_SecureResume(WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_SecureResume"); - - if (ssl == NULL) - return BAD_FUNC_ARG; - - if (ssl->options.side == WOLFSSL_SERVER_END) { - ssl->error = SIDE_ERROR; - return WOLFSSL_FATAL_ERROR; - } - - return _Rehandshake(ssl); -} - -#endif /* NO_WOLFSSL_CLIENT */ - -#endif /* HAVE_SECURE_RENEGOTIATION */ - -long wolfSSL_SSL_get_secure_renegotiation_support(WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_SSL_get_secure_renegotiation_support"); - - if (!ssl || !ssl->secure_renegotiation) - return WOLFSSL_FAILURE; - return ssl->secure_renegotiation->enabled; -} - -#endif /* HAVE_SECURE_RENEGOTIATION_INFO */ - -#if !defined(NO_WOLFSSL_CLIENT) && !defined(WOLFSSL_NO_TLS12) && \ - defined(WOLFSSL_HARDEN_TLS) && !defined(WOLFSSL_HARDEN_TLS_NO_SCR_CHECK) -WOLFSSL_API int wolfSSL_get_scr_check_enabled(const WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_get_scr_check_enabled"); - - if (ssl == NULL) - return BAD_FUNC_ARG; - - return ssl->scr_check_enabled; -} - -WOLFSSL_API int wolfSSL_set_scr_check_enabled(WOLFSSL* ssl, byte enabled) -{ - WOLFSSL_ENTER("wolfSSL_set_scr_check_enabled"); - - if (ssl == NULL) - return BAD_FUNC_ARG; - - ssl->scr_check_enabled = !!enabled; - return WOLFSSL_SUCCESS; -} -#endif - -#if defined(HAVE_SESSION_TICKET) -/* Session Ticket */ - -#if !defined(NO_WOLFSSL_SERVER) -int wolfSSL_CTX_NoTicketTLSv12(WOLFSSL_CTX* ctx) -{ - if (ctx == NULL) - return BAD_FUNC_ARG; - - ctx->noTicketTls12 = 1; - - return WOLFSSL_SUCCESS; -} - -int wolfSSL_NoTicketTLSv12(WOLFSSL* ssl) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - - ssl->options.noTicketTls12 = 1; - - return WOLFSSL_SUCCESS; -} - -/* WOLFSSL_SUCCESS on ok */ -int wolfSSL_CTX_set_TicketEncCb(WOLFSSL_CTX* ctx, SessionTicketEncCb cb) -{ - if (ctx == NULL) - return BAD_FUNC_ARG; - - ctx->ticketEncCb = cb; - - return WOLFSSL_SUCCESS; -} - -/* set hint interval, WOLFSSL_SUCCESS on ok */ -int wolfSSL_CTX_set_TicketHint(WOLFSSL_CTX* ctx, int hint) -{ - if (ctx == NULL) - return BAD_FUNC_ARG; - - /* RFC8446 Section 4.6.1: Servers MUST NOT use any value greater than - * 604800 seconds (7 days). */ - if (hint < 0 || hint > 604800) - return BAD_FUNC_ARG; - - ctx->ticketHint = hint; - - return WOLFSSL_SUCCESS; -} - -/* set user context, WOLFSSL_SUCCESS on ok */ -int wolfSSL_CTX_set_TicketEncCtx(WOLFSSL_CTX* ctx, void* userCtx) -{ - if (ctx == NULL) - return BAD_FUNC_ARG; - - ctx->ticketEncCtx = userCtx; - - return WOLFSSL_SUCCESS; -} - -/* get user context - returns userCtx on success, NULL on failure */ -void* wolfSSL_CTX_get_TicketEncCtx(WOLFSSL_CTX* ctx) -{ - if (ctx == NULL) - return NULL; - - return ctx->ticketEncCtx; -} - -#ifdef WOLFSSL_TLS13 -/* set the maximum number of tickets to send - * return WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on fail - */ -int wolfSSL_CTX_set_num_tickets(WOLFSSL_CTX* ctx, size_t mxTickets) -{ - if (ctx == NULL) - return WOLFSSL_FAILURE; - - ctx->maxTicketTls13 = (unsigned int)mxTickets; - return WOLFSSL_SUCCESS; -} - -/* get the maximum number of tickets to send - * return number of tickets set to be sent - */ -size_t wolfSSL_CTX_get_num_tickets(WOLFSSL_CTX* ctx) -{ - if (ctx == NULL) - return 0; - - return (size_t)ctx->maxTicketTls13; -} -#endif /* WOLFSSL_TLS13 */ -#endif /* !NO_WOLFSSL_SERVER */ - -#if !defined(NO_WOLFSSL_CLIENT) -int wolfSSL_UseSessionTicket(WOLFSSL* ssl) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - - return TLSX_UseSessionTicket(&ssl->extensions, NULL, ssl->heap); -} - -int wolfSSL_CTX_UseSessionTicket(WOLFSSL_CTX* ctx) -{ - if (ctx == NULL) - return BAD_FUNC_ARG; - - return TLSX_UseSessionTicket(&ctx->extensions, NULL, ctx->heap); -} - -int wolfSSL_get_SessionTicket(WOLFSSL* ssl, byte* buf, word32* bufSz) -{ - if (ssl == NULL || bufSz == NULL) - return BAD_FUNC_ARG; - - if (*bufSz == 0 && buf == NULL) { - *bufSz = ssl->session->ticketLen; - return LENGTH_ONLY_E; - } - - if (buf == NULL) - return BAD_FUNC_ARG; - - if (ssl->session->ticketLen <= *bufSz) { - XMEMCPY(buf, ssl->session->ticket, ssl->session->ticketLen); - *bufSz = ssl->session->ticketLen; - } - else - *bufSz = 0; - - return WOLFSSL_SUCCESS; -} - -int wolfSSL_set_SessionTicket(WOLFSSL* ssl, const byte* buf, - word32 bufSz) -{ - if (ssl == NULL || (buf == NULL && bufSz > 0)) - return BAD_FUNC_ARG; - - if (bufSz > 0) { - /* Ticket will fit into static ticket */ - if (bufSz <= SESSION_TICKET_LEN) { - if (ssl->session->ticketLenAlloc > 0) { - XFREE(ssl->session->ticket, ssl->session->heap, - DYNAMIC_TYPE_SESSION_TICK); - ssl->session->ticketLenAlloc = 0; - ssl->session->ticket = ssl->session->staticTicket; - } - } - else { /* Ticket requires dynamic ticket storage */ - /* is dyn buffer big enough */ - if (ssl->session->ticketLen < bufSz) { - if (ssl->session->ticketLenAlloc > 0) { - XFREE(ssl->session->ticket, ssl->session->heap, - DYNAMIC_TYPE_SESSION_TICK); - } - ssl->session->ticket = (byte*)XMALLOC(bufSz, ssl->session->heap, - DYNAMIC_TYPE_SESSION_TICK); - if(ssl->session->ticket == NULL) { - ssl->session->ticket = ssl->session->staticTicket; - ssl->session->ticketLenAlloc = 0; - return MEMORY_ERROR; - } - ssl->session->ticketLenAlloc = (word16)bufSz; - } - } - XMEMCPY(ssl->session->ticket, buf, bufSz); - } - ssl->session->ticketLen = (word16)bufSz; - - return WOLFSSL_SUCCESS; -} - - -int wolfSSL_set_SessionTicket_cb(WOLFSSL* ssl, - CallbackSessionTicket cb, void* ctx) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - - ssl->session_ticket_cb = cb; - ssl->session_ticket_ctx = ctx; - - return WOLFSSL_SUCCESS; -} -#endif /* !NO_WOLFSSL_CLIENT */ - -#endif /* HAVE_SESSION_TICKET */ - - -#ifdef HAVE_EXTENDED_MASTER -#ifndef NO_WOLFSSL_CLIENT - -int wolfSSL_CTX_DisableExtendedMasterSecret(WOLFSSL_CTX* ctx) -{ - if (ctx == NULL) - return BAD_FUNC_ARG; - - ctx->haveEMS = 0; - - return WOLFSSL_SUCCESS; -} - - -int wolfSSL_DisableExtendedMasterSecret(WOLFSSL* ssl) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - - ssl->options.haveEMS = 0; - - return WOLFSSL_SUCCESS; -} - -#endif -#endif #ifndef WOLFSSL_LEANPSK @@ -4363,56 +2460,6 @@ int wolfSSL_UseClientSuites(WOLFSSL* ssl) return 0; } -#ifdef WOLFSSL_DTLS -const byte* wolfSSL_GetDtlsMacSecret(WOLFSSL* ssl, int verify, int epochOrder) -{ -#ifndef WOLFSSL_AEAD_ONLY - Keys* keys = NULL; - - (void)epochOrder; - - if (ssl == NULL) - return NULL; - -#ifdef HAVE_SECURE_RENEGOTIATION - switch (epochOrder) { - case PEER_ORDER: - if (IsDtlsMsgSCRKeys(ssl)) - keys = &ssl->secure_renegotiation->tmp_keys; - else - keys = &ssl->keys; - break; - case PREV_ORDER: - keys = &ssl->keys; - break; - case CUR_ORDER: - if (DtlsUseSCRKeys(ssl)) - keys = &ssl->secure_renegotiation->tmp_keys; - else - keys = &ssl->keys; - break; - default: - WOLFSSL_MSG("Unknown epoch order"); - return NULL; - } -#else - keys = &ssl->keys; -#endif - - if ( (ssl->options.side == WOLFSSL_CLIENT_END && !verify) || - (ssl->options.side == WOLFSSL_SERVER_END && verify) ) - return keys->client_write_MAC_secret; - else - return keys->server_write_MAC_secret; -#else - (void)ssl; - (void)verify; - (void)epochOrder; - - return NULL; -#endif -} -#endif /* WOLFSSL_DTLS */ const byte* wolfSSL_GetMacSecret(WOLFSSL* ssl, int verify) { @@ -6104,291 +4151,6 @@ int wolfSSL_export_keying_material(WOLFSSL *ssl, } #endif /* HAVE_KEYING_MATERIAL */ -int wolfSSL_dtls_get_using_nonblock(WOLFSSL* ssl) -{ - int useNb = 0; - - if (ssl == NULL) - return WOLFSSL_FAILURE; - - WOLFSSL_ENTER("wolfSSL_dtls_get_using_nonblock"); - if (ssl->options.dtls) { -#ifdef WOLFSSL_DTLS - useNb = ssl->options.dtlsUseNonblock; -#endif - } - else { - WOLFSSL_MSG("wolfSSL_dtls_get_using_nonblock() is " - "DEPRECATED for non-DTLS use."); - } - return useNb; -} - - -#ifndef WOLFSSL_LEANPSK - -void wolfSSL_dtls_set_using_nonblock(WOLFSSL* ssl, int nonblock) -{ - (void)nonblock; - - WOLFSSL_ENTER("wolfSSL_dtls_set_using_nonblock"); - - if (ssl == NULL) - return; - - if (ssl->options.dtls) { -#ifdef WOLFSSL_DTLS - ssl->options.dtlsUseNonblock = (nonblock != 0); -#endif - } - else { - WOLFSSL_MSG("wolfSSL_dtls_set_using_nonblock() is " - "DEPRECATED for non-DTLS use."); - } -} - - -#ifdef WOLFSSL_DTLS - -int wolfSSL_dtls_get_current_timeout(WOLFSSL* ssl) -{ - int timeout = 0; - if (ssl) - timeout = ssl->dtls_timeout; - - WOLFSSL_LEAVE("wolfSSL_dtls_get_current_timeout", timeout); - return timeout; -} - -#ifdef WOLFSSL_DTLS13 - -/* - * This API returns 1 when the user should set a short timeout for receiving - * data. It is recommended that it is at most 1/4 the value returned by - * wolfSSL_dtls_get_current_timeout(). - */ -int wolfSSL_dtls13_use_quick_timeout(WOLFSSL* ssl) -{ - return ssl != NULL && ssl->dtls13FastTimeout; -} - -/* - * When this is set, a DTLS 1.3 connection will send acks immediately when a - * disruption is detected to shortcut timeouts. This results in potentially - * more traffic but may make the handshake quicker. - */ -void wolfSSL_dtls13_set_send_more_acks(WOLFSSL* ssl, int value) -{ - if (ssl != NULL) - ssl->options.dtls13SendMoreAcks = !!value; -} -#endif /* WOLFSSL_DTLS13 */ - -int wolfSSL_DTLSv1_get_timeout(WOLFSSL* ssl, WOLFSSL_TIMEVAL* timeleft) -{ - if (ssl && timeleft) { - XMEMSET(timeleft, 0, sizeof(WOLFSSL_TIMEVAL)); - timeleft->tv_sec = ssl->dtls_timeout; - } - return 0; -} - -#ifndef NO_WOLFSSL_STUB -int wolfSSL_DTLSv1_handle_timeout(WOLFSSL* ssl) -{ - WOLFSSL_STUB("SSL_DTLSv1_handle_timeout"); - (void)ssl; - return 0; -} -#endif - -#ifndef NO_WOLFSSL_STUB -void wolfSSL_DTLSv1_set_initial_timeout_duration(WOLFSSL* ssl, - word32 duration_ms) -{ - WOLFSSL_STUB("SSL_DTLSv1_set_initial_timeout_duration"); - (void)ssl; - (void)duration_ms; -} -#endif - -/* user may need to alter init dtls recv timeout, WOLFSSL_SUCCESS on ok */ -int wolfSSL_dtls_set_timeout_init(WOLFSSL* ssl, int timeout) -{ - if (ssl == NULL || timeout < 0) - return BAD_FUNC_ARG; - - if (timeout > ssl->dtls_timeout_max) { - WOLFSSL_MSG("Can't set dtls timeout init greater than dtls timeout " - "max"); - return BAD_FUNC_ARG; - } - - ssl->dtls_timeout_init = timeout; - ssl->dtls_timeout = timeout; - - return WOLFSSL_SUCCESS; -} - - -/* user may need to alter max dtls recv timeout, WOLFSSL_SUCCESS on ok */ -int wolfSSL_dtls_set_timeout_max(WOLFSSL* ssl, int timeout) -{ - if (ssl == NULL || timeout < 0) - return BAD_FUNC_ARG; - - if (timeout < ssl->dtls_timeout_init) { - WOLFSSL_MSG("Can't set dtls timeout max less than dtls timeout init"); - return BAD_FUNC_ARG; - } - - ssl->dtls_timeout_max = timeout; - - return WOLFSSL_SUCCESS; -} - - -int wolfSSL_dtls_got_timeout(WOLFSSL* ssl) -{ - int result = WOLFSSL_SUCCESS; - WOLFSSL_ENTER("wolfSSL_dtls_got_timeout"); - - if (ssl == NULL || !ssl->options.dtls) - return WOLFSSL_FATAL_ERROR; - -#ifdef WOLFSSL_DTLS13 - if (IsAtLeastTLSv1_3(ssl->version)) { - result = Dtls13RtxTimeout(ssl); - if (result < 0) { - if (result == WC_NO_ERR_TRACE(WANT_WRITE)) - ssl->dtls13SendingAckOrRtx = 1; - ssl->error = result; - WOLFSSL_ERROR(result); - return WOLFSSL_FATAL_ERROR; - } - - return WOLFSSL_SUCCESS; - } -#endif /* WOLFSSL_DTLS13 */ - - /* Do we have any 1.2 messages stored? */ - if (ssl->dtls_tx_msg_list != NULL || ssl->dtls_tx_msg != NULL) { - if (DtlsMsgPoolTimeout(ssl) < 0){ - ssl->error = SOCKET_ERROR_E; - WOLFSSL_ERROR(ssl->error); - result = WOLFSSL_FATAL_ERROR; - } - else if ((result = DtlsMsgPoolSend(ssl, 0)) < 0) { - ssl->error = result; - WOLFSSL_ERROR(result); - result = WOLFSSL_FATAL_ERROR; - } - else { - /* Reset return value to success */ - result = WOLFSSL_SUCCESS; - } - } - - WOLFSSL_LEAVE("wolfSSL_dtls_got_timeout", result); - return result; -} - - -/* retransmit all the saves messages, WOLFSSL_SUCCESS on ok */ -int wolfSSL_dtls_retransmit(WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_dtls_retransmit"); - - if (ssl == NULL) - return WOLFSSL_FATAL_ERROR; - - if (!ssl->options.handShakeDone) { - int result; -#ifdef WOLFSSL_DTLS13 - if (IsAtLeastTLSv1_3(ssl->version)) - result = Dtls13DoScheduledWork(ssl); - else -#endif - result = DtlsMsgPoolSend(ssl, 0); - if (result < 0) { - ssl->error = result; - WOLFSSL_ERROR(result); - return WOLFSSL_FATAL_ERROR; - } - } - - return WOLFSSL_SUCCESS; -} - -#endif /* DTLS */ -#endif /* LEANPSK */ - - -#if defined(WOLFSSL_DTLS) && !defined(NO_WOLFSSL_SERVER) - -/* Not an SSL function, return 0 for success, error code otherwise */ -/* Prereq: ssl's RNG needs to be initialized. */ -int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, - const byte* secret, word32 secretSz) -{ - int ret = 0; - - WOLFSSL_ENTER("wolfSSL_DTLS_SetCookieSecret"); - - if (ssl == NULL) { - WOLFSSL_MSG("need a SSL object"); - return BAD_FUNC_ARG; - } - - if (secret != NULL && secretSz == 0) { - WOLFSSL_MSG("can't have a new secret without a size"); - return BAD_FUNC_ARG; - } - - /* If secretSz is 0, use the default size. */ - if (secretSz == 0) - secretSz = COOKIE_SECRET_SZ; - - if (secretSz != ssl->buffers.dtlsCookieSecret.length) { - byte* newSecret; - - if (ssl->buffers.dtlsCookieSecret.buffer != NULL) { - ForceZero(ssl->buffers.dtlsCookieSecret.buffer, - ssl->buffers.dtlsCookieSecret.length); - XFREE(ssl->buffers.dtlsCookieSecret.buffer, - ssl->heap, DYNAMIC_TYPE_COOKIE_PWD); - } - - newSecret = (byte*)XMALLOC(secretSz, ssl->heap,DYNAMIC_TYPE_COOKIE_PWD); - if (newSecret == NULL) { - ssl->buffers.dtlsCookieSecret.buffer = NULL; - ssl->buffers.dtlsCookieSecret.length = 0; - WOLFSSL_MSG("couldn't allocate new cookie secret"); - return MEMORY_ERROR; - } - ssl->buffers.dtlsCookieSecret.buffer = newSecret; - ssl->buffers.dtlsCookieSecret.length = secretSz; - #ifdef WOLFSSL_CHECK_MEM_ZERO - wc_MemZero_Add("wolfSSL_DTLS_SetCookieSecret secret", - ssl->buffers.dtlsCookieSecret.buffer, - ssl->buffers.dtlsCookieSecret.length); - #endif - } - - /* If the supplied secret is NULL, randomly generate a new secret. */ - if (secret == NULL) { - ret = wc_RNG_GenerateBlock(ssl->rng, - ssl->buffers.dtlsCookieSecret.buffer, secretSz); - } - else - XMEMCPY(ssl->buffers.dtlsCookieSecret.buffer, secret, secretSz); - - WOLFSSL_LEAVE("wolfSSL_DTLS_SetCookieSecret", 0); - return ret; -} - -#endif /* WOLFSSL_DTLS && !NO_WOLFSSL_SERVER */ - /* EITHER SIDE METHODS */ #if !defined(NO_TLS) && (defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE)) @@ -10107,7 +7869,6 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out, } #endif -#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) int wolfSSL_clear(WOLFSSL* ssl) { WOLFSSL_ENTER("wolfSSL_clear"); @@ -10140,6 +7901,7 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out, ssl->options.acceptState = ACCEPT_BEGIN; ssl->options.handShakeState = NULL_STATE; ssl->options.handShakeDone = 0; + ssl->recordSzOverhead = 0; ssl->options.processReply = 0; /* doProcessInit */ ssl->options.havePeerVerify = 0; ssl->options.havePeerCert = 0; @@ -10224,8 +7986,6 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out, return WOLFSSL_SUCCESS; } -#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */ - #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) || defined(HAVE_MEMCACHED) long wolfSSL_CTX_set_mode(WOLFSSL_CTX* ctx, long mode) { @@ -10464,8 +8224,7 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out, #endif /* OPENSSL_EXTRA */ -#if (defined(KEEP_PEER_CERT) && defined(SESSION_CERTS)) || \ - (defined(OPENSSL_EXTRA) && defined(SESSION_CERTS)) +#ifdef SESSION_CERTS /* Decode the X509 DER encoded certificate into a WOLFSSL_X509 object. * * x509 WOLFSSL_X509 object to decode into. @@ -10497,7 +8256,7 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out, return ret; } -#endif /* (KEEP_PEER_CERT & SESSION_CERTS) || (OPENSSL_EXTRA & SESSION_CERTS) */ +#endif /* SESSION_CERTS */ #ifdef KEEP_PEER_CERT @@ -11987,19 +9746,6 @@ WOLFSSL_X509_VERIFY_PARAM* wolfSSL_get0_param(WOLFSSL* ssl) #endif /* OPENSSL_EXTRA */ -#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) -/* Gets an index to store SSL structure at. - * - * Returns positive index on success and negative values on failure - */ -int wolfSSL_get_ex_data_X509_STORE_CTX_idx(void) -{ - WOLFSSL_ENTER("wolfSSL_get_ex_data_X509_STORE_CTX_idx"); - - /* store SSL at index 0 */ - return 0; -} -#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */ #ifdef OPENSSL_EXTRA /* Sets a function callback that will send information about the state of all @@ -12847,70 +10593,6 @@ long wolfSSL_clear_options(WOLFSSL* ssl, long opt) return (long)ssl->options.mask; } -#ifdef HAVE_PK_CALLBACKS -long wolfSSL_set_tlsext_debug_arg(WOLFSSL* ssl, void *arg) -{ - if (ssl == NULL) { - return WOLFSSL_FAILURE; - } - - ssl->loggingCtx = arg; - return WOLFSSL_SUCCESS; -} -#endif /* HAVE_PK_CALLBACKS */ - -#ifndef NO_WOLFSSL_STUB -long wolfSSL_get_tlsext_status_exts(WOLFSSL *s, void *arg) -{ - (void)s; - (void)arg; - WOLFSSL_STUB("wolfSSL_get_tlsext_status_exts"); - return WOLFSSL_FAILURE; -} -#endif - -/*** TBD ***/ -#ifndef NO_WOLFSSL_STUB -long wolfSSL_set_tlsext_status_exts(WOLFSSL *s, void *arg) -{ - (void)s; - (void)arg; - WOLFSSL_STUB("wolfSSL_set_tlsext_status_exts"); - return WOLFSSL_FAILURE; -} -#endif - -/*** TBD ***/ -#ifndef NO_WOLFSSL_STUB -long wolfSSL_get_tlsext_status_ids(WOLFSSL *s, void *arg) -{ - (void)s; - (void)arg; - WOLFSSL_STUB("wolfSSL_get_tlsext_status_ids"); - return WOLFSSL_FAILURE; -} -#endif - -/*** TBD ***/ -#ifndef NO_WOLFSSL_STUB -long wolfSSL_set_tlsext_status_ids(WOLFSSL *s, void *arg) -{ - (void)s; - (void)arg; - WOLFSSL_STUB("wolfSSL_set_tlsext_status_ids"); - return WOLFSSL_FAILURE; -} -#endif - -#ifndef NO_WOLFSSL_STUB -/*** TBD ***/ -WOLFSSL_EVP_PKEY *wolfSSL_get_privatekey(const WOLFSSL *ssl) -{ - (void)ssl; - WOLFSSL_STUB("SSL_get_privatekey"); - return NULL; -} -#endif #ifndef NO_WOLFSSL_STUB /*** TBD ***/ @@ -12940,37 +10622,6 @@ void wolfSSL_ERR_load_SSL_strings(void) } #endif -#ifdef HAVE_MAX_FRAGMENT -#if !defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS) -/** - * Set max fragment tls extension - * @param c a pointer to WOLFSSL_CTX object - * @param mode maximum fragment length mode - * @return 1 on success, otherwise 0 or negative error code - */ -int wolfSSL_CTX_set_tlsext_max_fragment_length(WOLFSSL_CTX *c, - unsigned char mode) -{ - if (c == NULL || (mode < WOLFSSL_MFL_2_9 || mode > WOLFSSL_MFL_2_12 )) - return BAD_FUNC_ARG; - - return wolfSSL_CTX_UseMaxFragment(c, mode); -} -/** - * Set max fragment tls extension - * @param c a pointer to WOLFSSL object - * @param mode maximum fragment length mode - * @return 1 on success, otherwise 0 or negative error code - */ -int wolfSSL_set_tlsext_max_fragment_length(WOLFSSL *s, unsigned char mode) -{ - if (s == NULL || (mode < WOLFSSL_MFL_2_9 || mode > WOLFSSL_MFL_2_12 )) - return BAD_FUNC_ARG; - - return wolfSSL_UseMaxFragment(s, mode); -} -#endif /* !NO_WOLFSSL_CLIENT && !NO_TLS */ -#endif /* HAVE_MAX_FRAGMENT */ #endif /* OPENSSL_EXTRA */ @@ -13038,17 +10689,6 @@ size_t wolfSSL_get_peer_finished(const WOLFSSL *ssl, void *buf, size_t count) } #endif /* WOLFSSL_HAVE_TLS_UNIQUE */ -#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) || \ - defined(OPENSSL_ALL) -long wolfSSL_get_verify_result(const WOLFSSL *ssl) -{ - if (ssl == NULL) { - return WOLFSSL_FAILURE; - } - - return (long)ssl->peerVerifyRet; -} -#endif #ifdef OPENSSL_EXTRA @@ -13223,78 +10863,6 @@ long wolfSSL_CTX_set_tlsext_opaque_prf_input_callback_arg(WOLFSSL_CTX* ctx, #endif /* OPENSSL_EXTRA */ -#if defined(OPENSSL_EXTRA) && defined(KEEP_PEER_CERT) && \ - defined(HAVE_EX_DATA) && !defined(NO_FILESYSTEM) -int wolfSSL_cmp_peer_cert_to_file(WOLFSSL* ssl, const char *fname) -{ - int ret = WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR); - - WOLFSSL_ENTER("wolfSSL_cmp_peer_cert_to_file"); - if (ssl != NULL && fname != NULL) - { - #ifdef WOLFSSL_SMALL_STACK - byte staticBuffer[1]; /* force heap usage */ - #else - byte staticBuffer[FILE_BUFFER_SIZE]; - #endif - byte* myBuffer = staticBuffer; - int dynamic = 0; - XFILE file; - long sz = 0; - WOLFSSL_CTX* ctx = ssl->ctx; - WOLFSSL_X509* peer_cert = &ssl->peerCert; - DerBuffer* fileDer = NULL; - - file = XFOPEN(fname, "rb"); - if (file == XBADFILE) - return WOLFSSL_BAD_FILE; - - if (XFSEEK(file, 0, XSEEK_END) != 0) { - XFCLOSE(file); - return WOLFSSL_BAD_FILE; - } - sz = XFTELL(file); - if (XFSEEK(file, 0, XSEEK_SET) != 0) { - XFCLOSE(file); - return WOLFSSL_BAD_FILE; - } - - if (sz > MAX_WOLFSSL_FILE_SIZE || sz < 0) { - WOLFSSL_MSG("cmp_peer_cert_to_file size error"); - XFCLOSE(file); - return WOLFSSL_BAD_FILE; - } - - if (sz > (long)sizeof(staticBuffer)) { - WOLFSSL_MSG("Getting dynamic buffer"); - myBuffer = (byte*)XMALLOC((size_t)sz, ctx->heap, DYNAMIC_TYPE_FILE); - dynamic = 1; - } - - if ((myBuffer != NULL) && - (sz > 0) && - (XFREAD(myBuffer, 1, (size_t)sz, file) == (size_t)sz) && - (PemToDer(myBuffer, (long)sz, CERT_TYPE, - &fileDer, ctx->heap, NULL, NULL) == 0) && - (fileDer->length != 0) && - (fileDer->length == peer_cert->derCert->length) && - (XMEMCMP(peer_cert->derCert->buffer, fileDer->buffer, - fileDer->length) == 0)) - { - ret = 0; - } - - FreeDer(&fileDer); - - if (dynamic) - XFREE(myBuffer, ctx->heap, DYNAMIC_TYPE_FILE); - - XFCLOSE(file); - } - - return ret; -} -#endif #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) const WOLFSSL_ObjectInfo wolfssl_object_info[] = { @@ -13868,416 +11436,8 @@ int wolfSSL_OPENSSL_init_crypto(word64 opts, return wolfSSL_library_init(); } -/* Colon separated list of + algorithms. - * Replaces list in context. - */ -int wolfSSL_CTX_set1_sigalgs_list(WOLFSSL_CTX* ctx, const char* list) -{ - WOLFSSL_MSG("wolfSSL_CTX_set1_sigalg_list"); - - if (ctx == NULL || list == NULL) { - WOLFSSL_MSG("Bad function arguments"); - return WOLFSSL_FAILURE; - } - - if (AllocateCtxSuites(ctx) != 0) - return WOLFSSL_FAILURE; - - return SetSuitesHashSigAlgo(ctx->suites, list); -} - -/* Colon separated list of + algorithms. - * Replaces list in SSL. - */ -int wolfSSL_set1_sigalgs_list(WOLFSSL* ssl, const char* list) -{ - WOLFSSL_MSG("wolfSSL_set1_sigalg_list"); - - if (ssl == NULL || list == NULL) { - WOLFSSL_MSG("Bad function arguments"); - return WOLFSSL_FAILURE; - } - - if (AllocateSuites(ssl) != 0) - return WOLFSSL_FAILURE; - - return SetSuitesHashSigAlgo(ssl->suites, list); -} - -static int HashToNid(byte hashAlgo, int* nid) -{ - int ret = WOLFSSL_SUCCESS; - - /* Cast for compiler to check everything is implemented */ - switch ((enum wc_MACAlgorithm)hashAlgo) { - case no_mac: - case rmd_mac: - *nid = WC_NID_undef; - break; - case md5_mac: - *nid = WC_NID_md5; - break; - case sha_mac: - *nid = WC_NID_sha1; - break; - case sha224_mac: - *nid = WC_NID_sha224; - break; - case sha256_mac: - *nid = WC_NID_sha256; - break; - case sha384_mac: - *nid = WC_NID_sha384; - break; - case sha512_mac: - *nid = WC_NID_sha512; - break; - case blake2b_mac: - *nid = WC_NID_blake2b512; - break; - case sm3_mac: - *nid = WC_NID_sm3; - break; - default: - ret = WOLFSSL_FAILURE; - break; - } - - return ret; -} - -static int SaToNid(byte sa, int* nid) -{ - int ret = WOLFSSL_SUCCESS; - /* Cast for compiler to check everything is implemented */ - switch ((enum SignatureAlgorithm)sa) { - case anonymous_sa_algo: - *nid = WC_NID_undef; - break; - case rsa_sa_algo: - *nid = WC_NID_rsaEncryption; - break; - case dsa_sa_algo: - *nid = WC_NID_dsa; - break; - case ecc_dsa_sa_algo: - case ecc_brainpool_sa_algo: - *nid = WC_NID_X9_62_id_ecPublicKey; - break; - case rsa_pss_sa_algo: - *nid = WC_NID_rsassaPss; - break; - case ed25519_sa_algo: -#ifdef HAVE_ED25519 - *nid = WC_NID_ED25519; -#else - ret = WOLFSSL_FAILURE; -#endif - break; - case rsa_pss_pss_algo: - *nid = WC_NID_rsassaPss; - break; - case ed448_sa_algo: -#ifdef HAVE_ED448 - *nid = WC_NID_ED448; -#else - ret = WOLFSSL_FAILURE; -#endif - break; - case falcon_level1_sa_algo: - *nid = CTC_FALCON_LEVEL1; - break; - case falcon_level5_sa_algo: - *nid = CTC_FALCON_LEVEL5; - break; - case mldsa_44_sa_algo: - *nid = CTC_ML_DSA_44; - break; - case mldsa_65_sa_algo: - *nid = CTC_ML_DSA_65; - break; - case mldsa_87_sa_algo: - *nid = CTC_ML_DSA_87; - break; - case sm2_sa_algo: - *nid = WC_NID_sm2; - break; - case invalid_sa_algo: - case any_sa_algo: - default: - ret = WOLFSSL_FAILURE; - break; - } - return ret; -} - -/* This API returns the hash selected. */ -int wolfSSL_get_signature_nid(WOLFSSL *ssl, int* nid) -{ - WOLFSSL_MSG("wolfSSL_get_signature_nid"); - - if (ssl == NULL || nid == NULL) { - WOLFSSL_MSG("Bad function arguments"); - return WOLFSSL_FAILURE; - } - - return HashToNid(ssl->options.hashAlgo, nid); -} - -/* This API returns the signature selected. */ -int wolfSSL_get_signature_type_nid(const WOLFSSL* ssl, int* nid) -{ - WOLFSSL_MSG("wolfSSL_get_signature_type_nid"); - - if (ssl == NULL || nid == NULL) { - WOLFSSL_MSG("Bad function arguments"); - return WOLFSSL_FAILURE; - } - - return SaToNid(ssl->options.sigAlgo, nid); -} - -int wolfSSL_get_peer_signature_nid(WOLFSSL* ssl, int* nid) -{ - WOLFSSL_MSG("wolfSSL_get_peer_signature_nid"); - - if (ssl == NULL || nid == NULL) { - WOLFSSL_MSG("Bad function arguments"); - return WOLFSSL_FAILURE; - } - - return HashToNid(ssl->options.peerHashAlgo, nid); -} - -int wolfSSL_get_peer_signature_type_nid(const WOLFSSL* ssl, int* nid) -{ - WOLFSSL_MSG("wolfSSL_get_peer_signature_type_nid"); - - if (ssl == NULL || nid == NULL) { - WOLFSSL_MSG("Bad function arguments"); - return WOLFSSL_FAILURE; - } - - return SaToNid(ssl->options.peerSigAlgo, nid); -} - -#ifdef HAVE_ECC - -#if defined(WOLFSSL_TLS13) && defined(HAVE_SUPPORTED_CURVES) -int wolfSSL_CTX_set1_groups_list(WOLFSSL_CTX *ctx, const char *list) -{ - if (!ctx || !list) { - return WOLFSSL_FAILURE; - } - - return set_curves_list(NULL, ctx, list, 0); -} - -int wolfSSL_set1_groups_list(WOLFSSL *ssl, const char *list) -{ - if (!ssl || !list) { - return WOLFSSL_FAILURE; - } - - return set_curves_list(ssl, NULL, list, 0); -} -#endif /* WOLFSSL_TLS13 */ - -#endif /* HAVE_ECC */ - #endif /* OPENSSL_EXTRA */ -#ifdef WOLFSSL_ALT_CERT_CHAINS -int wolfSSL_is_peer_alt_cert_chain(const WOLFSSL* ssl) -{ - int isUsing = 0; - if (ssl) - isUsing = ssl->options.usingAltCertChain; - return isUsing; -} -#endif /* WOLFSSL_ALT_CERT_CHAINS */ - - -#ifdef SESSION_CERTS - -#ifdef WOLFSSL_ALT_CERT_CHAINS -/* Get peer's alternate certificate chain */ -WOLFSSL_X509_CHAIN* wolfSSL_get_peer_alt_chain(WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_get_peer_alt_chain"); - if (ssl) - return &ssl->session->altChain; - - return 0; -} -#endif /* WOLFSSL_ALT_CERT_CHAINS */ - - -/* Get peer's certificate chain */ -WOLFSSL_X509_CHAIN* wolfSSL_get_peer_chain(WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_get_peer_chain"); - if (ssl) - return &ssl->session->chain; - - return 0; -} - - -/* Get peer's certificate chain total count */ -int wolfSSL_get_chain_count(WOLFSSL_X509_CHAIN* chain) -{ - WOLFSSL_ENTER("wolfSSL_get_chain_count"); - if (chain) - return chain->count; - - return 0; -} - - -/* Get peer's ASN.1 DER certificate at index (idx) length in bytes */ -int wolfSSL_get_chain_length(WOLFSSL_X509_CHAIN* chain, int idx) -{ - WOLFSSL_ENTER("wolfSSL_get_chain_length"); - if (chain && idx >= 0 && idx < chain->count) - return chain->certs[idx].length; - - return 0; -} - - -/* Get peer's ASN.1 DER certificate at index (idx) */ -byte* wolfSSL_get_chain_cert(WOLFSSL_X509_CHAIN* chain, int idx) -{ - WOLFSSL_ENTER("wolfSSL_get_chain_cert"); - if (chain && idx >= 0 && idx < chain->count) - return chain->certs[idx].buffer; - - return 0; -} - - -/* Get peer's wolfSSL X509 certificate at index (idx) */ -WOLFSSL_X509* wolfSSL_get_chain_X509(WOLFSSL_X509_CHAIN* chain, int idx) -{ - int ret = 0; - WOLFSSL_X509* x509 = NULL; - WC_DECLARE_VAR(cert, DecodedCert, 1, 0); - - WOLFSSL_ENTER("wolfSSL_get_chain_X509"); - if (chain != NULL && idx >= 0 && idx < chain->count) { - #ifdef WOLFSSL_SMALL_STACK - cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, - DYNAMIC_TYPE_DCERT); - if (cert != NULL) - #endif - { - InitDecodedCert(cert, chain->certs[idx].buffer, - (word32)chain->certs[idx].length, NULL); - - if ((ret = ParseCertRelative(cert, CERT_TYPE, 0, NULL, NULL)) != 0) { - WOLFSSL_MSG("Failed to parse cert"); - } - else { - x509 = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), NULL, - DYNAMIC_TYPE_X509); - if (x509 == NULL) { - WOLFSSL_MSG("Failed alloc X509"); - } - else { - InitX509(x509, 1, NULL); - - if ((ret = CopyDecodedToX509(x509, cert)) != 0) { - WOLFSSL_MSG("Failed to copy decoded"); - wolfSSL_X509_free(x509); - x509 = NULL; - } - } - } - - FreeDecodedCert(cert); - WC_FREE_VAR_EX(cert, NULL, DYNAMIC_TYPE_DCERT); - } - } - (void)ret; - - return x509; -} - - -/* Get peer's PEM certificate at index (idx), output to buffer if inLen big - enough else return error (-1). If buffer is NULL only calculate - outLen. Output length is in *outLen WOLFSSL_SUCCESS on ok */ -int wolfSSL_get_chain_cert_pem(WOLFSSL_X509_CHAIN* chain, int idx, - unsigned char* buf, int inLen, int* outLen) -{ -#if defined(WOLFSSL_PEM_TO_DER) || defined(WOLFSSL_DER_TO_PEM) - const char* header = NULL; - const char* footer = NULL; - int headerLen; - int footerLen; - int i; - int err; - word32 szNeeded = 0; - - WOLFSSL_ENTER("wolfSSL_get_chain_cert_pem"); - if (!chain || !outLen || idx < 0 || idx >= wolfSSL_get_chain_count(chain)) - return BAD_FUNC_ARG; - - err = wc_PemGetHeaderFooter(CERT_TYPE, &header, &footer); - if (err != 0) - return err; - - headerLen = (int)XSTRLEN(header); - footerLen = (int)XSTRLEN(footer); - - /* Null output buffer return size needed in outLen */ - if(!buf) { - if(Base64_Encode(chain->certs[idx].buffer, - (word32)chain->certs[idx].length, - NULL, &szNeeded) != WC_NO_ERR_TRACE(LENGTH_ONLY_E)) - return WOLFSSL_FAILURE; - *outLen = (int)szNeeded + headerLen + footerLen; - return WC_NO_ERR_TRACE(LENGTH_ONLY_E); - } - - /* don't even try if inLen too short */ - if (inLen < headerLen + footerLen + chain->certs[idx].length) - return BAD_FUNC_ARG; - - /* header */ - if (XMEMCPY(buf, header, (size_t)headerLen) == NULL) - return WOLFSSL_FATAL_ERROR; - - i = headerLen; - - /* body */ - *outLen = inLen; /* input to Base64_Encode */ - if ( (err = Base64_Encode(chain->certs[idx].buffer, - (word32)chain->certs[idx].length, buf + i, - (word32*)outLen)) < 0) - return err; - i += *outLen; - - /* footer */ - if ( (i + footerLen) > inLen) - return BAD_FUNC_ARG; - if (XMEMCPY(buf + i, footer, (size_t)footerLen) == NULL) - return WOLFSSL_FATAL_ERROR; - *outLen += headerLen + footerLen; - - return WOLFSSL_SUCCESS; -#else - (void)chain; - (void)idx; - (void)buf; - (void)inLen; - (void)outLen; - return WOLFSSL_FAILURE; -#endif /* WOLFSSL_PEM_TO_DER || WOLFSSL_DER_TO_PEM */ -} - -#endif /* SESSION_CERTS */ #ifdef HAVE_FUZZER void wolfSSL_SetFuzzerCb(WOLFSSL* ssl, CallbackFuzzer cbf, void* fCtx) @@ -15758,23 +12918,6 @@ long wolfSSL_CTX_callback_ctrl(WOLFSSL_CTX* ctx, int cmd, void (*fp)(void)) } #endif /* NO_WOLFSSL_STUB */ -#ifndef NO_WOLFSSL_STUB -long wolfSSL_CTX_clear_extra_chain_certs(WOLFSSL_CTX* ctx) -{ - return wolfSSL_CTX_ctrl(ctx, SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS, 0L, NULL); -} -#endif - -/* Returns the verifyCallback from the ssl structure if successful. -Returns NULL otherwise. */ -VerifyCallback wolfSSL_get_verify_callback(WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_get_verify_callback"); - if (ssl) { - return ssl->verifyCallback; - } - return NULL; -} #endif /* OPENSSL_ALL || WOLFSSL_ASIO || WOLFSSL_HAPROXY || WOLFSSL_QT */ @@ -15928,32 +13071,6 @@ int wolfSSL_CIPHER_get_bits(const WOLFSSL_CIPHER *c, int *alg_bits) return ret; } -#ifdef HAVE_SNI -int wolfSSL_set_tlsext_host_name(WOLFSSL* ssl, const char* host_name) -{ - int ret; - WOLFSSL_ENTER("wolfSSL_set_tlsext_host_name"); - ret = wolfSSL_UseSNI(ssl, WOLFSSL_SNI_HOST_NAME, - host_name, (word16)XSTRLEN(host_name)); - WOLFSSL_LEAVE("wolfSSL_set_tlsext_host_name", ret); - return ret; -} - -#ifndef NO_WOLFSSL_SERVER -/* May be called by server to get the requested accepted name and by the client - * to get the requested name. */ -const char * wolfSSL_get_servername(WOLFSSL* ssl, byte type) -{ - void * serverName = NULL; - if (ssl == NULL) - return NULL; - TLSX_SNI_GetRequest(ssl->extensions, type, &serverName, - !wolfSSL_is_server(ssl)); - return (const char *)serverName; -} -#endif - -#endif /* HAVE_SNI */ WOLFSSL_CTX* wolfSSL_set_SSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx) { @@ -16071,6 +13188,9 @@ WOLFSSL_CTX* wolfSSL_set_SSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx) #endif #else if (ctx->privateKey != NULL) { + if (ssl->buffers.key != NULL && ssl->buffers.weOwnKey) { + FreeDer(&ssl->buffers.key); + } ret = AllocCopyDer(&ssl->buffers.key, ctx->privateKey->buffer, ctx->privateKey->length, ctx->privateKey->type, ctx->privateKey->heap); @@ -16135,30 +13255,6 @@ WOLFSSL_CTX* wolfSSL_set_SSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx) } -VerifyCallback wolfSSL_CTX_get_verify_callback(WOLFSSL_CTX* ctx) -{ - WOLFSSL_ENTER("wolfSSL_CTX_get_verify_callback"); - if(ctx) - return ctx->verifyCallback; - return NULL; -} - -#ifdef HAVE_SNI -/* this is a compatibility function, consider using - * wolfSSL_CTX_set_servername_callback */ -int wolfSSL_CTX_set_tlsext_servername_callback(WOLFSSL_CTX* ctx, - CallbackSniRecv cb) -{ - WOLFSSL_ENTER("wolfSSL_CTX_set_tlsext_servername_callback"); - if (ctx) { - ctx->sniRecvCb = cb; - return WOLFSSL_SUCCESS; - } - return WOLFSSL_FAILURE; -} - -#endif /* HAVE_SNI */ - #ifndef NO_BIO void wolfSSL_ERR_load_BIO_strings(void) { WOLFSSL_ENTER("wolfSSL_ERR_load_BIO_strings"); @@ -16191,35 +13287,29 @@ void wolfSSL_THREADID_set_numeric(void* id, unsigned long val) #endif /* OPENSSL_ALL || OPENSSL_EXTRA */ -#ifdef HAVE_SNI - -void wolfSSL_CTX_set_servername_callback(WOLFSSL_CTX* ctx, CallbackSniRecv cb) -{ - WOLFSSL_ENTER("wolfSSL_CTX_set_servername_callback"); - if (ctx) - ctx->sniRecvCb = cb; -} - - -int wolfSSL_CTX_set_servername_arg(WOLFSSL_CTX* ctx, void* arg) -{ - WOLFSSL_ENTER("wolfSSL_CTX_set_servername_arg"); - if (ctx) { - ctx->sniRecvCbArg = arg; - return WOLFSSL_SUCCESS; - } - return WOLFSSL_FAILURE; -} - -#endif /* HAVE_SNI */ #if defined(OPENSSL_EXTRA) int wolfSSL_CRYPTO_memcmp(const void *a, const void *b, size_t size) { + int ret = 0; + int chunk; + const byte* pa = (const byte*)a; + const byte* pb = (const byte*)b; + if (!a || !b) return -1; - return ConstantCompare((const byte*)a, (const byte*)b, (int)size); + /* ConstantCompare takes an int length. Compare in chunks of at most + * INT_MAX so a size that does not fit in an int is not narrowed into a + * negative or truncated length, which could wrongly report equality. */ + while (size > 0) { + chunk = (size > (size_t)INT_MAX) ? INT_MAX : (int)size; + ret |= ConstantCompare(pa, pb, chunk); + pa += chunk; + pb += chunk; + size -= (size_t)chunk; + } + return ret; } unsigned long wolfSSL_ERR_peek_last_error(void) @@ -16289,77 +13379,6 @@ WOLFSSL_CTX* wolfSSL_get_SSL_CTX(const WOLFSSL* ssl) return ssl->ctx; } -#if defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) || defined(HAVE_STUNNEL) || \ - defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(WOLFSSL_NGINX) - -/* TODO: Doesn't currently track SSL_VERIFY_CLIENT_ONCE */ -int wolfSSL_get_verify_mode(const WOLFSSL* ssl) -{ - int mode = 0; - WOLFSSL_ENTER("wolfSSL_get_verify_mode"); - - if (!ssl) { - return WOLFSSL_FAILURE; - } - - if (ssl->options.verifyNone) { - mode = WOLFSSL_VERIFY_NONE; - } - else { - if (ssl->options.verifyPeer) { - mode |= WOLFSSL_VERIFY_PEER; - } - if (ssl->options.failNoCert) { - mode |= WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT; - } - if (ssl->options.failNoCertxPSK) { - mode |= WOLFSSL_VERIFY_FAIL_EXCEPT_PSK; - } -#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) - if (ssl->options.verifyPostHandshake) { - mode |= WOLFSSL_VERIFY_POST_HANDSHAKE; - } -#endif - } - - WOLFSSL_LEAVE("wolfSSL_get_verify_mode", mode); - return mode; -} - -int wolfSSL_CTX_get_verify_mode(const WOLFSSL_CTX* ctx) -{ - int mode = 0; - WOLFSSL_ENTER("wolfSSL_CTX_get_verify_mode"); - - if (!ctx) { - return WOLFSSL_FAILURE; - } - - if (ctx->verifyNone) { - mode = WOLFSSL_VERIFY_NONE; - } - else { - if (ctx->verifyPeer) { - mode |= WOLFSSL_VERIFY_PEER; - } - if (ctx->failNoCert) { - mode |= WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT; - } - if (ctx->failNoCertxPSK) { - mode |= WOLFSSL_VERIFY_FAIL_EXCEPT_PSK; - } -#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) - if (ctx->verifyPostHandshake) { - mode |= WOLFSSL_VERIFY_POST_HANDSHAKE; - } -#endif - } - - WOLFSSL_LEAVE("wolfSSL_CTX_get_verify_mode", mode); - return mode; -} - -#endif #ifdef WOLFSSL_JNI @@ -16735,19 +13754,6 @@ long wolfSSL_get_timeout(WOLFSSL* ssl) #if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) \ || defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) -#ifdef HAVE_ECC -int wolfSSL_SSL_CTX_set_tmp_ecdh(WOLFSSL_CTX *ctx, WOLFSSL_EC_KEY *ecdh) -{ - WOLFSSL_ENTER("wolfSSL_SSL_CTX_set_tmp_ecdh"); - - if (ctx == NULL || ecdh == NULL) - return BAD_FUNC_ARG; - - ctx->ecdhCurveOID = (word32)ecdh->group->curve_oid; - - return WOLFSSL_SUCCESS; -} -#endif #ifndef NO_BIO WOLFSSL_BIO *wolfSSL_SSL_get_rbio(const WOLFSSL *s) { @@ -16847,331 +13853,14 @@ int wolfSSL_SSL_in_connect_init(WOLFSSL* ssl) ssl->options.acceptState < ACCEPT_THIRD_REPLY_DONE; } -#if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_SERVER) -/* Expected return values from implementations of OpenSSL ticket key callback. - */ -#define TICKET_KEY_CB_RET_FAILURE (-1) -#define TICKET_KEY_CB_RET_NOT_FOUND 0 -#define TICKET_KEY_CB_RET_OK 1 -#define TICKET_KEY_CB_RET_RENEW 2 - -/* Implementation of session ticket encryption/decryption using OpenSSL - * callback to initialize the cipher and HMAC. - * - * ssl The SSL/TLS object. - * keyName The key name - used to identify the key to be used. - * iv The IV to use. - * mac The MAC of the encrypted data. - * enc Encrypt ticket. - * encTicket The ticket data. - * encTicketLen The length of the ticket data. - * encLen The encrypted/decrypted ticket length - output length. - * ctx Ignored. Application specific data. - * returns WOLFSSL_TICKET_RET_OK to indicate success, - * WOLFSSL_TICKET_RET_CREATE if a new ticket is required and - * WOLFSSL_TICKET_RET_FATAL on error. - */ -static int wolfSSL_TicketKeyCb(WOLFSSL* ssl, - unsigned char keyName[WOLFSSL_TICKET_NAME_SZ], - unsigned char iv[WOLFSSL_TICKET_IV_SZ], - unsigned char mac[WOLFSSL_TICKET_MAC_SZ], - int enc, unsigned char* encTicket, - int encTicketLen, int* encLen, void* ctx) -{ - byte digest[WC_MAX_DIGEST_SIZE]; - WC_DECLARE_VAR(evpCtx, WOLFSSL_EVP_CIPHER_CTX, 1, 0); - WOLFSSL_HMAC_CTX hmacCtx; - unsigned int mdSz = 0; - int len = 0; - int ret = WOLFSSL_TICKET_RET_FATAL; - int res; - int totalSz = 0; - - (void)ctx; - - WOLFSSL_ENTER("wolfSSL_TicketKeyCb"); - - if (ssl == NULL || ssl->ctx == NULL || ssl->ctx->ticketEncWrapCb == NULL) { - WOLFSSL_MSG("Bad parameter"); - return WOLFSSL_TICKET_RET_FATAL; - } - -#ifdef WOLFSSL_SMALL_STACK - evpCtx = (WOLFSSL_EVP_CIPHER_CTX *)XMALLOC(sizeof(*evpCtx), ssl->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (evpCtx == NULL) { - WOLFSSL_MSG("out of memory"); - return WOLFSSL_TICKET_RET_FATAL; - } -#endif - - /* Initialize the cipher and HMAC. */ - wolfSSL_EVP_CIPHER_CTX_init(evpCtx); - if (wolfSSL_HMAC_CTX_Init(&hmacCtx) != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("wolfSSL_HMAC_CTX_Init error"); - WC_FREE_VAR_EX(evpCtx, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); - return WOLFSSL_TICKET_RET_FATAL; - } - res = ssl->ctx->ticketEncWrapCb(ssl, keyName, - iv, evpCtx, &hmacCtx, enc); - if (res != TICKET_KEY_CB_RET_OK && res != TICKET_KEY_CB_RET_RENEW) { - WOLFSSL_MSG("Ticket callback error"); - ret = WOLFSSL_TICKET_RET_FATAL; - goto end; - } - - if (wolfSSL_HMAC_size(&hmacCtx) > WOLFSSL_TICKET_MAC_SZ) { - WOLFSSL_MSG("Ticket cipher MAC size error"); - goto end; - } - - if (enc) - { - /* Encrypt in place. */ - if (!wolfSSL_EVP_CipherUpdate(evpCtx, encTicket, &len, - encTicket, encTicketLen)) - goto end; - totalSz = len; - if (totalSz > *encLen) - goto end; - if (!wolfSSL_EVP_EncryptFinal(evpCtx, &encTicket[len], &len)) - goto end; - /* Total length of encrypted data. */ - totalSz += len; - if (totalSz > *encLen) - goto end; - - /* HMAC the encrypted data into the parameter 'mac'. */ - if (!wolfSSL_HMAC_Update(&hmacCtx, encTicket, totalSz)) - goto end; - if (!wolfSSL_HMAC_Final(&hmacCtx, mac, &mdSz)) - goto end; - } - else - { - /* HMAC the encrypted data and compare it to the passed in data. */ - if (!wolfSSL_HMAC_Update(&hmacCtx, encTicket, encTicketLen)) - goto end; - if (!wolfSSL_HMAC_Final(&hmacCtx, digest, &mdSz)) - goto end; - if (ConstantCompare(mac, digest, (int)mdSz) != 0) - goto end; - - /* Decrypt the ticket data in place. */ - if (!wolfSSL_EVP_CipherUpdate(evpCtx, encTicket, &len, - encTicket, encTicketLen)) - goto end; - totalSz = len; - if (totalSz > encTicketLen) - goto end; - if (!wolfSSL_EVP_DecryptFinal(evpCtx, &encTicket[len], &len)) - goto end; - /* Total length of decrypted data. */ - totalSz += len; - if (totalSz > encTicketLen) - goto end; - } - *encLen = totalSz; - - if (res == TICKET_KEY_CB_RET_RENEW && !IsAtLeastTLSv1_3(ssl->version) - && !enc) - ret = WOLFSSL_TICKET_RET_CREATE; - else - ret = WOLFSSL_TICKET_RET_OK; -end: - - (void)wc_HmacFree(&hmacCtx.hmac); - (void)wolfSSL_EVP_CIPHER_CTX_cleanup(evpCtx); - - WC_FREE_VAR_EX(evpCtx, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); - - return ret; -} - -/* Set the callback to use when encrypting/decrypting tickets. - * - * ctx The SSL/TLS context object. - * cb The OpenSSL session ticket callback. - * returns WOLFSSL_SUCCESS to indicate success. - */ -int wolfSSL_CTX_set_tlsext_ticket_key_cb(WOLFSSL_CTX *ctx, ticketCompatCb cb) -{ - - /* Set the ticket encryption callback to be a wrapper around OpenSSL - * callback. - */ - ctx->ticketEncCb = wolfSSL_TicketKeyCb; - ctx->ticketEncWrapCb = cb; - - return WOLFSSL_SUCCESS; -} - -#endif /* HAVE_SESSION_TICKET */ #endif /* OPENSSL_ALL || WOLFSSL_NGINX || WOLFSSL_HAPROXY || OPENSSL_EXTRA || HAVE_LIGHTY */ -#if defined(HAVE_SESSION_TICKET) && !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \ - !defined(NO_WOLFSSL_SERVER) -/* Serialize the session ticket encryption keys. - * - * @param [in] ctx SSL/TLS context object. - * @param [in] keys Buffer to hold session ticket keys. - * @param [in] keylen Length of buffer. - * @return WOLFSSL_SUCCESS on success. - * @return WOLFSSL_FAILURE when ctx is NULL, keys is NULL or keylen is not the - * correct length. - */ -long wolfSSL_CTX_get_tlsext_ticket_keys(WOLFSSL_CTX *ctx, - unsigned char *keys, int keylen) -{ - if (ctx == NULL || keys == NULL) { - return WOLFSSL_FAILURE; - } - if (keylen != WOLFSSL_TICKET_KEYS_SZ) { - return WOLFSSL_FAILURE; - } - - XMEMCPY(keys, ctx->ticketKeyCtx.name, WOLFSSL_TICKET_NAME_SZ); - keys += WOLFSSL_TICKET_NAME_SZ; - XMEMCPY(keys, ctx->ticketKeyCtx.key[0], WOLFSSL_TICKET_KEY_SZ); - keys += WOLFSSL_TICKET_KEY_SZ; - XMEMCPY(keys, ctx->ticketKeyCtx.key[1], WOLFSSL_TICKET_KEY_SZ); - keys += WOLFSSL_TICKET_KEY_SZ; - c32toa(ctx->ticketKeyCtx.expirary[0], keys); - keys += OPAQUE32_LEN; - c32toa(ctx->ticketKeyCtx.expirary[1], keys); - - return WOLFSSL_SUCCESS; -} - -/* Deserialize the session ticket encryption keys. - * - * @param [in] ctx SSL/TLS context object. - * @param [in] keys Session ticket keys. - * @param [in] keylen Length of data. - * @return WOLFSSL_SUCCESS on success. - * @return WOLFSSL_FAILURE when ctx is NULL, keys is NULL or keylen is not the - * correct length. - */ -long wolfSSL_CTX_set_tlsext_ticket_keys(WOLFSSL_CTX *ctx, - const void *keys_vp, int keylen) -{ - const byte* keys = (const byte*)keys_vp; - if (ctx == NULL || keys == NULL) { - return WOLFSSL_FAILURE; - } - if (keylen != WOLFSSL_TICKET_KEYS_SZ) { - return WOLFSSL_FAILURE; - } - - XMEMCPY(ctx->ticketKeyCtx.name, keys, WOLFSSL_TICKET_NAME_SZ); - keys += WOLFSSL_TICKET_NAME_SZ; - XMEMCPY(ctx->ticketKeyCtx.key[0], keys, WOLFSSL_TICKET_KEY_SZ); - keys += WOLFSSL_TICKET_KEY_SZ; - XMEMCPY(ctx->ticketKeyCtx.key[1], keys, WOLFSSL_TICKET_KEY_SZ); - keys += WOLFSSL_TICKET_KEY_SZ; - ato32(keys, &ctx->ticketKeyCtx.expirary[0]); - keys += OPAQUE32_LEN; - ato32(keys, &ctx->ticketKeyCtx.expirary[1]); - - return WOLFSSL_SUCCESS; -} -#endif #if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) || \ defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) -int wolfSSL_CTX_get_extra_chain_certs(WOLFSSL_CTX* ctx, - WOLF_STACK_OF(X509)** chain) -{ - word32 idx; - word32 length; - WOLFSSL_STACK* node; - WOLFSSL_STACK* last = NULL; - if (ctx == NULL || chain == NULL) { - chain = NULL; - return WOLFSSL_FAILURE; - } - if (ctx->x509Chain != NULL) { - *chain = ctx->x509Chain; - return WOLFSSL_SUCCESS; - } - - /* If there are no chains then success! */ - *chain = NULL; - if (ctx->certChain == NULL || ctx->certChain->length == 0) { - return WOLFSSL_SUCCESS; - } - - /* Create a new stack of WOLFSSL_X509 object from chain buffer. */ - for (idx = 0; idx < ctx->certChain->length; ) { - node = wolfSSL_sk_X509_new_null(); - if (node == NULL) - return WOLFSSL_FAILURE; - node->next = NULL; - - /* 3 byte length | X509 DER data */ - ato24(ctx->certChain->buffer + idx, &length); - idx += 3; - - /* Create a new X509 from DER encoded data. */ - node->data.x509 = wolfSSL_X509_d2i_ex(NULL, - ctx->certChain->buffer + idx, (int)length, ctx->heap); - if (node->data.x509 == NULL) { - XFREE(node, NULL, DYNAMIC_TYPE_OPENSSL); - /* Return as much of the chain as we created. */ - ctx->x509Chain = *chain; - return WOLFSSL_FAILURE; - } - idx += length; - - /* Add object to the end of the stack. */ - if (last == NULL) { - node->num = 1; - *chain = node; - } - else { - (*chain)->num++; - last->next = node; - } - - last = node; - } - - ctx->x509Chain = *chain; - - return WOLFSSL_SUCCESS; -} - -int wolfSSL_CTX_get0_chain_certs(WOLFSSL_CTX *ctx, - WOLF_STACK_OF(WOLFSSL_X509) **sk) -{ - WOLFSSL_ENTER("wolfSSL_CTX_get0_chain_certs"); - if (ctx == NULL || sk == NULL) { - WOLFSSL_MSG("Bad parameter"); - return WOLFSSL_FAILURE; - } - - /* This function should return ctx->x509Chain if it is populated, otherwise - it should be populated from ctx->certChain. This matches the behavior of - wolfSSL_CTX_get_extra_chain_certs, so it is used directly. */ - return wolfSSL_CTX_get_extra_chain_certs(ctx, sk); -} - -#ifdef KEEP_OUR_CERT -int wolfSSL_get0_chain_certs(WOLFSSL *ssl, - WOLF_STACK_OF(WOLFSSL_X509) **sk) -{ - WOLFSSL_ENTER("wolfSSL_get0_chain_certs"); - if (ssl == NULL || sk == NULL) { - WOLFSSL_MSG("Bad parameter"); - return WOLFSSL_FAILURE; - } - *sk = ssl->ourCertChain; - return WOLFSSL_SUCCESS; -} -#endif void wolfSSL_WOLFSSL_STRING_free(WOLFSSL_STRING s) { @@ -17182,157 +13871,8 @@ void wolfSSL_WOLFSSL_STRING_free(WOLFSSL_STRING s) #endif /* WOLFSSL_NGINX || WOLFSSL_HAPROXY || OPENSSL_EXTRA || OPENSSL_ALL */ -#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || \ - defined(WOLFSSL_HAPROXY) || defined(HAVE_LIGHTY) || \ - defined(WOLFSSL_QUIC) -#ifdef HAVE_ALPN -void wolfSSL_get0_alpn_selected(const WOLFSSL *ssl, const unsigned char **data, - unsigned int *len) -{ - word16 nameLen = 0; - - if (ssl != NULL && data != NULL && len != NULL) { - TLSX_ALPN_GetRequest(ssl->extensions, (void **)data, &nameLen); - *len = nameLen; - } -} - -int wolfSSL_select_next_proto(unsigned char **out, unsigned char *outLen, - const unsigned char *in, unsigned int inLen, - const unsigned char *clientNames, - unsigned int clientLen) -{ - unsigned int i, j; - byte lenIn, lenClient; - - if (out == NULL || outLen == NULL || in == NULL || clientNames == NULL) - return WOLFSSL_NPN_UNSUPPORTED; - - for (i = 0; i < inLen; i += lenIn) { - lenIn = in[i++]; - if (lenIn == 0 || i + lenIn > inLen) - break; - for (j = 0; j < clientLen; j += lenClient) { - lenClient = clientNames[j++]; - if (lenClient == 0 || j + lenClient > clientLen) - break; - - if (lenIn != lenClient) - continue; - - if (XMEMCMP(in + i, clientNames + j, lenIn) == 0) { - *out = (unsigned char *)(in + i); - *outLen = lenIn; - return WOLFSSL_NPN_NEGOTIATED; - } - } - } - - if (clientLen > 0 && (unsigned int)clientNames[0] + 1 <= clientLen) { - *out = (unsigned char *)clientNames + 1; - *outLen = clientNames[0]; - } - else { - *out = (unsigned char *)clientNames; - *outLen = 0; - } - return WOLFSSL_NPN_NO_OVERLAP; -} - -void wolfSSL_set_alpn_select_cb(WOLFSSL *ssl, - int (*cb) (WOLFSSL *ssl, - const unsigned char **out, - unsigned char *outlen, - const unsigned char *in, - unsigned int inlen, - void *arg), void *arg) -{ - if (ssl != NULL) { - ssl->alpnSelect = cb; - ssl->alpnSelectArg = arg; - } -} - -void wolfSSL_CTX_set_alpn_select_cb(WOLFSSL_CTX *ctx, - int (*cb) (WOLFSSL *ssl, - const unsigned char **out, - unsigned char *outlen, - const unsigned char *in, - unsigned int inlen, - void *arg), void *arg) -{ - if (ctx != NULL) { - ctx->alpnSelect = cb; - ctx->alpnSelectArg = arg; - } -} - -void wolfSSL_CTX_set_next_protos_advertised_cb(WOLFSSL_CTX *s, - int (*cb) (WOLFSSL *ssl, - const unsigned char - **out, - unsigned int *outlen, - void *arg), void *arg) -{ - (void)s; - (void)cb; - (void)arg; - WOLFSSL_STUB("wolfSSL_CTX_set_next_protos_advertised_cb"); -} - -void wolfSSL_CTX_set_next_proto_select_cb(WOLFSSL_CTX *s, - int (*cb) (WOLFSSL *ssl, - unsigned char **out, - unsigned char *outlen, - const unsigned char *in, - unsigned int inlen, - void *arg), void *arg) -{ - (void)s; - (void)cb; - (void)arg; - WOLFSSL_STUB("wolfSSL_CTX_set_next_proto_select_cb"); -} - -void wolfSSL_get0_next_proto_negotiated(const WOLFSSL *s, - const unsigned char **data, unsigned *len) -{ - (void)s; - (void)data; - (void)len; - WOLFSSL_STUB("wolfSSL_get0_next_proto_negotiated"); -} -#endif /* HAVE_ALPN */ - -#endif /* WOLFSSL_NGINX / WOLFSSL_HAPROXY */ #if defined(OPENSSL_EXTRA) || defined(HAVE_CURL) -int wolfSSL_curve_is_disabled(const WOLFSSL* ssl, word16 curve_id) -{ - int ret = 0; - - WOLFSSL_ENTER("wolfSSL_curve_is_disabled"); - WOLFSSL_MSG_EX("wolfSSL_curve_is_disabled checking for %d", curve_id); - - /* (curve_id >= WOLFSSL_FFDHE_START) - DH parameters are never disabled. */ - if (curve_id < WOLFSSL_FFDHE_START) { - if (curve_id > WOLFSSL_ECC_MAX_AVAIL) { - WOLFSSL_MSG("Curve id out of supported range"); - /* Disabled if not in valid range. */ - ret = 1; - } - else if (curve_id >= 32) { - /* 0 is for invalid and 1-14 aren't used otherwise. */ - ret = (ssl->disabledCurves & (1U << (curve_id - 32))) != 0; - } - else { - ret = (ssl->disabledCurves & (1U << curve_id)) != 0; - } - } - - WOLFSSL_LEAVE("wolfSSL_curve_is_disabled", ret); - return ret; -} #if (defined(HAVE_ECC) || \ defined(HAVE_CURVE25519) || defined(HAVE_CURVE448)) @@ -17576,25 +14116,6 @@ leave: return ret; } -int wolfSSL_CTX_set1_curves_list(WOLFSSL_CTX* ctx, const char* names) -{ - WOLFSSL_ENTER("wolfSSL_CTX_set1_curves_list"); - if (ctx == NULL || names == NULL) { - WOLFSSL_MSG("ctx or names was NULL"); - return WOLFSSL_FAILURE; - } - return set_curves_list(NULL, ctx, names, 1); -} - -int wolfSSL_set1_curves_list(WOLFSSL* ssl, const char* names) -{ - WOLFSSL_ENTER("wolfSSL_set1_curves_list"); - if (ssl == NULL || names == NULL) { - WOLFSSL_MSG("ssl or names was NULL"); - return WOLFSSL_FAILURE; - } - return set_curves_list(ssl, NULL, names, 1); -} #endif /* (HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448) */ #endif /* OPENSSL_EXTRA || HAVE_CURL */ @@ -17693,142 +14214,11 @@ void wolfSSL_OPENSSL_cleanse(void *ptr, size_t len) ForceZero(ptr, (word32)len); } -int wolfSSL_CTX_set_alpn_protos(WOLFSSL_CTX *ctx, const unsigned char *p, - unsigned int p_len) -{ - WOLFSSL_ENTER("wolfSSL_CTX_set_alpn_protos"); - if (ctx == NULL || p == NULL) - return BAD_FUNC_ARG; - if (ctx->alpn_cli_protos != NULL) { - XFREE((void*)ctx->alpn_cli_protos, ctx->heap, DYNAMIC_TYPE_OPENSSL); - } - - ctx->alpn_cli_protos = (const unsigned char*)XMALLOC(p_len, - ctx->heap, DYNAMIC_TYPE_OPENSSL); - if (ctx->alpn_cli_protos == NULL) { -#if defined(WOLFSSL_ERROR_CODE_OPENSSL) - /* 0 on success in OpenSSL, non-0 on failure in OpenSSL - * the function reverses the return value convention. - */ - return 1; -#else - return WOLFSSL_FAILURE; -#endif - } - XMEMCPY((void*)ctx->alpn_cli_protos, p, p_len); - ctx->alpn_cli_protos_len = p_len; - -#if defined(WOLFSSL_ERROR_CODE_OPENSSL) - /* 0 on success in OpenSSL, non-0 on failure in OpenSSL - * the function reverses the return value convention. - */ - return 0; -#else - return WOLFSSL_SUCCESS; -#endif -} - - -#ifdef HAVE_ALPN -#ifndef NO_BIO -/* Sets the ALPN extension protos - * - * example format is - * unsigned char p[] = { - * 8, 'h', 't', 't', 'p', '/', '1', '.', '1' - * }; - * - * returns WOLFSSL_SUCCESS on success */ -int wolfSSL_set_alpn_protos(WOLFSSL* ssl, - const unsigned char* p, unsigned int p_len) -{ - char* pt = NULL; - unsigned int ptIdx; - unsigned int sz; - unsigned int idx = 0; - /* RFC 7301: a server that does not select any of the client's offered - * protocols MUST send no_application_protocol. Match that contract on - * the OpenSSL-compat surface rather than silently continuing. */ - int alpn_opt = WOLFSSL_ALPN_FAILED_ON_MISMATCH; - int ret; - - WOLFSSL_ENTER("wolfSSL_set_alpn_protos"); - - if (ssl == NULL || p_len <= 1 || p == NULL) { -#if defined(WOLFSSL_ERROR_CODE_OPENSSL) - /* 0 on success in OpenSSL, non-0 on failure in OpenSSL - * the function reverses the return value convention. - */ - return 1; -#else - return WOLFSSL_FAILURE; -#endif - } - - /* Replacing leading number with trailing ',' and adding '\0'. */ - pt = (char*)XMALLOC(p_len + 1, ssl->heap, DYNAMIC_TYPE_OPENSSL); - if (pt == NULL) { -#if defined(WOLFSSL_ERROR_CODE_OPENSSL) - /* 0 on success in OpenSSL, non-0 on failure in OpenSSL - * the function reverses the return value convention. - */ - return 1; -#else - return WOLFSSL_FAILURE; -#endif - } - - ptIdx = 0; - /* convert into comma separated list */ - while (idx < p_len - 1) { - unsigned int i; - - sz = p[idx++]; - if (idx + sz > p_len) { - WOLFSSL_MSG("Bad list format"); - XFREE(pt, ssl->heap, DYNAMIC_TYPE_OPENSSL); - #if defined(WOLFSSL_ERROR_CODE_OPENSSL) - /* 0 on success in OpenSSL, non-0 on failure in OpenSSL - * the function reverses the return value convention. - */ - return 1; - #else - return WOLFSSL_FAILURE; - #endif - } - if (sz > 0) { - for (i = 0; i < sz; i++) { - pt[ptIdx++] = p[idx++]; - } - if (idx < p_len - 1) { - pt[ptIdx++] = ','; - } - } - } - pt[ptIdx++] = '\0'; - - /* clears out all current ALPN extensions set */ - TLSX_Remove(&ssl->extensions, TLSX_APPLICATION_LAYER_PROTOCOL, ssl->heap); - - ret = wolfSSL_UseALPN(ssl, pt, ptIdx, (byte)alpn_opt); - XFREE(pt, ssl->heap, DYNAMIC_TYPE_OPENSSL); -#if defined(WOLFSSL_ERROR_CODE_OPENSSL) - /* 0 on success in OpenSSL, non-0 on failure in OpenSSL - * the function reverses the return value convention. - */ - if (ret != WOLFSSL_SUCCESS) - return 1; - return 0; -#else - if (ret != WOLFSSL_SUCCESS) - return WOLFSSL_FAILURE; - return WOLFSSL_SUCCESS; -#endif -} -#endif /* !NO_BIO */ -#endif /* HAVE_ALPN */ #endif /* OPENSSL_EXTRA */ +#define WOLFSSL_SSL_API_EXT_INCLUDED +#include "src/ssl_api_ext.c" + #if defined(OPENSSL_EXTRA) #ifndef NO_BIO @@ -18659,421 +15049,6 @@ void wolfSSL_ERR_remove_state(unsigned long id) #endif /* OPENSSL_EXTRA */ -#ifdef WOLFSSL_STATIC_EPHEMERAL -int wolfSSL_StaticEphemeralKeyLoad(WOLFSSL* ssl, int keyAlgo, void* keyPtr) -{ - int ret; - word32 idx = 0; - DerBuffer* der = NULL; - - if (ssl == NULL || ssl->ctx == NULL || keyPtr == NULL) { - return BAD_FUNC_ARG; - } - -#ifndef SINGLE_THREADED - if (!ssl->ctx->staticKELockInit) { - return BUFFER_E; /* no keys set */ - } - ret = wc_LockMutex(&ssl->ctx->staticKELock); - if (ret != 0) { - return ret; - } -#endif - - ret = BUFFER_E; /* set default error */ - switch (keyAlgo) { - #ifndef NO_DH - case WC_PK_TYPE_DH: - if (ssl != NULL) - der = ssl->staticKE.dhKey; - if (der == NULL) - der = ssl->ctx->staticKE.dhKey; - if (der != NULL) { - DhKey* key = (DhKey*)keyPtr; - WOLFSSL_MSG("Using static DH key"); - ret = wc_DhKeyDecode(der->buffer, &idx, key, der->length); - } - break; - #endif - #ifdef HAVE_ECC - case WC_PK_TYPE_ECDH: - if (ssl != NULL) - der = ssl->staticKE.ecKey; - if (der == NULL) - der = ssl->ctx->staticKE.ecKey; - if (der != NULL) { - ecc_key* key = (ecc_key*)keyPtr; - WOLFSSL_MSG("Using static ECDH key"); - ret = wc_EccPrivateKeyDecode(der->buffer, &idx, key, - der->length); - } - break; - #endif - #ifdef HAVE_CURVE25519 - case WC_PK_TYPE_CURVE25519: - if (ssl != NULL) - der = ssl->staticKE.x25519Key; - if (der == NULL) - der = ssl->ctx->staticKE.x25519Key; - if (der != NULL) { - curve25519_key* key = (curve25519_key*)keyPtr; - WOLFSSL_MSG("Using static X25519 key"); - - #ifdef WOLFSSL_CURVE25519_BLINDING - ret = wc_curve25519_set_rng(key, ssl->rng); - if (ret == 0) - #endif - ret = wc_Curve25519PrivateKeyDecode(der->buffer, &idx, key, - der->length); - } - break; - #endif - #ifdef HAVE_CURVE448 - case WC_PK_TYPE_CURVE448: - if (ssl != NULL) - der = ssl->staticKE.x448Key; - if (der == NULL) - der = ssl->ctx->staticKE.x448Key; - if (der != NULL) { - curve448_key* key = (curve448_key*)keyPtr; - WOLFSSL_MSG("Using static X448 key"); - ret = wc_Curve448PrivateKeyDecode(der->buffer, &idx, key, - der->length); - } - break; - #endif - default: - /* not supported */ - ret = NOT_COMPILED_IN; - break; - } - -#ifndef SINGLE_THREADED - wc_UnLockMutex(&ssl->ctx->staticKELock); -#endif - return ret; -} - -static int SetStaticEphemeralKey(WOLFSSL_CTX* ctx, - StaticKeyExchangeInfo_t* staticKE, int keyAlgo, const char* key, - unsigned int keySz, int format, void* heap) -{ - int ret = 0; - DerBuffer* der = NULL; - byte* keyBuf = NULL; -#ifndef NO_FILESYSTEM - const char* keyFile = NULL; -#endif - - /* allow empty key to free buffer */ - if (staticKE == NULL || (key == NULL && keySz > 0)) { - return BAD_FUNC_ARG; - } - - WOLFSSL_ENTER("SetStaticEphemeralKey"); - - /* if just free'ing key then skip loading */ - if (key != NULL) { - #ifndef NO_FILESYSTEM - /* load file from filesystem */ - if (key != NULL && keySz == 0) { - size_t keyBufSz = 0; - keyFile = (const char*)key; - ret = wc_FileLoad(keyFile, &keyBuf, &keyBufSz, heap); - if (ret != 0) { - return ret; - } - keySz = (unsigned int)keyBufSz; - } - else - #endif - { - /* use as key buffer directly */ - keyBuf = (byte*)key; - } - - if (format == WOLFSSL_FILETYPE_PEM) { - #ifdef WOLFSSL_PEM_TO_DER - int keyFormat = 0; - ret = PemToDer(keyBuf, keySz, PRIVATEKEY_TYPE, &der, - heap, NULL, &keyFormat); - /* auto detect key type */ - if (ret == 0 && keyAlgo == WC_PK_TYPE_NONE) { - if (keyFormat == ECDSAk) - keyAlgo = WC_PK_TYPE_ECDH; - else if (keyFormat == X25519k) - keyAlgo = WC_PK_TYPE_CURVE25519; - else - keyAlgo = WC_PK_TYPE_DH; - } - #else - ret = NOT_COMPILED_IN; - #endif - } - else { - /* Detect PK type (if required) */ - #ifdef HAVE_ECC - if (keyAlgo == WC_PK_TYPE_NONE) { - word32 idx = 0; - WC_DECLARE_VAR(eccKey, ecc_key, 1, heap); - WC_ALLOC_VAR_EX(eccKey, ecc_key, 1, heap, DYNAMIC_TYPE_ECC, - ret = MEMORY_E); - if (ret == 0) - ret = wc_ecc_init_ex(eccKey, heap, INVALID_DEVID); - if (ret == 0) { - ret = wc_EccPrivateKeyDecode(keyBuf, &idx, eccKey, keySz); - if (ret == 0) - keyAlgo = WC_PK_TYPE_ECDH; - wc_ecc_free(eccKey); - ret = 0; /* clear error to enable key-type detect cascade */ - } - WC_FREE_VAR_EX(eccKey, heap, DYNAMIC_TYPE_ECC); - } - #endif - #if !defined(NO_DH) && defined(WOLFSSL_DH_EXTRA) - if (keyAlgo == WC_PK_TYPE_NONE) { - word32 idx = 0; - WC_DECLARE_VAR(dhKey, DhKey, 1, heap); - WC_ALLOC_VAR_EX(dhKey, DhKey, 1, heap, DYNAMIC_TYPE_DH, - ret = MEMORY_E); - if (ret == 0) - ret = wc_InitDhKey_ex(dhKey, heap, INVALID_DEVID); - if (ret == 0) { - ret = wc_DhKeyDecode(keyBuf, &idx, dhKey, keySz); - if (ret == 0) - keyAlgo = WC_PK_TYPE_DH; - wc_FreeDhKey(dhKey); - ret = 0; /* clear error to enable key-type detect cascade */ - } - WC_FREE_VAR_EX(dhKey, heap, DYNAMIC_TYPE_DH); - } - #endif - #ifdef HAVE_CURVE25519 - if (keyAlgo == WC_PK_TYPE_NONE) { - word32 idx = 0; - WC_DECLARE_VAR(x25519Key, curve25519_key, 1, heap); - WC_ALLOC_VAR_EX(x25519Key, curve25519_key, 1, heap, - DYNAMIC_TYPE_CURVE25519, ret = MEMORY_E); - if (ret == 0) - ret = wc_curve25519_init_ex(x25519Key, heap, INVALID_DEVID); - if (ret == 0) { - ret = wc_Curve25519PrivateKeyDecode(keyBuf, &idx, - x25519Key, keySz); - if (ret == 0) - keyAlgo = WC_PK_TYPE_CURVE25519; - wc_curve25519_free(x25519Key); - ret = 0; /* clear error to enable key-type detect cascade */ - } - WC_FREE_VAR_EX(x25519Key, heap, DYNAMIC_TYPE_CURVE25519); - } - #endif - #ifdef HAVE_CURVE448 - if (keyAlgo == WC_PK_TYPE_NONE) { - word32 idx = 0; - WC_DECLARE_VAR(x448Key, curve448_key, 1, heap); - WC_ALLOC_VAR_EX(x448Key, curve448_key, 1, heap, - DYNAMIC_TYPE_CURVE448, ret = MEMORY_E); - if (ret == 0) - ret = wc_curve448_init(x448Key); - if (ret == 0) { - ret = wc_Curve448PrivateKeyDecode(keyBuf, &idx, x448Key, - keySz); - if (ret == 0) - keyAlgo = WC_PK_TYPE_CURVE448; - wc_curve448_free(x448Key); - ret = 0; /* clear error to enable key-type detect cascade */ - } - WC_FREE_VAR_EX(x448Key, heap, DYNAMIC_TYPE_CURVE448); - } - #endif - - if (keyAlgo != WC_PK_TYPE_NONE) { - ret = AllocDer(&der, keySz, PRIVATEKEY_TYPE, heap); - if (ret == 0) { - XMEMCPY(der->buffer, keyBuf, keySz); - } - } - } - } - -#ifndef NO_FILESYSTEM - /* done with keyFile buffer */ - if (keyFile && keyBuf) { - ForceZero(keyBuf, keySz); - XFREE(keyBuf, heap, DYNAMIC_TYPE_TMP_BUFFER); - } -#endif - -#ifndef SINGLE_THREADED - if (ret == 0 && !ctx->staticKELockInit) { - ret = wc_InitMutex(&ctx->staticKELock); - if (ret == 0) { - ctx->staticKELockInit = 1; - } - } -#endif - if (ret == 0 - #ifndef SINGLE_THREADED - && (ret = wc_LockMutex(&ctx->staticKELock)) == 0 - #endif - ) { - switch (keyAlgo) { - #ifndef NO_DH - case WC_PK_TYPE_DH: - FreeDer(&staticKE->dhKey); - staticKE->dhKey = der; der = NULL; - break; - #endif - #ifdef HAVE_ECC - case WC_PK_TYPE_ECDH: - FreeDer(&staticKE->ecKey); - staticKE->ecKey = der; der = NULL; - break; - #endif - #ifdef HAVE_CURVE25519 - case WC_PK_TYPE_CURVE25519: - FreeDer(&staticKE->x25519Key); - staticKE->x25519Key = der; der = NULL; - break; - #endif - #ifdef HAVE_CURVE448 - case WC_PK_TYPE_CURVE448: - FreeDer(&staticKE->x448Key); - staticKE->x448Key = der; der = NULL; - break; - #endif - default: - /* not supported */ - ret = NOT_COMPILED_IN; - break; - } - - #ifndef SINGLE_THREADED - wc_UnLockMutex(&ctx->staticKELock); - #endif - } - - if (ret != 0) { - FreeDer(&der); - } - - (void)ctx; /* not used for single threaded */ - - WOLFSSL_LEAVE("SetStaticEphemeralKey", ret); - - return ret; -} - -int wolfSSL_CTX_set_ephemeral_key(WOLFSSL_CTX* ctx, int keyAlgo, - const char* key, unsigned int keySz, int format) -{ - if (ctx == NULL) { - return BAD_FUNC_ARG; - } - return SetStaticEphemeralKey(ctx, &ctx->staticKE, keyAlgo, - key, keySz, format, ctx->heap); -} -int wolfSSL_set_ephemeral_key(WOLFSSL* ssl, int keyAlgo, - const char* key, unsigned int keySz, int format) -{ - if (ssl == NULL || ssl->ctx == NULL) { - return BAD_FUNC_ARG; - } - return SetStaticEphemeralKey(ssl->ctx, &ssl->staticKE, keyAlgo, - key, keySz, format, ssl->heap); -} - -static int GetStaticEphemeralKey(WOLFSSL_CTX* ctx, WOLFSSL* ssl, - int keyAlgo, const unsigned char** key, unsigned int* keySz) -{ - int ret = 0; - DerBuffer* der = NULL; - - if (key) *key = NULL; - if (keySz) *keySz = 0; - -#ifndef SINGLE_THREADED - if (ctx->staticKELockInit && - (ret = wc_LockMutex(&ctx->staticKELock)) != 0) { - return ret; - } -#endif - - switch (keyAlgo) { - #ifndef NO_DH - case WC_PK_TYPE_DH: - if (ssl != NULL) - der = ssl->staticKE.dhKey; - if (der == NULL) - der = ctx->staticKE.dhKey; - break; - #endif - #ifdef HAVE_ECC - case WC_PK_TYPE_ECDH: - if (ssl != NULL) - der = ssl->staticKE.ecKey; - if (der == NULL) - der = ctx->staticKE.ecKey; - break; - #endif - #ifdef HAVE_CURVE25519 - case WC_PK_TYPE_CURVE25519: - if (ssl != NULL) - der = ssl->staticKE.x25519Key; - if (der == NULL) - der = ctx->staticKE.x25519Key; - break; - #endif - #ifdef HAVE_CURVE448 - case WC_PK_TYPE_CURVE448: - if (ssl != NULL) - der = ssl->staticKE.x448Key; - if (der == NULL) - der = ctx->staticKE.x448Key; - break; - #endif - default: - /* not supported */ - ret = NOT_COMPILED_IN; - break; - } - - if (der) { - if (key) - *key = der->buffer; - if (keySz) - *keySz = der->length; - } - -#ifndef SINGLE_THREADED - wc_UnLockMutex(&ctx->staticKELock); -#endif - - return ret; -} - -/* returns pointer to currently loaded static ephemeral as ASN.1 */ -/* this can be converted to PEM using wc_DerToPem */ -int wolfSSL_CTX_get_ephemeral_key(WOLFSSL_CTX* ctx, int keyAlgo, - const unsigned char** key, unsigned int* keySz) -{ - if (ctx == NULL) { - return BAD_FUNC_ARG; - } - - return GetStaticEphemeralKey(ctx, NULL, keyAlgo, key, keySz); -} -int wolfSSL_get_ephemeral_key(WOLFSSL* ssl, int keyAlgo, - const unsigned char** key, unsigned int* keySz) -{ - if (ssl == NULL || ssl->ctx == NULL) { - return BAD_FUNC_ARG; - } - - return GetStaticEphemeralKey(ssl->ctx, ssl, keyAlgo, key, keySz); -} - -#endif /* WOLFSSL_STATIC_EPHEMERAL */ #if defined(OPENSSL_EXTRA) /* wolfSSL_THREADID_current is provided as a compat API with @@ -19099,40 +15074,6 @@ unsigned long wolfSSL_THREADID_hash(const WOLFSSL_CRYPTO_THREADID* id) (void)id; return 0UL; } -/* wolfSSL_set_ecdh_auto is provided as compatible API with - * SSL_set_ecdh_auto to enable auto ecdh curve selection functionality. - * Since this functionality is enabled by default in wolfSSL, - * this API exists as a stub. - */ -int wolfSSL_set_ecdh_auto(WOLFSSL* ssl, int onoff) -{ - (void)ssl; - (void)onoff; - return WOLFSSL_SUCCESS; -} -/* wolfSSL_CTX_set_ecdh_auto is provided as compatible API with - * SSL_CTX_set_ecdh_auto to enable auto ecdh curve selection functionality. - * Since this functionality is enabled by default in wolfSSL, - * this API exists as a stub. - */ -int wolfSSL_CTX_set_ecdh_auto(WOLFSSL_CTX* ctx, int onoff) -{ - (void)ctx; - (void)onoff; - return WOLFSSL_SUCCESS; -} - -/* wolfSSL_CTX_set_dh_auto is provided as compatible API with - * SSL_CTX_set_dh_auto to enable auto dh selection functionality. - * Since this functionality is enabled by default in wolfSSL, - * this API exists as a stub. - */ -int wolfSSL_CTX_set_dh_auto(WOLFSSL_CTX* ctx, int onoff) -{ - (void)ctx; - (void)onoff; - return WOLFSSL_SUCCESS; -} /** * Set security level (wolfSSL doesn't support setting the security level). diff --git a/src/ssl_api_cert.c b/src/ssl_api_cert.c index ed471be105..dbb95d5f56 100644 --- a/src/ssl_api_cert.c +++ b/src/ssl_api_cert.c @@ -42,6 +42,7 @@ int wolfSSL_CTX_mutual_auth(WOLFSSL_CTX* ctx, int req) { if (ctx == NULL) return BAD_FUNC_ARG; + /* Mutual authentication is a server-side only setting. */ if (ctx->method->side != WOLFSSL_SERVER_END) return SIDE_ERROR; @@ -63,6 +64,7 @@ int wolfSSL_mutual_auth(WOLFSSL* ssl, int req) { if (ssl == NULL) return BAD_FUNC_ARG; + /* Mutual authentication is a server-side only setting. */ if (ssl->options.side != WOLFSSL_SERVER_END) return SIDE_ERROR; @@ -81,7 +83,8 @@ WOLFSSL_CERT_MANAGER* wolfSSL_CTX_GetCertManager(WOLFSSL_CTX* ctx) { WOLFSSL_CERT_MANAGER* cm = NULL; - if (ctx) + /* The certificate manager is owned by the context. */ + if (ctx != NULL) cm = ctx->cm; return cm; @@ -98,6 +101,7 @@ void wolfSSL_CTX_set_verify_depth(WOLFSSL_CTX *ctx, int depth) { WOLFSSL_ENTER("wolfSSL_CTX_set_verify_depth"); + /* Reject out-of-range depths; valid range is 0 to MAX_CHAIN_DEPTH. */ if ((ctx == NULL) || (depth < 0) || (depth > MAX_CHAIN_DEPTH)) { WOLFSSL_MSG("Bad depth argument, too large or less than 0"); } @@ -121,6 +125,8 @@ long wolfSSL_CTX_get_verify_depth(WOLFSSL_CTX* ctx) ret = BAD_FUNC_ARG; } else { + /* A configurable depth is only tracked with the OpenSSL extra APIs; + * otherwise the fixed maximum chain depth applies. */ #ifndef OPENSSL_EXTRA ret = MAX_CHAIN_DEPTH; #else @@ -145,6 +151,8 @@ long wolfSSL_get_verify_depth(WOLFSSL* ssl) ret = BAD_FUNC_ARG; } else { + /* A configurable depth is only tracked with the OpenSSL extra APIs; + * otherwise the fixed maximum chain depth applies. */ #ifndef OPENSSL_EXTRA ret = MAX_CHAIN_DEPTH; #else @@ -168,7 +176,7 @@ long wolfSSL_get_verify_depth(WOLFSSL* ssl) static int isArrayUnique(const char* buf, size_t len) { size_t i; - /* check the array is unique */ + /* Check the array is unique. */ for (i = 0; i < len - 1; ++i) { size_t j; for (j = i + 1; j < len; ++j) { @@ -260,6 +268,7 @@ int wolfSSL_CTX_set_client_cert_type(WOLFSSL_CTX* ctx, const char* buf, int len) ret = BAD_FUNC_ARG; } else { + /* A side value of 1 records these as the client certificate types. */ ret = set_cert_type(&ctx->rpkConfig, 1, buf, len); } @@ -284,6 +293,7 @@ int wolfSSL_CTX_set_server_cert_type(WOLFSSL_CTX* ctx, const char* buf, int len) ret = BAD_FUNC_ARG; } else { + /* A side value of 0 records these as the server certificate types. */ ret = set_cert_type(&ctx->rpkConfig, 0, buf, len); } @@ -308,6 +318,7 @@ int wolfSSL_set_client_cert_type(WOLFSSL* ssl, const char* buf, int len) ret = BAD_FUNC_ARG; } else { + /* A side value of 1 records these as the client certificate types. */ ret = set_cert_type(&ssl->options.rpkConfig, 1, buf, len); } @@ -332,6 +343,7 @@ int wolfSSL_set_server_cert_type(WOLFSSL* ssl, const char* buf, int len) ret = BAD_FUNC_ARG; } else { + /* A side value of 0 records these as the server certificate types. */ ret = set_cert_type(&ssl->options.rpkConfig, 0, buf, len); } @@ -627,7 +639,7 @@ int wolfSSL_verify_client_post_handshake(WOLFSSL* ssl) ret = wolfSSL_request_certificate(ssl); if (ret != 1) { /* Special logging for wrong protocol version. */ - if ((ssl != NULL) && !IsAtLeastTLSv1_3(ssl->version)) { + if ((ssl != NULL) && (!IsAtLeastTLSv1_3(ssl->version))) { WOLFSSL_ERROR(UNSUPPORTED_PROTO_VERSION); } else { @@ -851,7 +863,7 @@ int wolfSSL_UnloadCertsKeys(WOLFSSL* ssl) ret = BAD_FUNC_ARG; } else { - if (ssl->buffers.weOwnCert && !ssl->keepCert) { + if (ssl->buffers.weOwnCert && (!ssl->keepCert)) { WOLFSSL_MSG("Unloading cert"); FreeDer(&ssl->buffers.certificate); #ifdef KEEP_OUR_CERT @@ -869,7 +881,7 @@ int wolfSSL_UnloadCertsKeys(WOLFSSL* ssl) if (ssl->buffers.weOwnKey) { WOLFSSL_MSG("Unloading key"); - if (ssl->buffers.key != NULL && ssl->buffers.key->buffer != NULL) + if ((ssl->buffers.key != NULL) && (ssl->buffers.key->buffer != NULL)) ForceZero(ssl->buffers.key->buffer, ssl->buffers.key->length); FreeDer(&ssl->buffers.key); #ifdef WOLFSSL_BLIND_PRIVATE_KEY @@ -881,8 +893,8 @@ int wolfSSL_UnloadCertsKeys(WOLFSSL* ssl) #ifdef WOLFSSL_DUAL_ALG_CERTS if (ssl->buffers.weOwnAltKey) { WOLFSSL_MSG("Unloading alt key"); - if (ssl->buffers.altKey != NULL && - ssl->buffers.altKey->buffer != NULL) { + if ((ssl->buffers.altKey != NULL) && + (ssl->buffers.altKey->buffer != NULL)) { ForceZero(ssl->buffers.altKey->buffer, ssl->buffers.altKey->length); } @@ -1028,11 +1040,13 @@ static int add_to_ca_names_list(WOLFSSL_STACK* ca_names, WOLFSSL_X509* x509) int ret = 1; WOLFSSL_X509_NAME *nameCopy = NULL; + /* The list owns its names, so push a copy of the subject name. */ nameCopy = wolfSSL_X509_NAME_dup(wolfSSL_X509_get_subject_name(x509)); if (nameCopy == NULL) { WOLFSSL_MSG("wolfSSL_X509_NAME_dup error"); ret = 0; } + /* On push failure the copy is not owned by the list - free it here. */ else if (wolfSSL_sk_X509_NAME_push(ca_names, nameCopy) <= 0) { WOLFSSL_MSG("wolfSSL_sk_X509_NAME_push error"); wolfSSL_X509_NAME_free(nameCopy); @@ -1435,7 +1449,7 @@ WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_load_client_CA_file(const char* fname) } /* Read each certificate in the chain out of the file. */ - while (!err && wolfSSL_PEM_read_bio_X509(bio, &cert, NULL, NULL) != NULL) { + while ((!err) && (wolfSSL_PEM_read_bio_X509(bio, &cert, NULL, NULL) != NULL)) { WOLFSSL_X509_NAME *nameCopy; /* Need a persistent copy of the subject name. */ @@ -1730,15 +1744,15 @@ WOLFSSL_X509* wolfSSL_get_certificate(WOLFSSL* ssl) * a new X509. This maintains pointer compatibility with * applications (like nginx OCSP stapling) that use the X509 pointer * from SSL_CTX_use_certificate as a lookup key. */ - if (ssl->ctx != NULL && ssl->ctx->ourCert != NULL) { + if ((ssl->ctx != NULL) && (ssl->ctx->ourCert != NULL)) { /* Compare cert buffers to make sure they are the same */ - if (ssl->buffers.certificate == NULL || - ssl->buffers.certificate->buffer == NULL || - (ssl->buffers.certificate->length == - ssl->ctx->certificate->length && - XMEMCMP(ssl->buffers.certificate->buffer, + if ((ssl->buffers.certificate == NULL) || + (ssl->buffers.certificate->buffer == NULL) || + ((ssl->buffers.certificate->length == + ssl->ctx->certificate->length) && + (XMEMCMP(ssl->buffers.certificate->buffer, ssl->ctx->certificate->buffer, - ssl->buffers.certificate->length) == 0)) { + ssl->buffers.certificate->length) == 0))) { return ssl->ctx->ourCert; } } @@ -1769,4 +1783,747 @@ WOLFSSL_X509* wolfSSL_get_certificate(WOLFSSL* ssl) #endif /* !NO_CERTS */ +#ifndef WOLFCRYPT_ONLY + +#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) +/* Get the index at which the object is stored in an X509 store context's + * external data. + * + * @return Index of the SSL/TLS object (0). + */ +int wolfSSL_get_ex_data_X509_STORE_CTX_idx(void) +{ + WOLFSSL_ENTER("wolfSSL_get_ex_data_X509_STORE_CTX_idx"); + + /* store SSL at index 0 */ + return 0; +} +#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */ + + +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) || \ + defined(OPENSSL_ALL) +/* Get the result of peer certificate verification. + * + * @param [in] ssl SSL/TLS object. + * @return Verification result code on success. + * @return WOLFSSL_X509_V_ERR_APPLICATION_VERIFICATION when ssl is NULL. + */ +long wolfSSL_get_verify_result(const WOLFSSL *ssl) +{ + long ret; + + if (ssl == NULL) { + /* Return a non-zero error so the OpenSSL-idiomatic + * "!= X509_V_OK" check does not mistake a NULL ssl for a + * successful verification (X509_V_OK is 0). */ + ret = WOLFSSL_X509_V_ERR_APPLICATION_VERIFICATION; + } + else { + /* Result of verifying the peer's certificate chain. */ + ret = (long)ssl->peerVerifyRet; + } + + return ret; +} +#endif + + +#if defined(OPENSSL_EXTRA) && defined(KEEP_PEER_CERT) && \ + defined(HAVE_EX_DATA) && !defined(NO_FILESYSTEM) +/* Compare the peer's certificate against a PEM certificate file. + * + * @param [in] ssl SSL/TLS object. + * @param [in] fname Path to a PEM certificate file. + * @return 0 when the certificates match. + * @return WOLFSSL_FATAL_ERROR when arguments are NULL or they do not match. + * @return WOLFSSL_BAD_FILE when the file cannot be read. + */ +int wolfSSL_cmp_peer_cert_to_file(WOLFSSL* ssl, const char *fname) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_cmp_peer_cert_to_file"); + + if ((ssl == NULL) || (fname == NULL)) { + ret = WOLFSSL_FATAL_ERROR; + } + else { + #ifdef WOLFSSL_SMALL_STACK + byte staticBuffer[1]; /* force heap usage */ + #else + byte staticBuffer[FILE_BUFFER_SIZE]; + #endif + byte* myBuf = staticBuffer; + XFILE file; + long sz = 0; + void* heap = ssl->ctx->heap; + WOLFSSL_X509* peer_cert = &ssl->peerCert; + DerBuffer* fileDer = NULL; + + /* Open the file and determine its size. From here, ret == 0 + * indicates processing is still on track. */ + file = XFOPEN(fname, "rb"); + ret = wolfssl_file_len(file, &sz); + /* Use a heap buffer when the file is bigger than the stack buffer. */ + if ((ret == 0) && (sz > (long)sizeof(staticBuffer))) { + WOLFSSL_MSG("Getting dynamic buffer"); + myBuf = (byte*)XMALLOC((size_t)sz, heap, DYNAMIC_TYPE_FILE); + if (myBuf == NULL) { + ret = WOLFSSL_FATAL_ERROR; + } + } + /* Read the whole file into the buffer. */ + if ((ret == 0) && (XFREAD(myBuf, 1, (size_t)sz, file) != (size_t)sz)) { + ret = WOLFSSL_FATAL_ERROR; + } + /* Convert the PEM file contents to DER. */ + if ((ret == 0) && (PemToDer(myBuf, sz, CERT_TYPE, &fileDer, heap, NULL, + NULL) != 0)) { + ret = WOLFSSL_FATAL_ERROR; + } + /* Peer certificate matches when the DER lengths and bytes are equal. */ + if ((ret == 0) && ((fileDer->length == 0) || + (fileDer->length != peer_cert->derCert->length) || + (XMEMCMP(peer_cert->derCert->buffer, fileDer->buffer, + fileDer->length) != 0))) { + ret = WOLFSSL_FATAL_ERROR; + } + + /* Dispose of the DER, any heap buffer and close the file. */ + FreeDer(&fileDer); + if (myBuf != staticBuffer) { + XFREE(myBuf, heap, DYNAMIC_TYPE_FILE); + } + if (file != XBADFILE) { + XFCLOSE(file); + } + } + + return ret; +} +#endif + + +#ifdef WOLFSSL_ALT_CERT_CHAINS +/* Determine whether the peer was verified using an alternate cert chain. + * + * @param [in] ssl SSL/TLS object. + * @return 1 when an alternate certificate chain was used. + * @return 0 otherwise, or when ssl is NULL. + */ +int wolfSSL_is_peer_alt_cert_chain(const WOLFSSL* ssl) +{ + return (ssl != NULL) && ssl->options.usingAltCertChain; +} +#endif /* WOLFSSL_ALT_CERT_CHAINS */ + + +#ifdef SESSION_CERTS + +#ifdef WOLFSSL_ALT_CERT_CHAINS +/* Get the peer's alternate certificate chain. + * + * @param [in] ssl SSL/TLS object. + * @return Alternate certificate chain on success. + * @return NULL when ssl is NULL. + */ +WOLFSSL_X509_CHAIN* wolfSSL_get_peer_alt_chain(WOLFSSL* ssl) +{ + WOLFSSL_X509_CHAIN* chain = NULL; + + WOLFSSL_ENTER("wolfSSL_get_peer_alt_chain"); + + if (ssl != NULL) { + /* The alternate chain is held within the session. */ + chain = &ssl->session->altChain; + } + + return chain; +} +#endif /* WOLFSSL_ALT_CERT_CHAINS */ + + +/* Get the peer's certificate chain. + * + * @param [in] ssl SSL/TLS object. + * @return Certificate chain on success. + * @return NULL when ssl is NULL. + */ +WOLFSSL_X509_CHAIN* wolfSSL_get_peer_chain(WOLFSSL* ssl) +{ + WOLFSSL_X509_CHAIN* chain = NULL; + + WOLFSSL_ENTER("wolfSSL_get_peer_chain"); + + if (ssl != NULL) { + /* The peer chain is held within the session. */ + chain = &ssl->session->chain; + } + + return chain; +} + + +/* Get the number of certificates in a certificate chain. + * + * @param [in] chain Certificate chain object. + * @return Number of certificates on success. + * @return 0 when chain is NULL. + */ +int wolfSSL_get_chain_count(WOLFSSL_X509_CHAIN* chain) +{ + int count = 0; + + WOLFSSL_ENTER("wolfSSL_get_chain_count"); + + if (chain != NULL) { + /* Number of certificates captured in the chain. */ + count = chain->count; + } + + return count; +} + + +/* Get the length, in bytes, of the DER certificate at an index in a chain. + * + * @param [in] chain Certificate chain object. + * @param [in] idx Index of the certificate in the chain. + * @return Length of the DER certificate in bytes on success. + * @return 0 when chain is NULL or idx is out of range. + */ +int wolfSSL_get_chain_length(WOLFSSL_X509_CHAIN* chain, int idx) +{ + int length = 0; + + WOLFSSL_ENTER("wolfSSL_get_chain_length"); + + if ((chain != NULL) && (idx >= 0) && (idx < chain->count)) { + /* DER length of the certificate stored at the given index. */ + length = chain->certs[idx].length; + } + + return length; +} + + +/* Get the DER certificate at an index in a certificate chain. + * + * @param [in] chain Certificate chain object. + * @param [in] idx Index of the certificate in the chain. + * @return Buffer holding the DER certificate on success. + * @return 0 when chain is NULL or idx is out of range. + */ +byte* wolfSSL_get_chain_cert(WOLFSSL_X509_CHAIN* chain, int idx) +{ + byte* cert = NULL; + + WOLFSSL_ENTER("wolfSSL_get_chain_cert"); + + if ((chain != NULL) && (idx >= 0) && (idx < chain->count)) { + /* DER buffer of the certificate stored at the given index. */ + cert = chain->certs[idx].buffer; + } + + return cert; +} + + +/* Decode DER certificate data into a WOLFSSL_X509 object. Defined in + * src/ssl.c. */ +static int DecodeToX509(WOLFSSL_X509* x509, const byte* in, int len); + +/* Get the certificate at an index in a chain as a new X509 object. + * + * The returned object must be freed by the caller with wolfSSL_X509_free(). + * + * @param [in] chain Certificate chain object. + * @param [in] idx Index of the certificate in the chain. + * @return Newly allocated X509 certificate object on success. + * @return NULL when chain is NULL, idx is out of range or on error. + */ +WOLFSSL_X509* wolfSSL_get_chain_X509(WOLFSSL_X509_CHAIN* chain, int idx) +{ + WOLFSSL_X509* x509 = NULL; + + WOLFSSL_ENTER("wolfSSL_get_chain_X509"); + + if ((chain != NULL) && (idx >= 0) && (idx < chain->count)) { + x509 = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), NULL, + DYNAMIC_TYPE_X509); + if (x509 == NULL) { + WOLFSSL_MSG("Failed alloc X509"); + } + else { + /* Pre-init with dynamicMemory=1 so DecodeToX509 skips its own + * InitX509 (and we still own the buffer for X509_free). */ + InitX509(x509, 1, NULL); + if (DecodeToX509(x509, chain->certs[idx].buffer, + chain->certs[idx].length) != 0) { + WOLFSSL_MSG("Failed to decode cert"); + wolfSSL_X509_free(x509); + x509 = NULL; + } + } + } + + return x509; +} + + +/* Get the certificate at an index in a chain as PEM. + * + * When buf is NULL, the length required is returned in outLen. + * + * @param [in] chain Certificate chain object. + * @param [in] idx Index of the certificate in the chain. + * @param [out] buf Buffer to hold PEM. May be NULL to get the length. + * @param [in] inLen Length of buffer in bytes. + * @param [out] outLen Length of PEM data in bytes. + * @return WOLFSSL_SUCCESS on success. + * @return LENGTH_ONLY_E when buf is NULL and outLen has been set. + * @return BAD_FUNC_ARG when a required argument is NULL or idx is invalid. + * @return WOLFSSL_FAILURE on error. + */ +int wolfSSL_get_chain_cert_pem(WOLFSSL_X509_CHAIN* chain, int idx, + unsigned char* buf, int inLen, int* outLen) +{ +#ifdef WOLFSSL_DER_TO_PEM + int ret = WOLFSSL_SUCCESS; + + WOLFSSL_ENTER("wolfSSL_get_chain_cert_pem"); + if ((chain == NULL) || (outLen == NULL) || (idx < 0) || + (idx >= wolfSSL_get_chain_count(chain))) { + ret = BAD_FUNC_ARG; + } + /* Delegate to wc_DerToPem when DER-to-PEM is available. */ + if (ret == WOLFSSL_SUCCESS) { + if (buf == NULL) { + inLen = 0; + } + else if (inLen < 0) { + ret = BAD_FUNC_ARG; + } + } + if (ret == WOLFSSL_SUCCESS) { + int n = wc_DerToPem(chain->certs[idx].buffer, + (word32)chain->certs[idx].length, buf, (word32)inLen, CERT_TYPE); + if (n < 0) { + if (buf == NULL) { + ret = WOLFSSL_FAILURE; + } + else { + ret = n; + } + } + else { + *outLen = n; + if (buf == NULL) { + ret = WC_NO_ERR_TRACE(LENGTH_ONLY_E); + } + } + } + + return ret; +#elif defined(WOLFSSL_PEM_TO_DER) + int ret = WOLFSSL_SUCCESS; + const char* header = NULL; + const char* footer = NULL; + int headerLen; + int footerLen; + int i; + int err; + + WOLFSSL_ENTER("wolfSSL_get_chain_cert_pem"); + if ((chain == NULL) || (outLen == NULL) || (idx < 0) || + (idx >= wolfSSL_get_chain_count(chain))) { + ret = BAD_FUNC_ARG; + } + if (ret == WOLFSSL_SUCCESS) { + if ((err = wc_PemGetHeaderFooter(CERT_TYPE, &header, &footer)) != 0) { + ret = err; + } + } + if (ret == WOLFSSL_SUCCESS) { + headerLen = (int)XSTRLEN(header); + footerLen = (int)XSTRLEN(footer); + + /* Null output buffer returns size needed in outLen. */ + if (buf == NULL) { + word32 szNeeded = 0; + + if (Base64_Encode(chain->certs[idx].buffer, + (word32)chain->certs[idx].length, NULL, + &szNeeded) != WC_NO_ERR_TRACE(LENGTH_ONLY_E)) { + ret = WOLFSSL_FAILURE; + } + else { + *outLen = (int)szNeeded + headerLen + footerLen; + ret = WC_NO_ERR_TRACE(LENGTH_ONLY_E); + } + } + /* buf == NULL, ret will not be WOLFSSL_SUCCESS. */ + } + /* Don't even try when inLen is too short. */ + if ((ret == WOLFSSL_SUCCESS) && + (inLen < headerLen + footerLen + chain->certs[idx].length)) { + ret = BAD_FUNC_ARG; + } + if (ret == WOLFSSL_SUCCESS) { + /* Write the PEM header. */ + XMEMCPY(buf, header, (size_t)headerLen); + i = headerLen; + + /* Space left for Base64 data after header and before footer. */ + *outLen = inLen - headerLen - footerLen; + if ((err = Base64_Encode(chain->certs[idx].buffer, + (word32)chain->certs[idx].length, buf + i, + (word32*)outLen)) < 0) { + ret = err; + } + } + if (ret == WOLFSSL_SUCCESS) { + i += *outLen; + + /* Write the PEM footer. */ + XMEMCPY(buf + i, footer, (size_t)footerLen); + *outLen += headerLen + footerLen; + } + + return ret; +#else + (void)chain; + (void)idx; + (void)buf; + (void)inLen; + (void)outLen; + return WOLFSSL_FAILURE; +#endif /* WOLFSSL_PEM_TO_DER || WOLFSSL_DER_TO_PEM */ +} + +#endif /* SESSION_CERTS */ + + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO) || defined(WOLFSSL_HAPROXY) \ + || defined(WOLFSSL_NGINX) || defined(WOLFSSL_QT) +#ifndef NO_WOLFSSL_STUB +/* Clear the extra certificate chain set on the context. + * + * Not implemented - stub for OpenSSL compatibility. + * + * @param [in] ctx SSL/TLS context object. + * @return Result of the SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS control command. + */ +long wolfSSL_CTX_clear_extra_chain_certs(WOLFSSL_CTX* ctx) +{ + return wolfSSL_CTX_ctrl(ctx, SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS, 0L, NULL); +} +#endif + +/* Get the verify callback set on the object. + * + * @param [in] ssl SSL/TLS object. + * @return Verify callback on success. + * @return NULL when ssl is NULL or no callback is set. + */ +VerifyCallback wolfSSL_get_verify_callback(WOLFSSL* ssl) +{ + VerifyCallback cb = NULL; + + WOLFSSL_ENTER("wolfSSL_get_verify_callback"); + + if (ssl != NULL) { + /* Verify callback configured on the object. */ + cb = ssl->verifyCallback; + } + + return cb; +} + +#endif + +#if defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) +/* Get the verify callback set on the context. + * + * @param [in] ctx SSL/TLS context object. + * @return Verify callback on success. + * @return NULL when ctx is NULL or no callback is set. + */ +VerifyCallback wolfSSL_CTX_get_verify_callback(WOLFSSL_CTX* ctx) +{ + VerifyCallback cb = NULL; + + WOLFSSL_ENTER("wolfSSL_CTX_get_verify_callback"); + + if (ctx != NULL) { + /* Verify callback configured on the context. */ + cb = ctx->verifyCallback; + } + + return cb; +} + +#endif + +#if defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) || defined(HAVE_STUNNEL) || \ + defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(WOLFSSL_NGINX) + +/* Get the verification mode set on the object. + * + * TODO: Doesn't currently track SSL_VERIFY_CLIENT_ONCE. + * + * @param [in] ssl SSL/TLS object. + * @return Bitmask of WOLFSSL_VERIFY_* flags on success. + * @return WOLFSSL_FAILURE when ssl is NULL. + */ +int wolfSSL_get_verify_mode(const WOLFSSL* ssl) +{ + int mode = 0; + + WOLFSSL_ENTER("wolfSSL_get_verify_mode"); + + if (ssl == NULL) { + mode = WOLFSSL_FAILURE; + } + else if (ssl->options.verifyNone) { + /* VERIFY_NONE is exclusive of the other verify flags. */ + mode = WOLFSSL_VERIFY_NONE; + } + else { + /* Build the mode as a bitmask of the enabled verify flags. */ + if (ssl->options.verifyPeer) { + mode |= WOLFSSL_VERIFY_PEER; + } + if (ssl->options.failNoCert) { + mode |= WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT; + } + if (ssl->options.failNoCertxPSK) { + mode |= WOLFSSL_VERIFY_FAIL_EXCEPT_PSK; + } +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) + if (ssl->options.verifyPostHandshake) { + mode |= WOLFSSL_VERIFY_POST_HANDSHAKE; + } +#endif + } + + WOLFSSL_LEAVE("wolfSSL_get_verify_mode", mode); + return mode; +} + +/* Get the verification mode set on the context. + * + * @param [in] ctx SSL/TLS context object. + * @return Bitmask of WOLFSSL_VERIFY_* flags on success. + * @return WOLFSSL_FAILURE when ctx is NULL. + */ +int wolfSSL_CTX_get_verify_mode(const WOLFSSL_CTX* ctx) +{ + int mode = 0; + + WOLFSSL_ENTER("wolfSSL_CTX_get_verify_mode"); + + if (ctx == NULL) { + mode = WOLFSSL_FAILURE; + } + else if (ctx->verifyNone) { + /* VERIFY_NONE is exclusive of the other verify flags. */ + mode = WOLFSSL_VERIFY_NONE; + } + else { + /* Build the mode as a bitmask of the enabled verify flags. */ + if (ctx->verifyPeer) { + mode |= WOLFSSL_VERIFY_PEER; + } + if (ctx->failNoCert) { + mode |= WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT; + } + if (ctx->failNoCertxPSK) { + mode |= WOLFSSL_VERIFY_FAIL_EXCEPT_PSK; + } +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) + if (ctx->verifyPostHandshake) { + mode |= WOLFSSL_VERIFY_POST_HANDSHAKE; + } +#endif + } + + WOLFSSL_LEAVE("wolfSSL_CTX_get_verify_mode", mode); + return mode; +} + +#endif + + +#if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) || \ + defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) +/* Create a stack of X509 certificates from a DER encoded certificate chain. + * + * The chain buffer holds each certificate as: 3 byte length | X509 DER data. + * + * @param [in] der DER encoded certificate chain. + * @param [in] derLen Length of certificate chain buffer in bytes. + * @param [in] heap Dynamic memory hint. + * @param [out] chain Stack of X509 certificates. Holds as much of the + * chain as was created on failure. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE on allocation or decode error. + */ +static int wolfssl_certchain_to_x509_stack(byte* der, word32 derLen, + void* heap, WOLF_STACK_OF(X509)** chain) +{ + int ret = WOLFSSL_SUCCESS; + word32 idx; + word32 length; + WOLFSSL_STACK* node; + WOLFSSL_STACK* last = NULL; + + /* Create a new stack of WOLFSSL_X509 object from chain buffer. */ + for (idx = 0; idx < derLen; ) { + /* Need 3 bytes for the length of the DER encoded certificate. */ + if ((derLen - idx) < 3) { + ret = WOLFSSL_FAILURE; + break; + } + + /* Format: 3 byte length | X509 DER data. */ + ato24(der + idx, &length); + idx += 3; + + /* Ensure the DER encoded certificate is contained in the buffer. */ + if (length > (derLen - idx)) { + ret = WOLFSSL_FAILURE; + break; + } + + node = wolfSSL_sk_X509_new_null(); + if (node == NULL) { + ret = WOLFSSL_FAILURE; + break; + } + node->next = NULL; + + /* Create a new X509 from DER encoded data. */ + node->data.x509 = wolfSSL_X509_d2i_ex(NULL, der + idx, (int)length, + heap); + if (node->data.x509 == NULL) { + XFREE(node, NULL, DYNAMIC_TYPE_OPENSSL); + /* Return as much of the chain as we created. */ + ret = WOLFSSL_FAILURE; + break; + } + idx += length; + + /* Add object to the end of the stack. */ + if (last == NULL) { + node->num = 1; + *chain = node; + } + else { + (*chain)->num++; + last->next = node; + } + + last = node; + } + + return ret; +} + +/* Get the extra certificate chain set on the context as a stack of X509. + * + * Builds the stack from the context's certificate chain buffer when needed. + * + * @param [in] ctx SSL/TLS context object. + * @param [out] chain Stack of X509 certificates. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ctx or chain is NULL, or on allocation error. + */ +int wolfSSL_CTX_get_extra_chain_certs(WOLFSSL_CTX* ctx, + WOLF_STACK_OF(X509)** chain) +{ + int ret = WOLFSSL_SUCCESS; + + if ((ctx == NULL) || (chain == NULL)) { + ret = WOLFSSL_FAILURE; + } + else if (ctx->x509Chain != NULL) { + *chain = ctx->x509Chain; + } + else { + /* If there are no chains then success! */ + *chain = NULL; + if ((ctx->certChain != NULL) && (ctx->certChain->length != 0)) { + /* Build a stack of X509 from the DER certificate chain buffer. */ + ret = wolfssl_certchain_to_x509_stack(ctx->certChain->buffer, + ctx->certChain->length, ctx->heap, chain); + /* Cache the chain - holds as much as was created on failure. */ + ctx->x509Chain = *chain; + } + } + + return ret; +} + +/* Get the certificate chain set on the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [out] sk Stack of X509 certificates. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ctx or sk is NULL. + */ +int wolfSSL_CTX_get0_chain_certs(WOLFSSL_CTX *ctx, + WOLF_STACK_OF(WOLFSSL_X509) **sk) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_get0_chain_certs"); + + if ((ctx == NULL) || (sk == NULL)) { + WOLFSSL_MSG("Bad parameter"); + ret = WOLFSSL_FAILURE; + } + else { + /* This function should return ctx->x509Chain if it is populated, + * otherwise it should be populated from ctx->certChain. This matches + * the behavior of wolfSSL_CTX_get_extra_chain_certs, so it is used + * directly. */ + ret = wolfSSL_CTX_get_extra_chain_certs(ctx, sk); + } + + return ret; +} + +#ifdef KEEP_OUR_CERT +/* Get our certificate chain set on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [out] sk Stack of X509 certificates. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ssl or sk is NULL. + */ +int wolfSSL_get0_chain_certs(WOLFSSL *ssl, WOLF_STACK_OF(WOLFSSL_X509) **sk) +{ + int ret = WOLFSSL_SUCCESS; + + WOLFSSL_ENTER("wolfSSL_get0_chain_certs"); + + if ((ssl == NULL) || (sk == NULL)) { + WOLFSSL_MSG("Bad parameter"); + ret = WOLFSSL_FAILURE; + } + else { + /* Return our own certificate chain held on the object. */ + *sk = ssl->ourCertChain; + } + + return ret; +} +#endif + +#endif + +#endif /* !WOLFCRYPT_ONLY */ + #endif /* !WOLFSSL_SSL_API_CERT_INCLUDED */ diff --git a/src/ssl_api_dtls.c b/src/ssl_api_dtls.c new file mode 100644 index 0000000000..46ea02b567 --- /dev/null +++ b/src/ssl_api_dtls.c @@ -0,0 +1,1462 @@ +/* ssl_api_dtls.c + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL 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. + * + * wolfSSL 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 + +#if !defined(WOLFSSL_SSL_API_DTLS_INCLUDED) + #ifndef WOLFSSL_IGNORE_FILE_WARN + #warning ssl_api_dtls.c does not need to be compiled separately from ssl.c + #endif +#else + +#ifndef WOLFCRYPT_ONLY + +#ifdef WOLFSSL_DTLS +/* Set the file descriptor for an already connected DTLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] fd Connected socket file descriptor. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL. + */ +int wolfSSL_set_dtls_fd_connected(WOLFSSL* ssl, int fd) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_set_dtls_fd_connected"); + + if (ssl == NULL) { + return BAD_FUNC_ARG; + } + + ret = wolfSSL_set_fd(ssl, fd); + if (ret == WOLFSSL_SUCCESS) + ssl->buffers.dtlsCtx.connected = 1; + + return ret; +} +#endif + + +/* Determine whether the object is configured for DTLS. + * + * @param [in] ssl SSL/TLS object. + * @return 1 when using DTLS. + * @return 0 otherwise, or when ssl is NULL. + */ +int wolfSSL_dtls(WOLFSSL* ssl) +{ + int dtlsOpt = 0; + if (ssl) + dtlsOpt = ssl->options.dtls; + return dtlsOpt; +} + + +#ifndef WOLFSSL_LEANPSK +#if defined(WOLFSSL_DTLS) && defined(XINET_PTON) && \ + !defined(WOLFSSL_NO_SOCK) && defined(HAVE_SOCKADDR) +/* Create a DTLS peer address from a port and IPv4 address string. + * + * The returned object must be freed with wolfSSL_dtls_free_peer(). + * + * @param [in] port Port number. + * @param [in] ip Dotted-decimal IPv4 address string. + * @return Newly allocated peer address on success. + * @return NULL on allocation error or when the address is invalid. + */ +void* wolfSSL_dtls_create_peer(int port, char* ip) +{ + SOCKADDR_IN *addr; + addr = (SOCKADDR_IN*)XMALLOC(sizeof(*addr), NULL, + DYNAMIC_TYPE_SOCKADDR); + if (addr == NULL) { + return NULL; + } + + addr->sin_family = AF_INET; + addr->sin_port = XHTONS((word16)port); + if (XINET_PTON(AF_INET, ip, &addr->sin_addr) < 1) { + XFREE(addr, NULL, DYNAMIC_TYPE_SOCKADDR); + return NULL; + } + + return addr; +} + +/* Free a DTLS peer address created with wolfSSL_dtls_create_peer(). + * + * @param [in] addr Peer address to free. + * @return WOLFSSL_SUCCESS always. + */ +int wolfSSL_dtls_free_peer(void* addr) +{ + XFREE(addr, NULL, DYNAMIC_TYPE_SOCKADDR); + return WOLFSSL_SUCCESS; +} +#endif + +#ifdef WOLFSSL_DTLS +/* Store a socket address into a socket address holder, resizing as needed. + * + * A NULL or zero-length peer frees the holder's buffer. + * + * @param [in, out] sockAddr Socket address holder. + * @param [in] peer Socket address data, may be NULL to free. + * @param [in] peerSz Length of socket address data in bytes. + * @param [in] heap Heap hint for dynamic memory allocation. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE on allocation error. + */ +static int SockAddrSet(WOLFSSL_SOCKADDR* sockAddr, void* peer, + unsigned int peerSz, void* heap) +{ + if (peer == NULL || peerSz == 0) { + if (sockAddr->sa != NULL) + XFREE(sockAddr->sa, heap, DYNAMIC_TYPE_SOCKADDR); + sockAddr->sa = NULL; + sockAddr->sz = 0; + sockAddr->bufSz = 0; + return WOLFSSL_SUCCESS; + } + + if (peerSz > sockAddr->bufSz) { + if (sockAddr->sa != NULL) + XFREE(sockAddr->sa, heap, DYNAMIC_TYPE_SOCKADDR); + sockAddr->sa = + (void*)XMALLOC(peerSz, heap, DYNAMIC_TYPE_SOCKADDR); + if (sockAddr->sa == NULL) { + sockAddr->sz = 0; + sockAddr->bufSz = 0; + return WOLFSSL_FAILURE; + } + sockAddr->bufSz = peerSz; + } + XMEMCPY(sockAddr->sa, peer, peerSz); + sockAddr->sz = peerSz; + return WOLFSSL_SUCCESS; +} +#endif + +/* Set the DTLS peer address on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] peer Peer socket address, may be NULL to clear. + * @param [in] peerSz Length of peer address in bytes. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ssl is NULL or on error. + * @return WOLFSSL_NOT_IMPLEMENTED when DTLS is not compiled in. + */ +int wolfSSL_dtls_set_peer(WOLFSSL* ssl, void* peer, unsigned int peerSz) +{ +#ifdef WOLFSSL_DTLS + int ret; + + if (ssl == NULL) + return WOLFSSL_FAILURE; +#ifdef WOLFSSL_RW_THREADED + if (wc_LockRwLock_Wr(&ssl->buffers.dtlsCtx.peerLock) != 0) + return WOLFSSL_FAILURE; +#endif + ret = SockAddrSet(&ssl->buffers.dtlsCtx.peer, peer, peerSz, ssl->heap); + if (ret == WOLFSSL_SUCCESS && !(peer == NULL || peerSz == 0)) + ssl->buffers.dtlsCtx.userSet = 1; + else + ssl->buffers.dtlsCtx.userSet = 0; +#ifdef WOLFSSL_RW_THREADED + if (wc_UnLockRwLock(&ssl->buffers.dtlsCtx.peerLock) != 0) + ret = WOLFSSL_FAILURE; +#endif + return ret; +#else + (void)ssl; + (void)peer; + (void)peerSz; + return WOLFSSL_NOT_IMPLEMENTED; +#endif +} + +#if defined(WOLFSSL_DTLS_CID) && !defined(WOLFSSL_NO_SOCK) +/* Set the pending DTLS peer address on the object. + * + * Used with connection ID to stage a change of peer address. + * + * @param [in] ssl SSL/TLS object. + * @param [in] peer Peer socket address. + * @param [in] peerSz Length of peer address in bytes. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ssl is NULL or on error. + * @return WOLFSSL_NOT_IMPLEMENTED when DTLS is not compiled in. + */ +int wolfSSL_dtls_set_pending_peer(WOLFSSL* ssl, void* peer, unsigned int peerSz) +{ +#ifdef WOLFSSL_DTLS + int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); + + if (ssl == NULL) + return WOLFSSL_FAILURE; +#ifdef WOLFSSL_RW_THREADED + if (wc_LockRwLock_Rd(&ssl->buffers.dtlsCtx.peerLock) != 0) + return WOLFSSL_FAILURE; +#endif + if (ssl->buffers.dtlsCtx.peer.sa != NULL && + ssl->buffers.dtlsCtx.peer.sz == peerSz && + sockAddrEqual((SOCKADDR_S*)ssl->buffers.dtlsCtx.peer.sa, + (XSOCKLENT)ssl->buffers.dtlsCtx.peer.sz, (SOCKADDR_S*)peer, + (XSOCKLENT)peerSz)) { + /* Already the current peer. */ + if (ssl->buffers.dtlsCtx.pendingPeer.sa != NULL) { + /* Clear any other pendingPeer */ + XFREE(ssl->buffers.dtlsCtx.pendingPeer.sa, ssl->heap, + DYNAMIC_TYPE_SOCKADDR); + ssl->buffers.dtlsCtx.pendingPeer.sa = NULL; + ssl->buffers.dtlsCtx.pendingPeer.sz = 0; + ssl->buffers.dtlsCtx.pendingPeer.bufSz = 0; + } + ret = WOLFSSL_SUCCESS; + } + else { + ret = SockAddrSet(&ssl->buffers.dtlsCtx.pendingPeer, peer, peerSz, + ssl->heap); + } + if (ret == WOLFSSL_SUCCESS) + ssl->buffers.dtlsCtx.processingPendingRecord = 0; +#ifdef WOLFSSL_RW_THREADED + if (wc_UnLockRwLock(&ssl->buffers.dtlsCtx.peerLock) != 0) + ret = WOLFSSL_FAILURE; +#endif + return ret; +#else + (void)ssl; + (void)peer; + (void)peerSz; + return WOLFSSL_NOT_IMPLEMENTED; +#endif +} +#endif /* WOLFSSL_DTLS_CID && !WOLFSSL_NO_SOCK */ + +/* Get a copy of the DTLS peer address from the object. + * + * @param [in] ssl SSL/TLS object. + * @param [out] peer Buffer to hold the peer address. + * @param [in, out] peerSz In: size of buffer. Out: length of address. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ssl is NULL or the buffer is too small. + * @return WOLFSSL_NOT_IMPLEMENTED when DTLS is not compiled in. + */ +int wolfSSL_dtls_get_peer(WOLFSSL* ssl, void* peer, unsigned int* peerSz) +{ +#ifdef WOLFSSL_DTLS + int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); + if (ssl == NULL) + return WOLFSSL_FAILURE; +#ifdef WOLFSSL_RW_THREADED + if (wc_LockRwLock_Rd(&ssl->buffers.dtlsCtx.peerLock) != 0) + return WOLFSSL_FAILURE; +#endif + if (peer != NULL && peerSz != NULL + && *peerSz >= ssl->buffers.dtlsCtx.peer.sz + && ssl->buffers.dtlsCtx.peer.sa != NULL) { + *peerSz = ssl->buffers.dtlsCtx.peer.sz; + XMEMCPY(peer, ssl->buffers.dtlsCtx.peer.sa, *peerSz); + ret = WOLFSSL_SUCCESS; + } +#ifdef WOLFSSL_RW_THREADED + if (wc_UnLockRwLock(&ssl->buffers.dtlsCtx.peerLock) != 0) + ret = WOLFSSL_FAILURE; +#endif + return ret; +#else + (void)ssl; + (void)peer; + (void)peerSz; + return WOLFSSL_NOT_IMPLEMENTED; +#endif +} + +/* Get a pointer to the DTLS peer address stored on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [out] peer Pointer to the stored peer address. + * @param [out] peerSz Length of the peer address in bytes. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when an argument is NULL. + * @return WOLFSSL_NOT_IMPLEMENTED when DTLS is not compiled in or threaded. + */ +int wolfSSL_dtls_get0_peer(WOLFSSL* ssl, const void** peer, + unsigned int* peerSz) +{ +#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_RW_THREADED) + if (ssl == NULL) + return WOLFSSL_FAILURE; + + if (peer == NULL || peerSz == NULL) + return WOLFSSL_FAILURE; + + *peer = ssl->buffers.dtlsCtx.peer.sa; + *peerSz = ssl->buffers.dtlsCtx.peer.sz; + return WOLFSSL_SUCCESS; +#else + (void)ssl; + (void)peer; + (void)peerSz; + return WOLFSSL_NOT_IMPLEMENTED; +#endif +} + + +#if defined(WOLFSSL_SCTP) && defined(WOLFSSL_DTLS) + +/* Enable DTLS over SCTP mode on the context. + * + * @param [in] ctx SSL/TLS context object. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx is NULL. + */ +int wolfSSL_CTX_dtls_set_sctp(WOLFSSL_CTX* ctx) +{ + WOLFSSL_ENTER("wolfSSL_CTX_dtls_set_sctp"); + + if (ctx == NULL) + return BAD_FUNC_ARG; + + ctx->dtlsSctp = 1; + return WOLFSSL_SUCCESS; +} + + +/* Enable DTLS over SCTP mode on the object. + * + * @param [in] ssl SSL/TLS object. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL. + */ +int wolfSSL_dtls_set_sctp(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_dtls_set_sctp"); + + if (ssl == NULL) + return BAD_FUNC_ARG; + + ssl->options.dtlsSctp = 1; + return WOLFSSL_SUCCESS; +} + +#endif /* WOLFSSL_DTLS && WOLFSSL_SCTP */ + +#if (defined(WOLFSSL_SCTP) || defined(WOLFSSL_DTLS_MTU)) && \ + defined(WOLFSSL_DTLS) + +/* Set the DTLS path MTU on the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] newMtu Maximum transmission unit in bytes. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx is NULL or newMtu is too large. + */ +int wolfSSL_CTX_dtls_set_mtu(WOLFSSL_CTX* ctx, word16 newMtu) +{ + if (ctx == NULL || newMtu > MAX_RECORD_SIZE) + return BAD_FUNC_ARG; + + ctx->dtlsMtuSz = newMtu; + return WOLFSSL_SUCCESS; +} + + +/* Set the DTLS path MTU on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] newMtu Maximum transmission unit in bytes. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL. + * @return WOLFSSL_FAILURE when newMtu is too large. + */ +int wolfSSL_dtls_set_mtu(WOLFSSL* ssl, word16 newMtu) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + + if (newMtu > MAX_RECORD_SIZE) { + ssl->error = BAD_FUNC_ARG; + return WOLFSSL_FAILURE; + } + + ssl->dtlsMtuSz = newMtu; + return WOLFSSL_SUCCESS; +} + +#ifdef OPENSSL_EXTRA +/* Set the DTLS path MTU on the object. + * + * Maps to the compatibility API SSL_set_mtu. Same as wolfSSL_dtls_set_mtu() + * but returns only success or failure. + * + * @param [in] ssl SSL/TLS object. + * @param [in] mtu Maximum transmission unit in bytes. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE on error. + */ +int wolfSSL_set_mtu_compat(WOLFSSL* ssl, unsigned short mtu) +{ + if (wolfSSL_dtls_set_mtu(ssl, mtu) == WOLFSSL_SUCCESS) + return WOLFSSL_SUCCESS; + else + return WOLFSSL_FAILURE; +} +#endif /* OPENSSL_EXTRA */ + +#endif /* WOLFSSL_DTLS && (WOLFSSL_SCTP || WOLFSSL_DTLS_MTU) */ + +#ifdef WOLFSSL_SRTP + +static const WOLFSSL_SRTP_PROTECTION_PROFILE gSrtpProfiles[] = { + /* AES CCM 128, Salt:112-bits, Auth HMAC-SHA1 Tag: 80-bits + * (master_key:128bits + master_salt:112bits) * 2 = 480 bits (60) */ + {"SRTP_AES128_CM_SHA1_80", SRTP_AES128_CM_SHA1_80, + (((128 + 112) * 2) / 8) }, + /* AES CCM 128, Salt:112-bits, Auth HMAC-SHA1 Tag: 32-bits + * (master_key:128bits + master_salt:112bits) * 2 = 480 bits (60) */ + {"SRTP_AES128_CM_SHA1_32", SRTP_AES128_CM_SHA1_32, + (((128 + 112) * 2) / 8) }, + /* NULL Cipher, Salt:112-bits, Auth HMAC-SHA1 Tag 80-bits */ + {"SRTP_NULL_SHA1_80", SRTP_NULL_SHA1_80, ((112 * 2) / 8)}, + /* NULL Cipher, Salt:112-bits, Auth HMAC-SHA1 Tag 32-bits */ + {"SRTP_NULL_SHA1_32", SRTP_NULL_SHA1_32, ((112 * 2) / 8)}, + /* AES GCM 128, Salt: 96-bits, Auth GCM Tag 128-bits + * (master_key:128bits + master_salt:96bits) * 2 = 448 bits (56) */ + {"SRTP_AEAD_AES_128_GCM", SRTP_AEAD_AES_128_GCM, (((128 + 96) * 2) / 8) }, + /* AES GCM 256, Salt: 96-bits, Auth GCM Tag 128-bits + * (master_key:256bits + master_salt:96bits) * 2 = 704 bits (88) */ + {"SRTP_AEAD_AES_256_GCM", SRTP_AEAD_AES_256_GCM, (((256 + 96) * 2) / 8) }, +}; + +/* Find an SRTP protection profile by name or by id. + * + * @param [in] profile_str Profile name, or NULL to search by id. + * @param [in] profile_str_len Length of profile name in bytes. + * @param [in] id Profile id to search for when name is NULL. + * @return Matching SRTP protection profile on success. + * @return NULL when no profile matches. + */ +static const WOLFSSL_SRTP_PROTECTION_PROFILE* DtlsSrtpFindProfile( + const char* profile_str, word32 profile_str_len, unsigned long id) +{ + int i; + const WOLFSSL_SRTP_PROTECTION_PROFILE* profile = NULL; + for (i=0; + i<(int)(sizeof(gSrtpProfiles)/sizeof(WOLFSSL_SRTP_PROTECTION_PROFILE)); + i++) { + if (profile_str != NULL) { + word32 srtp_profile_len = (word32)XSTRLEN(gSrtpProfiles[i].name); + if (srtp_profile_len == profile_str_len && + XMEMCMP(gSrtpProfiles[i].name, profile_str, profile_str_len) + == 0) { + profile = &gSrtpProfiles[i]; + break; + } + } + else if (id != 0 && gSrtpProfiles[i].id == id) { + profile = &gSrtpProfiles[i]; + break; + } + } + return profile; +} + +/* Select SRTP protection profiles from a colon-separated name list. + * + * @param [out] id Bitmask of selected profile ids. + * @param [in] profile_str Colon-separated list of SRTP profile names. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when profile_str is NULL. + */ +static int DtlsSrtpSelProfiles(word16* id, const char* profile_str) +{ + const WOLFSSL_SRTP_PROTECTION_PROFILE* profile; + const char *current, *next = NULL; + word32 length = 0, current_length; + + *id = 0; /* reset destination ID's */ + + if (profile_str == NULL) { + return WOLFSSL_FAILURE; + } + + /* loop on end of line or colon ":" */ + next = profile_str; + length = (word32)XSTRLEN(profile_str); + do { + current = next; + next = XSTRSTR(current, ":"); + if (next) { + current_length = (word32)(next - current); + ++next; /* ++ needed to skip ':' */ + } else { + current_length = (word32)XSTRLEN(current); + } + if (current_length < length) + length = current_length; + profile = DtlsSrtpFindProfile(current, current_length, 0); + if (profile != NULL) { + *id |= (1 << profile->id); /* selected bit based on ID */ + } + } while (next != NULL); + return WOLFSSL_SUCCESS; +} + +/* Set the SRTP protection profiles for DTLS on the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] profile_str Colon-separated list of SRTP profile names. + * @return 0 on success, to match OpenSSL. + * @return 1 on error, to match OpenSSL. + */ +int wolfSSL_CTX_set_tlsext_use_srtp(WOLFSSL_CTX* ctx, const char* profile_str) +{ + int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); + if (ctx != NULL) { + ret = DtlsSrtpSelProfiles(&ctx->dtlsSrtpProfiles, profile_str); + } + + if (ret == WC_NO_ERR_TRACE(WOLFSSL_FAILURE)) { + ret = 1; + } else { + ret = 0; + } + + return ret; +} + +/* Set the SRTP protection profiles for DTLS on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] profile_str Colon-separated list of SRTP profile names. + * @return 0 on success, to match OpenSSL. + * @return 1 on error, to match OpenSSL. + */ +int wolfSSL_set_tlsext_use_srtp(WOLFSSL* ssl, const char* profile_str) +{ + int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); + if (ssl != NULL) { + ret = DtlsSrtpSelProfiles(&ssl->dtlsSrtpProfiles, profile_str); + } + + if (ret == WC_NO_ERR_TRACE(WOLFSSL_FAILURE)) { + ret = 1; + } else { + ret = 0; + } + + return ret; +} + +/* Get the SRTP protection profile selected for the object. + * + * @param [in] ssl SSL/TLS object. + * @return Selected SRTP protection profile on success. + * @return NULL when ssl is NULL or none is selected. + */ +const WOLFSSL_SRTP_PROTECTION_PROFILE* wolfSSL_get_selected_srtp_profile( + WOLFSSL* ssl) +{ + const WOLFSSL_SRTP_PROTECTION_PROFILE* profile = NULL; + if (ssl) { + profile = DtlsSrtpFindProfile(NULL, 0, ssl->dtlsSrtpId); + } + return profile; +} +#ifndef NO_WOLFSSL_STUB +/* Get the list of SRTP protection profiles set on the object. + * + * Not implemented - stub. + * + * @param [in] ssl SSL/TLS object. + * @return NULL always. + */ +WOLF_STACK_OF(WOLFSSL_SRTP_PROTECTION_PROFILE)* wolfSSL_get_srtp_profiles( + WOLFSSL* ssl) +{ + /* Not yet implemented - should return list of available SRTP profiles + * ssl->dtlsSrtpProfiles */ + (void)ssl; + return NULL; +} +#endif + +#define DTLS_SRTP_KEYING_MATERIAL_LABEL "EXTRACTOR-dtls_srtp" + +/* Export the DTLS-SRTP keying material for the object. + * + * When out is NULL, the length required is returned in olen. + * + * @param [in] ssl SSL/TLS object. + * @param [out] out Buffer to hold keying material. May be NULL. + * @param [in, out] olen In: size of buffer. Out: length of keying material. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl or olen is NULL. + * @return EXT_MISSING when DTLS-SRTP is not in use. + * @return LENGTH_ONLY_E when out is NULL and olen has been set. + * @return BUFFER_E when the buffer is too small. + */ +int wolfSSL_export_dtls_srtp_keying_material(WOLFSSL* ssl, + unsigned char* out, size_t* olen) +{ + const WOLFSSL_SRTP_PROTECTION_PROFILE* profile = NULL; + + if (ssl == NULL || olen == NULL) { + return BAD_FUNC_ARG; + } + + profile = DtlsSrtpFindProfile(NULL, 0, ssl->dtlsSrtpId); + if (profile == NULL) { + WOLFSSL_MSG("Not using DTLS SRTP"); + return EXT_MISSING; + } + if (out == NULL) { + *olen = (size_t)profile->kdfBits; + return WC_NO_ERR_TRACE(LENGTH_ONLY_E); + } + + if (*olen < (size_t)profile->kdfBits) { + return BUFFER_E; + } + + return wolfSSL_export_keying_material(ssl, out, (size_t)profile->kdfBits, + DTLS_SRTP_KEYING_MATERIAL_LABEL, + XSTR_SIZEOF(DTLS_SRTP_KEYING_MATERIAL_LABEL), NULL, 0, 0); +} + +#endif /* WOLFSSL_SRTP */ + + +#ifdef WOLFSSL_DTLS_DROP_STATS + +/* Get the DTLS dropped-record statistics for the object. + * + * @param [in] ssl SSL/TLS object. + * @param [out] macDropCount Number of records dropped on MAC failure. + * @param [out] replayDropCount Number of records dropped as replays. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL. + */ +int wolfSSL_dtls_get_drop_stats(WOLFSSL* ssl, + word32* macDropCount, word32* replayDropCount) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_dtls_get_drop_stats"); + + if (ssl == NULL) + ret = BAD_FUNC_ARG; + else { + ret = WOLFSSL_SUCCESS; + if (macDropCount != NULL) + *macDropCount = ssl->macDropCount; + if (replayDropCount != NULL) + *replayDropCount = ssl->replayDropCount; + } + + WOLFSSL_LEAVE("wolfSSL_dtls_get_drop_stats", ret); + return ret; +} + +#endif /* WOLFSSL_DTLS_DROP_STATS */ + + +#if defined(WOLFSSL_MULTICAST) + +/* Set the multicast member id on the context and enable multicast. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] id Multicast member id. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx is NULL or id is out of range. + */ +int wolfSSL_CTX_mcast_set_member_id(WOLFSSL_CTX* ctx, word16 id) +{ + int ret = 0; + + WOLFSSL_ENTER("wolfSSL_CTX_mcast_set_member_id"); + + if (ctx == NULL || id > WOLFSSL_MAX_8BIT) + ret = BAD_FUNC_ARG; + + if (ret == 0) { + ctx->haveEMS = 0; + ctx->haveMcast = 1; + ctx->mcastID = (byte)id; +#ifndef WOLFSSL_USER_IO + ctx->CBIORecv = EmbedReceiveFromMcast; +#endif /* WOLFSSL_USER_IO */ + + ret = WOLFSSL_SUCCESS; + } + WOLFSSL_LEAVE("wolfSSL_CTX_mcast_set_member_id", ret); + return ret; +} + +/* Get the maximum number of multicast peers supported. + * + * @return Maximum number of multicast peers. + */ +int wolfSSL_mcast_get_max_peers(void) +{ + return WOLFSSL_MULTICAST_PEERS; +} + +#ifdef WOLFSSL_DTLS +/* Determine the next highwater mark from the current sequence number. + * + * @param [in] cur Current sequence number. + * @param [in] first First highwater threshold. + * @param [in] second Second highwater threshold. + * @param [in] high Maximum highwater threshold. + * @return Next highwater mark, or 0 when cur is at or above high. + */ +static WC_INLINE word32 UpdateHighwaterMark(word32 cur, word32 first, + word32 second, word32 high) +{ + word32 newCur = 0; + + if (cur < first) + newCur = first; + else if (cur < second) + newCur = second; + else if (cur < high) + newCur = high; + + return newCur; +} +#endif /* WOLFSSL_DTLS */ + + +/* Set the master secret and derived keys directly on the object. + * + * Used with multicast to install externally derived keys. + * + * @param [in] ssl SSL/TLS object. + * @param [in] epoch DTLS epoch to use. + * @param [in] preMasterSecret Pre-master secret data. + * @param [in] preMasterSz Length of pre-master secret in bytes. + * @param [in] clientRandom Client random data (RAN_LEN bytes). + * @param [in] serverRandom Server random data (RAN_LEN bytes). + * @param [in] suite Cipher suite bytes (2). + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FATAL_ERROR on error, including invalid arguments. + */ +int wolfSSL_set_secret(WOLFSSL* ssl, word16 epoch, + const byte* preMasterSecret, word32 preMasterSz, + const byte* clientRandom, const byte* serverRandom, + const byte* suite) +{ + int ret = 0; + + WOLFSSL_ENTER("wolfSSL_set_secret"); + + if (ssl == NULL || preMasterSecret == NULL || + preMasterSz == 0 || preMasterSz > ENCRYPT_LEN || + clientRandom == NULL || serverRandom == NULL || suite == NULL) { + + ret = BAD_FUNC_ARG; + } + + if (ret == 0 && ssl->arrays->preMasterSecret == NULL) { + ssl->arrays->preMasterSz = ENCRYPT_LEN; + ssl->arrays->preMasterSecret = (byte*)XMALLOC(ENCRYPT_LEN, ssl->heap, + DYNAMIC_TYPE_SECRET); + if (ssl->arrays->preMasterSecret == NULL) { + ret = MEMORY_E; + } + } + + if (ret == 0) { + XMEMCPY(ssl->arrays->preMasterSecret, preMasterSecret, preMasterSz); + XMEMSET(ssl->arrays->preMasterSecret + preMasterSz, 0, + ENCRYPT_LEN - preMasterSz); + ssl->arrays->preMasterSz = preMasterSz; + XMEMCPY(ssl->arrays->clientRandom, clientRandom, RAN_LEN); + XMEMCPY(ssl->arrays->serverRandom, serverRandom, RAN_LEN); + ssl->options.cipherSuite0 = suite[0]; + ssl->options.cipherSuite = suite[1]; + + ret = SetCipherSpecs(ssl); + } + + if (ret == 0) + ret = MakeTlsMasterSecret(ssl); + + if (ret == 0) { + ssl->keys.encryptionOn = 1; + ret = SetKeysSide(ssl, ENCRYPT_AND_DECRYPT_SIDE); + } + + if (ret == 0) { + if (ssl->options.dtls) { + #ifdef WOLFSSL_DTLS + WOLFSSL_DTLS_PEERSEQ* peerSeq; + int i; + + ssl->keys.dtls_epoch = epoch; + for (i = 0, peerSeq = ssl->keys.peerSeq; + i < WOLFSSL_DTLS_PEERSEQ_SZ; + i++, peerSeq++) { + + peerSeq->nextEpoch = epoch; + peerSeq->prevSeq_lo = peerSeq->nextSeq_lo; + peerSeq->prevSeq_hi = peerSeq->nextSeq_hi; + peerSeq->nextSeq_lo = 0; + peerSeq->nextSeq_hi = 0; + XMEMCPY(peerSeq->prevWindow, peerSeq->window, DTLS_SEQ_SZ); + XMEMSET(peerSeq->window, 0, DTLS_SEQ_SZ); + peerSeq->highwaterMark = UpdateHighwaterMark(0, + ssl->ctx->mcastFirstSeq, + ssl->ctx->mcastSecondSeq, + ssl->ctx->mcastMaxSeq); + } + #else + (void)epoch; + #endif + } + FreeHandshakeResources(ssl); + ret = WOLFSSL_SUCCESS; + } + else { + if (ssl) + ssl->error = ret; + ret = WOLFSSL_FATAL_ERROR; + } + WOLFSSL_LEAVE("wolfSSL_set_secret", ret); + return ret; +} + + +#ifdef WOLFSSL_DTLS + +/* Add or remove a peer from the multicast peer list. + * + * @param [in] ssl SSL/TLS object. + * @param [in] peerId Peer id to add or remove. + * @param [in] sub 0 to add the peer, non-zero to remove it. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL or peerId is out of range. + * @return WOLFSSL_FATAL_ERROR when the peer list is full. + */ +int wolfSSL_mcast_peer_add(WOLFSSL* ssl, word16 peerId, int sub) +{ + WOLFSSL_DTLS_PEERSEQ* p = NULL; + int ret = WOLFSSL_SUCCESS; + int i; + + WOLFSSL_ENTER("wolfSSL_mcast_peer_add"); + if (ssl == NULL || peerId > WOLFSSL_MAX_8BIT) + return BAD_FUNC_ARG; + + if (!sub) { + /* Make sure it isn't already present, while keeping the first + * open spot. */ + for (i = 0; i < WOLFSSL_DTLS_PEERSEQ_SZ; i++) { + if (ssl->keys.peerSeq[i].peerId == INVALID_PEER_ID) + p = &ssl->keys.peerSeq[i]; + if (ssl->keys.peerSeq[i].peerId == peerId) { + WOLFSSL_MSG("Peer ID already in multicast peer list."); + p = NULL; + } + } + + if (p != NULL) { + XMEMSET(p, 0, sizeof(WOLFSSL_DTLS_PEERSEQ)); + p->peerId = peerId; + p->highwaterMark = UpdateHighwaterMark(0, + ssl->ctx->mcastFirstSeq, + ssl->ctx->mcastSecondSeq, + ssl->ctx->mcastMaxSeq); + } + else { + WOLFSSL_MSG("No room in peer list."); + ret = WOLFSSL_FATAL_ERROR; + } + } + else { + for (i = 0; i < WOLFSSL_DTLS_PEERSEQ_SZ; i++) { + if (ssl->keys.peerSeq[i].peerId == peerId) + p = &ssl->keys.peerSeq[i]; + } + + if (p != NULL) { + p->peerId = INVALID_PEER_ID; + } + else { + WOLFSSL_MSG("Peer not found in list."); + } + } + + WOLFSSL_LEAVE("wolfSSL_mcast_peer_add", ret); + return ret; +} + + +/* Determine whether a multicast peer is known and active. + * + * @param [in] ssl SSL/TLS object. + * @param [in] peerId Peer id to look up. + * @return 1 when the peer is in the list with a non-zero sequence number. + * @return 0 when the peer is not known or has not sent data. + * @return BAD_FUNC_ARG when ssl is NULL or peerId is out of range. + */ +int wolfSSL_mcast_peer_known(WOLFSSL* ssl, unsigned short peerId) +{ + int known = 0; + int i; + + WOLFSSL_ENTER("wolfSSL_mcast_peer_known"); + + if (ssl == NULL || peerId > WOLFSSL_MAX_8BIT) { + return BAD_FUNC_ARG; + } + + for (i = 0; i < WOLFSSL_DTLS_PEERSEQ_SZ; i++) { + if (ssl->keys.peerSeq[i].peerId == peerId) { + if (ssl->keys.peerSeq[i].nextSeq_hi || + ssl->keys.peerSeq[i].nextSeq_lo) { + + known = 1; + } + break; + } + } + + WOLFSSL_LEAVE("wolfSSL_mcast_peer_known", known); + return known; +} + + +/* Set the multicast highwater callback and thresholds on the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] maxSeq Maximum sequence number threshold. + * @param [in] first First sequence number threshold. + * @param [in] second Second sequence number threshold. + * @param [in] cb Highwater callback. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when an argument is NULL or thresholds are invalid. + */ +int wolfSSL_CTX_mcast_set_highwater_cb(WOLFSSL_CTX* ctx, word32 maxSeq, + word32 first, word32 second, + CallbackMcastHighwater cb) +{ + if (ctx == NULL || (second && first > second) || + first > maxSeq || second > maxSeq || cb == NULL) { + + return BAD_FUNC_ARG; + } + + ctx->mcastHwCb = cb; + ctx->mcastFirstSeq = first; + ctx->mcastSecondSeq = second; + ctx->mcastMaxSeq = maxSeq; + + return WOLFSSL_SUCCESS; +} + + +/* Set the user context passed to the multicast highwater callback. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx User context for the highwater callback. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl or ctx is NULL. + */ +int wolfSSL_mcast_set_highwater_ctx(WOLFSSL* ssl, void* ctx) +{ + if (ssl == NULL || ctx == NULL) + return BAD_FUNC_ARG; + + ssl->mcastHwCbCtx = ctx; + + return WOLFSSL_SUCCESS; +} + +#endif /* WOLFSSL_DTLS */ + +#endif /* WOLFSSL_MULTICAST */ + + +#endif /* WOLFSSL_LEANPSK */ + + +#ifndef NO_TLS +#ifdef WOLFSSL_MULTICAST + +/* Read application data from a multicast DTLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [out] id Peer id the data was received from. May be NULL. + * @param [out] data Buffer to hold the data read. + * @param [in] sz Size of the buffer in bytes. + * @return Number of bytes read on success. + * @return BAD_FUNC_ARG when ssl is NULL or sz is negative. + * @return Negative value on error. + */ +int wolfSSL_mcast_read(WOLFSSL* ssl, word16* id, void* data, int sz) +{ + int ret = 0; + + WOLFSSL_ENTER("wolfSSL_mcast_read"); + + if ((ssl == NULL) || (sz < 0)) + return BAD_FUNC_ARG; + + ret = wolfSSL_read_internal(ssl, data, (size_t)sz, FALSE); + if (ssl->options.dtls && ssl->options.haveMcast && id != NULL) + *id = ssl->keys.curPeerId; + return ret; +} + +#endif /* WOLFSSL_MULTICAST */ +#endif /* !NO_TLS */ + + +#ifdef WOLFSSL_DTLS +/* Get the DTLS MAC secret for the requested side and epoch. + * + * @param [in] ssl SSL/TLS object. + * @param [in] verify 1 for the verify (read) secret, 0 for the write one. + * @param [in] epochOrder Epoch order: PEER_ORDER, PREV_ORDER or CUR_ORDER. + * @return MAC secret on success. + * @return NULL when ssl is NULL, AEAD-only build, or epoch order is unknown. + */ +const byte* wolfSSL_GetDtlsMacSecret(WOLFSSL* ssl, int verify, int epochOrder) +{ +#ifndef WOLFSSL_AEAD_ONLY + Keys* keys = NULL; + + (void)epochOrder; + + if (ssl == NULL) + return NULL; + +#ifdef HAVE_SECURE_RENEGOTIATION + switch (epochOrder) { + case PEER_ORDER: + if (IsDtlsMsgSCRKeys(ssl)) + keys = &ssl->secure_renegotiation->tmp_keys; + else + keys = &ssl->keys; + break; + case PREV_ORDER: + keys = &ssl->keys; + break; + case CUR_ORDER: + if (DtlsUseSCRKeys(ssl)) + keys = &ssl->secure_renegotiation->tmp_keys; + else + keys = &ssl->keys; + break; + default: + WOLFSSL_MSG("Unknown epoch order"); + return NULL; + } +#else + keys = &ssl->keys; +#endif + + if ( (ssl->options.side == WOLFSSL_CLIENT_END && !verify) || + (ssl->options.side == WOLFSSL_SERVER_END && verify) ) + return keys->client_write_MAC_secret; + else + return keys->server_write_MAC_secret; +#else + (void)ssl; + (void)verify; + (void)epochOrder; + + return NULL; +#endif +} +#endif /* WOLFSSL_DTLS */ + + +/* Get whether the DTLS object is using non-blocking I/O. + * + * @param [in] ssl SSL/TLS object. + * @return 1 when non-blocking I/O is enabled. + * @return 0 when disabled or not a DTLS object. + * @return WOLFSSL_FAILURE when ssl is NULL. + */ +int wolfSSL_dtls_get_using_nonblock(WOLFSSL* ssl) +{ + int useNb = 0; + + if (ssl == NULL) + return WOLFSSL_FAILURE; + + WOLFSSL_ENTER("wolfSSL_dtls_get_using_nonblock"); + if (ssl->options.dtls) { +#ifdef WOLFSSL_DTLS + useNb = ssl->options.dtlsUseNonblock; +#endif + } + else { + WOLFSSL_MSG("wolfSSL_dtls_get_using_nonblock() is " + "DEPRECATED for non-DTLS use."); + } + return useNb; +} + + +#ifndef WOLFSSL_LEANPSK + +/* Set whether the DTLS object uses non-blocking I/O. + * + * @param [in] ssl SSL/TLS object. + * @param [in] nonblock 1 to use non-blocking I/O, 0 otherwise. + */ +void wolfSSL_dtls_set_using_nonblock(WOLFSSL* ssl, int nonblock) +{ + (void)nonblock; + + WOLFSSL_ENTER("wolfSSL_dtls_set_using_nonblock"); + + if (ssl == NULL) + return; + + if (ssl->options.dtls) { +#ifdef WOLFSSL_DTLS + ssl->options.dtlsUseNonblock = (nonblock != 0); +#endif + } + else { + WOLFSSL_MSG("wolfSSL_dtls_set_using_nonblock() is " + "DEPRECATED for non-DTLS use."); + } +} + + +#ifdef WOLFSSL_DTLS + +/* Get the current DTLS receive timeout, in seconds. + * + * @param [in] ssl SSL/TLS object. + * @return Current timeout in seconds, or 0 when ssl is NULL. + */ +int wolfSSL_dtls_get_current_timeout(WOLFSSL* ssl) +{ + int timeout = 0; + if (ssl) + timeout = ssl->dtls_timeout; + + WOLFSSL_LEAVE("wolfSSL_dtls_get_current_timeout", timeout); + return timeout; +} + +#ifdef WOLFSSL_DTLS13 + +/* Determine whether a short receive timeout should be used. + * + * Recommended to be at most 1/4 of wolfSSL_dtls_get_current_timeout(). + * + * @param [in] ssl SSL/TLS object. + * @return 1 when a short timeout should be used. + * @return 0 otherwise, or when ssl is NULL. + */ +int wolfSSL_dtls13_use_quick_timeout(WOLFSSL* ssl) +{ + return ssl != NULL && ssl->dtls13FastTimeout; +} + +/* Set whether a DTLS 1.3 connection sends acks immediately on a disruption. + * + * Sending more acks may increase traffic but can speed up the handshake. + * + * @param [in] ssl SSL/TLS object. + * @param [in] value Non-zero to send more acks, 0 otherwise. + */ +void wolfSSL_dtls13_set_send_more_acks(WOLFSSL* ssl, int value) +{ + if (ssl != NULL) + ssl->options.dtls13SendMoreAcks = !!value; +} +#endif /* WOLFSSL_DTLS13 */ + +/* Get the time left until the next DTLS timeout. + * + * @param [in] ssl SSL/TLS object. + * @param [out] timeleft Time left until the next timeout. + * @return 0 always. + */ +int wolfSSL_DTLSv1_get_timeout(WOLFSSL* ssl, WOLFSSL_TIMEVAL* timeleft) +{ + if (ssl && timeleft) { + XMEMSET(timeleft, 0, sizeof(WOLFSSL_TIMEVAL)); + timeleft->tv_sec = ssl->dtls_timeout; + } + return 0; +} + +#ifndef NO_WOLFSSL_STUB +/* Handle a DTLS timeout. + * + * Not implemented - stub for OpenSSL compatibility. + * + * @param [in] ssl SSL/TLS object. + * @return 0 always. + */ +int wolfSSL_DTLSv1_handle_timeout(WOLFSSL* ssl) +{ + WOLFSSL_STUB("SSL_DTLSv1_handle_timeout"); + (void)ssl; + return 0; +} +#endif + +#ifndef NO_WOLFSSL_STUB +/* Set the initial DTLS timeout duration. + * + * Not implemented - stub for OpenSSL compatibility. + * + * @param [in] ssl SSL/TLS object. + * @param [in] duration_ms Initial timeout duration in milliseconds. + */ +void wolfSSL_DTLSv1_set_initial_timeout_duration(WOLFSSL* ssl, + word32 duration_ms) +{ + WOLFSSL_STUB("SSL_DTLSv1_set_initial_timeout_duration"); + (void)ssl; + (void)duration_ms; +} +#endif + +/* Set the initial DTLS receive timeout, in seconds, on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] timeout Initial timeout in seconds. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL, timeout is negative or greater than + * the maximum timeout. + */ +int wolfSSL_dtls_set_timeout_init(WOLFSSL* ssl, int timeout) +{ + if (ssl == NULL || timeout < 0) + return BAD_FUNC_ARG; + + if (timeout > ssl->dtls_timeout_max) { + WOLFSSL_MSG("Can't set dtls timeout init greater than dtls timeout " + "max"); + return BAD_FUNC_ARG; + } + + ssl->dtls_timeout_init = timeout; + ssl->dtls_timeout = timeout; + + return WOLFSSL_SUCCESS; +} + + +/* Set the maximum DTLS receive timeout, in seconds, on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] timeout Maximum timeout in seconds. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL, timeout is negative or less than + * the initial timeout. + */ +int wolfSSL_dtls_set_timeout_max(WOLFSSL* ssl, int timeout) +{ + if (ssl == NULL || timeout < 0) + return BAD_FUNC_ARG; + + if (timeout < ssl->dtls_timeout_init) { + WOLFSSL_MSG("Can't set dtls timeout max less than dtls timeout init"); + return BAD_FUNC_ARG; + } + + ssl->dtls_timeout_max = timeout; + + return WOLFSSL_SUCCESS; +} + + +/* Process a DTLS timeout, retransmitting messages as needed. + * + * @param [in] ssl SSL/TLS object. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FATAL_ERROR when ssl is NULL, not DTLS, or on error. + */ +int wolfSSL_dtls_got_timeout(WOLFSSL* ssl) +{ + int result = WOLFSSL_SUCCESS; + WOLFSSL_ENTER("wolfSSL_dtls_got_timeout"); + + if (ssl == NULL || !ssl->options.dtls) + return WOLFSSL_FATAL_ERROR; + +#ifdef WOLFSSL_DTLS13 + if (IsAtLeastTLSv1_3(ssl->version)) { + result = Dtls13RtxTimeout(ssl); + if (result < 0) { + if (result == WC_NO_ERR_TRACE(WANT_WRITE)) + ssl->dtls13SendingAckOrRtx = 1; + ssl->error = result; + WOLFSSL_ERROR(result); + return WOLFSSL_FATAL_ERROR; + } + + return WOLFSSL_SUCCESS; + } +#endif /* WOLFSSL_DTLS13 */ + + /* Do we have any 1.2 messages stored? */ + if (ssl->dtls_tx_msg_list != NULL || ssl->dtls_tx_msg != NULL) { + if (DtlsMsgPoolTimeout(ssl) < 0){ + ssl->error = SOCKET_ERROR_E; + WOLFSSL_ERROR(ssl->error); + result = WOLFSSL_FATAL_ERROR; + } + else if ((result = DtlsMsgPoolSend(ssl, 0)) < 0) { + ssl->error = result; + WOLFSSL_ERROR(result); + result = WOLFSSL_FATAL_ERROR; + } + else { + /* Reset return value to success */ + result = WOLFSSL_SUCCESS; + } + } + + WOLFSSL_LEAVE("wolfSSL_dtls_got_timeout", result); + return result; +} + + +/* Retransmit all stored DTLS handshake messages. + * + * @param [in] ssl SSL/TLS object. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FATAL_ERROR when ssl is NULL or on error. + */ +int wolfSSL_dtls_retransmit(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_dtls_retransmit"); + + if (ssl == NULL) + return WOLFSSL_FATAL_ERROR; + + if (!ssl->options.handShakeDone) { + int result; +#ifdef WOLFSSL_DTLS13 + if (IsAtLeastTLSv1_3(ssl->version)) + result = Dtls13DoScheduledWork(ssl); + else +#endif + result = DtlsMsgPoolSend(ssl, 0); + if (result < 0) { + ssl->error = result; + WOLFSSL_ERROR(result); + return WOLFSSL_FATAL_ERROR; + } + } + + return WOLFSSL_SUCCESS; +} + +#endif /* DTLS */ +#endif /* LEANPSK */ + + +#if defined(WOLFSSL_DTLS) && !defined(NO_WOLFSSL_SERVER) + +/* Set the DTLS cookie secret used to generate HelloVerifyRequest cookies. + * + * When secret is NULL a new secret is randomly generated. The object's RNG + * must be initialized. This is not an SSL function. + * + * @param [in] ssl SSL/TLS object. + * @param [in] secret Cookie secret data, or NULL to generate one. + * @param [in] secretSz Length of secret in bytes, 0 to use the default. + * @return 0 on success. + * @return BAD_FUNC_ARG when ssl is NULL or secret is set with size 0. + * @return MEMORY_ERROR on allocation failure. + */ +int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, + const byte* secret, word32 secretSz) +{ + int ret = 0; + + WOLFSSL_ENTER("wolfSSL_DTLS_SetCookieSecret"); + + if (ssl == NULL) { + WOLFSSL_MSG("need a SSL object"); + return BAD_FUNC_ARG; + } + + if (secret != NULL && secretSz == 0) { + WOLFSSL_MSG("can't have a new secret without a size"); + return BAD_FUNC_ARG; + } + + /* If secretSz is 0, use the default size. */ + if (secretSz == 0) + secretSz = COOKIE_SECRET_SZ; + + if (secretSz != ssl->buffers.dtlsCookieSecret.length) { + byte* newSecret; + + if (ssl->buffers.dtlsCookieSecret.buffer != NULL) { + ForceZero(ssl->buffers.dtlsCookieSecret.buffer, + ssl->buffers.dtlsCookieSecret.length); + XFREE(ssl->buffers.dtlsCookieSecret.buffer, + ssl->heap, DYNAMIC_TYPE_COOKIE_PWD); + } + + newSecret = (byte*)XMALLOC(secretSz, ssl->heap,DYNAMIC_TYPE_COOKIE_PWD); + if (newSecret == NULL) { + ssl->buffers.dtlsCookieSecret.buffer = NULL; + ssl->buffers.dtlsCookieSecret.length = 0; + WOLFSSL_MSG("couldn't allocate new cookie secret"); + return MEMORY_ERROR; + } + ssl->buffers.dtlsCookieSecret.buffer = newSecret; + ssl->buffers.dtlsCookieSecret.length = secretSz; + #ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("wolfSSL_DTLS_SetCookieSecret secret", + ssl->buffers.dtlsCookieSecret.buffer, + ssl->buffers.dtlsCookieSecret.length); + #endif + } + + /* If the supplied secret is NULL, randomly generate a new secret. */ + if (secret == NULL) { + ret = wc_RNG_GenerateBlock(ssl->rng, + ssl->buffers.dtlsCookieSecret.buffer, secretSz); + } + else + XMEMCPY(ssl->buffers.dtlsCookieSecret.buffer, secret, secretSz); + + WOLFSSL_LEAVE("wolfSSL_DTLS_SetCookieSecret", 0); + return ret; +} + +#endif /* WOLFSSL_DTLS && !NO_WOLFSSL_SERVER */ + +#endif /* !WOLFCRYPT_ONLY */ + +#endif /* !WOLFSSL_SSL_API_DTLS_INCLUDED */ diff --git a/src/ssl_api_ext.c b/src/ssl_api_ext.c new file mode 100644 index 0000000000..0be59f0483 --- /dev/null +++ b/src/ssl_api_ext.c @@ -0,0 +1,2727 @@ +/* ssl_api_ext.c + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL 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. + * + * wolfSSL 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 + +#if !defined(WOLFSSL_SSL_API_EXT_INCLUDED) + #ifndef WOLFSSL_IGNORE_FILE_WARN + #warning ssl_api_ext.c does not need to be compiled separately from ssl.c + #endif +#else + +#ifndef WOLFCRYPT_ONLY +#ifndef NO_TLS + +#ifdef HAVE_SNI + +/* Set the Server Name Indication extension data on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] type SNI type, e.g. WOLFSSL_SNI_HOST_NAME. + * @param [in] data SNI data. + * @param [in] size Length of SNI data in bytes. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL. + * @return Negative value on error. + */ +WOLFSSL_ABI +int wolfSSL_UseSNI(WOLFSSL* ssl, byte type, const void* data, word16 size) +{ + int ret; + + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ret = TLSX_UseSNI(&ssl->extensions, type, data, size, ssl->heap); + } + + return ret; +} + + +/* Set the Server Name Indication extension data on the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] type SNI type, e.g. WOLFSSL_SNI_HOST_NAME. + * @param [in] data SNI data. + * @param [in] size Length of SNI data in bytes. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx is NULL. + * @return Negative value on error. + */ +WOLFSSL_ABI +int wolfSSL_CTX_UseSNI(WOLFSSL_CTX* ctx, byte type, const void* data, + word16 size) +{ + int ret; + + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ret = TLSX_UseSNI(&ctx->extensions, type, data, size, ctx->heap); + } + + return ret; +} + +#ifndef NO_WOLFSSL_SERVER + +/* Set options for the Server Name Indication extension on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] type SNI type. + * @param [in] options Bitmask of SNI options. + */ +void wolfSSL_SNI_SetOptions(WOLFSSL* ssl, byte type, byte options) +{ + if ((ssl != NULL) && (ssl->extensions != NULL)) { + TLSX_SNI_SetOptions(ssl->extensions, type, options); + } +} + + +/* Set options for the Server Name Indication extension on the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] type SNI type. + * @param [in] options Bitmask of SNI options. + */ +void wolfSSL_CTX_SNI_SetOptions(WOLFSSL_CTX* ctx, byte type, byte options) +{ + if ((ctx != NULL) && (ctx->extensions != NULL)) { + TLSX_SNI_SetOptions(ctx->extensions, type, options); + } +} + + +/* Get the status of the Server Name Indication extension on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] type SNI type. + * @return SNI status for the type. + */ +byte wolfSSL_SNI_Status(WOLFSSL* ssl, byte type) +{ + return TLSX_SNI_Status((ssl != NULL) ? ssl->extensions : NULL, type); +} + + +/* Get the Server Name Indication request data received from the peer. + * + * @param [in] ssl SSL/TLS object. + * @param [in] type SNI type. + * @param [out] data Pointer to the SNI request data. May be NULL. + * @return Length of the SNI request data in bytes, or 0 when none. + */ +word16 wolfSSL_SNI_GetRequest(WOLFSSL* ssl, byte type, void** data) +{ + word16 ret = 0; + + /* Default the output to no request data. */ + if (data != NULL) { + *data = NULL; + } + + /* Only query when SNI extensions are present on the object. */ + if ((ssl != NULL) && (ssl->extensions != NULL)) { + ret = TLSX_SNI_GetRequest(ssl->extensions, type, data, 0); + } + + return ret; +} + + +/* Get the Server Name Indication data from a raw ClientHello buffer. + * + * @param [in] clientHello ClientHello message buffer. + * @param [in] helloSz Length of the ClientHello in bytes. + * @param [in] type SNI type. + * @param [out] sni Buffer to hold the SNI data. + * @param [in, out] inOutSz In: size of buffer. Out: length of SNI data. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when an argument is NULL or a size is zero. + */ +int wolfSSL_SNI_GetFromBuffer(const byte* clientHello, word32 helloSz, + byte type, byte* sni, word32* inOutSz) +{ + int ret; + + /* All arguments are required and the sizes must be non-zero. */ + if ((clientHello == NULL) || (helloSz == 0) || (sni == NULL) || + (inOutSz == NULL) || (*inOutSz == 0)) { + ret = BAD_FUNC_ARG; + } + else { + ret = TLSX_SNI_GetFromBuffer(clientHello, helloSz, type, sni, inOutSz); + } + + return ret; +} + +#endif /* !NO_WOLFSSL_SERVER */ + +#endif /* HAVE_SNI */ + + +#ifdef HAVE_TRUSTED_CA + +/* Set the Trusted CA Indication extension on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] type Trusted CA identifier type. + * @param [in] certId Certificate identifier data. + * @param [in] certIdSz Length of certificate identifier in bytes. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL or arguments are inconsistent with + * the type. + */ +int wolfSSL_UseTrustedCA(WOLFSSL* ssl, byte type, + const byte* certId, word32 certIdSz) +{ + int ret = 0; + + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + /* Pre-agreed type carries no identifier. */ + else if (type == WOLFSSL_TRUSTED_CA_PRE_AGREED) { + if ((certId != NULL) || (certIdSz != 0)) { + ret = BAD_FUNC_ARG; + } + } + /* X.509 name type requires a non-empty identifier. */ + else if (type == WOLFSSL_TRUSTED_CA_X509_NAME) { + if ((certId == NULL) || (certIdSz == 0)) { + ret = BAD_FUNC_ARG; + } + } +#ifndef NO_SHA + /* SHA-1 hash types require a SHA-1 digest sized identifier. */ + else if ((type == WOLFSSL_TRUSTED_CA_KEY_SHA1) || + (type == WOLFSSL_TRUSTED_CA_CERT_SHA1)) { + if ((certId == NULL) || (certIdSz != WC_SHA_DIGEST_SIZE)) { + ret = BAD_FUNC_ARG; + } + } +#endif + /* Any other identifier type is not supported. */ + else { + ret = BAD_FUNC_ARG; + } + + /* Add the extension once the identifier has been validated. */ + if (ret == 0) { + ret = TLSX_UseTrustedCA(&ssl->extensions, type, certId, certIdSz, + ssl->heap); + } + + return ret; +} + +#endif /* HAVE_TRUSTED_CA */ + + +#ifdef HAVE_MAX_FRAGMENT +#ifndef NO_WOLFSSL_CLIENT + +/* Set the Maximum Fragment Length extension on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] mfl Maximum fragment length code, e.g. WOLFSSL_MFL_2_9. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL. + * @return Negative value on error. + */ +int wolfSSL_UseMaxFragment(WOLFSSL* ssl, byte mfl) +{ + int ret; + + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } +#ifdef WOLFSSL_ALLOW_MAX_FRAGMENT_ADJUST + /* The following is a non-standard way to reconfigure the max packet size + * post-handshake for wolfSSL_write/wolfSSL_read */ + else if (ssl->options.handShakeState == HANDSHAKE_DONE) { + switch (mfl) { + case WOLFSSL_MFL_2_8 : ssl->max_fragment = 256; break; + case WOLFSSL_MFL_2_9 : ssl->max_fragment = 512; break; + case WOLFSSL_MFL_2_10: ssl->max_fragment = 1024; break; + case WOLFSSL_MFL_2_11: ssl->max_fragment = 2048; break; + case WOLFSSL_MFL_2_12: ssl->max_fragment = 4096; break; + case WOLFSSL_MFL_2_13: ssl->max_fragment = 8192; break; + default: ssl->max_fragment = MAX_RECORD_SIZE; break; + } + ret = WOLFSSL_SUCCESS; + } +#endif /* WOLFSSL_MAX_FRAGMENT_ADJUST */ + else { + /* This call sets the max fragment TLS extension, which gets sent to + * server. The server_hello response is what sets the + * `ssl->max_fragment` in TLSX_MFL_Parse */ + ret = TLSX_UseMaxFragment(&ssl->extensions, mfl, ssl->heap); + } + + return ret; +} + + +/* Set the Maximum Fragment Length extension on the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] mfl Maximum fragment length code, e.g. WOLFSSL_MFL_2_9. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx is NULL. + * @return Negative value on error. + */ +int wolfSSL_CTX_UseMaxFragment(WOLFSSL_CTX* ctx, byte mfl) +{ + int ret; + + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ret = TLSX_UseMaxFragment(&ctx->extensions, mfl, ctx->heap); + } + + return ret; +} + +#endif /* NO_WOLFSSL_CLIENT */ +#endif /* HAVE_MAX_FRAGMENT */ + +#ifdef HAVE_TRUNCATED_HMAC +#ifndef NO_WOLFSSL_CLIENT + +/* Set the Truncated HMAC extension on the object. + * + * @param [in] ssl SSL/TLS object. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL. + * @return Negative value on error. + */ +int wolfSSL_UseTruncatedHMAC(WOLFSSL* ssl) +{ + int ret; + + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ret = TLSX_UseTruncatedHMAC(&ssl->extensions, ssl->heap); + } + + return ret; +} + + +/* Set the Truncated HMAC extension on the context. + * + * @param [in] ctx SSL/TLS context object. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx is NULL. + * @return Negative value on error. + */ +int wolfSSL_CTX_UseTruncatedHMAC(WOLFSSL_CTX* ctx) +{ + int ret; + + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ret = TLSX_UseTruncatedHMAC(&ctx->extensions, ctx->heap); + } + + return ret; +} + +#endif /* NO_WOLFSSL_CLIENT */ +#endif /* HAVE_TRUNCATED_HMAC */ + +/* Elliptic Curves */ +#if defined(HAVE_SUPPORTED_CURVES) + +/* Determine whether a named group is a supported curve or FFDHE group. + * + * @param [in] name Named group identifier. + * @return 1 when the named group is valid. + * @return 0 otherwise. + */ +static int isValidCurveGroup(word16 name) +{ + int ret; + + switch (name) { + case WOLFSSL_ECC_SECP160K1: + case WOLFSSL_ECC_SECP160R1: + case WOLFSSL_ECC_SECP160R2: + case WOLFSSL_ECC_SECP192K1: + case WOLFSSL_ECC_SECP192R1: + case WOLFSSL_ECC_SECP224K1: + case WOLFSSL_ECC_SECP224R1: + case WOLFSSL_ECC_SECP256K1: + case WOLFSSL_ECC_SECP256R1: + case WOLFSSL_ECC_SECP384R1: + case WOLFSSL_ECC_SECP521R1: + case WOLFSSL_ECC_BRAINPOOLP256R1: + case WOLFSSL_ECC_BRAINPOOLP384R1: + case WOLFSSL_ECC_BRAINPOOLP512R1: + case WOLFSSL_ECC_SM2P256V1: + case WOLFSSL_ECC_X25519: + case WOLFSSL_ECC_X448: + case WOLFSSL_ECC_BRAINPOOLP256R1TLS13: + case WOLFSSL_ECC_BRAINPOOLP384R1TLS13: + case WOLFSSL_ECC_BRAINPOOLP512R1TLS13: + + case WOLFSSL_FFDHE_2048: + case WOLFSSL_FFDHE_3072: + case WOLFSSL_FFDHE_4096: + case WOLFSSL_FFDHE_6144: + case WOLFSSL_FFDHE_8192: + +#ifdef WOLFSSL_HAVE_MLKEM +#ifndef WOLFSSL_NO_ML_KEM + #ifndef WOLFSSL_TLS_NO_MLKEM_STANDALONE + case WOLFSSL_ML_KEM_512: + case WOLFSSL_ML_KEM_768: + case WOLFSSL_ML_KEM_1024: + #endif /* !WOLFSSL_TLS_NO_MLKEM_STANDALONE */ + #ifdef WOLFSSL_PQC_HYBRIDS + case WOLFSSL_SECP384R1MLKEM1024: + case WOLFSSL_X25519MLKEM768: + case WOLFSSL_SECP256R1MLKEM768: + #endif /* WOLFSSL_PQC_HYBRIDS */ + #ifdef WOLFSSL_EXTRA_PQC_HYBRIDS + case WOLFSSL_SECP256R1MLKEM512: + case WOLFSSL_SECP384R1MLKEM768: + case WOLFSSL_SECP521R1MLKEM1024: + case WOLFSSL_X25519MLKEM512: + case WOLFSSL_X448MLKEM768: + #endif /* WOLFSSL_EXTRA_PQC_HYBRIDS */ +#endif /* !WOLFSSL_NO_ML_KEM */ +#ifdef WOLFSSL_MLKEM_KYBER + case WOLFSSL_KYBER_LEVEL1: + case WOLFSSL_KYBER_LEVEL3: + case WOLFSSL_KYBER_LEVEL5: + case WOLFSSL_P256_KYBER_LEVEL1: + case WOLFSSL_P384_KYBER_LEVEL3: + case WOLFSSL_P521_KYBER_LEVEL5: + case WOLFSSL_X25519_KYBER_LEVEL1: + case WOLFSSL_X448_KYBER_LEVEL3: + case WOLFSSL_X25519_KYBER_LEVEL3: + case WOLFSSL_P256_KYBER_LEVEL3: +#endif /* WOLFSSL_MLKEM_KYBER */ +#endif /* WOLFSSL_HAVE_MLKEM*/ + ret = 1; + break; + + default: + ret = 0; + break; + } + + return ret; +} + +/* Set a named group in the Supported Groups extension on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] name Named group identifier. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL or the group is invalid. + * @return WOLFSSL_FAILURE when TLS is not compiled in. + */ +int wolfSSL_UseSupportedCurve(WOLFSSL* ssl, word16 name) +{ + int ret; + + if ((ssl == NULL) || (!isValidCurveGroup(name))) { + ret = BAD_FUNC_ARG; + } + else { + ssl->options.userCurves = 1; + #if defined(NO_TLS) + ret = WOLFSSL_FAILURE; + #else + ret = TLSX_UseSupportedCurve(&ssl->extensions, name, ssl->heap, + ssl->options.side); + #endif /* NO_TLS */ + } + + return ret; +} + + +/* Set a named group in the Supported Groups extension on the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] name Named group identifier. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx is NULL or the group is invalid. + * @return WOLFSSL_FAILURE when TLS is not compiled in. + */ +int wolfSSL_CTX_UseSupportedCurve(WOLFSSL_CTX* ctx, word16 name) +{ + int ret; + + if ((ctx == NULL) || (!isValidCurveGroup(name))) { + ret = BAD_FUNC_ARG; + } + else { + ctx->userCurves = 1; + #if defined(NO_TLS) + ret = WOLFSSL_FAILURE; + #else + ret = TLSX_UseSupportedCurve(&ctx->extensions, name, ctx->heap, + ctx->method->side); + #endif /* NO_TLS */ + } + + return ret; +} + +#if defined(OPENSSL_EXTRA) +/* Validate a list of group identifiers and translate them into named groups. + * + * Group values may be wolfSSL named groups or curve NIDs (when ECC is + * available). + * + * @param [in] groups Array of group identifiers. + * @param [in] count Number of groups in the array. + * @param [out] outGroups Array to hold the named groups. Must have at least + * count entries. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when a group is not recognized. + */ +static int wolfssl_validate_groups(const int* groups, int count, int* outGroups) +{ + int i; + int ret = WOLFSSL_SUCCESS; + + for (i = 0; i < count; i++) { + if (isValidCurveGroup((word16)groups[i])) { + outGroups[i] = groups[i]; + } +#ifdef HAVE_ECC + else { + /* Groups may be populated with curve NIDs. */ + int oid = (int)nid2oid(groups[i], oidCurveType); + int name = (int)GetCurveByOID(oid); + if (name == 0) { + WOLFSSL_MSG("Invalid group name"); + ret = WOLFSSL_FAILURE; + break; + } + outGroups[i] = name; + } +#else + else { + WOLFSSL_MSG("Invalid group name"); + ret = WOLFSSL_FAILURE; + break; + } +#endif + } + + return ret; +} + +/* Set the list of supported groups on the context. + * + * Group values may be wolfSSL named groups or curve NIDs. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] groups Array of group identifiers. + * @param [in] count Number of groups in the array. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when count is invalid or a group is not recognized. + */ +int wolfSSL_CTX_set1_groups(WOLFSSL_CTX* ctx, int* groups, int count) +{ + int _groups[WOLFSSL_MAX_GROUP_COUNT]; + int ret = WOLFSSL_SUCCESS; + + WOLFSSL_ENTER("wolfSSL_CTX_set1_groups"); + if (groups == NULL || count <= 0) { + WOLFSSL_MSG("Groups NULL or count not positive"); + ret = WOLFSSL_FAILURE; + } + else if (count > WOLFSSL_MAX_GROUP_COUNT) { + WOLFSSL_MSG("Group count exceeds maximum"); + ret = WOLFSSL_FAILURE; + } + else { + /* Translate the input list into named groups, then apply it. */ + ret = wolfssl_validate_groups(groups, count, _groups); + if (ret == WOLFSSL_SUCCESS) { + ret = wolfSSL_CTX_set_groups(ctx, _groups, count); + /* Normalize any non-success result to WOLFSSL_FAILURE. */ + if (ret != WOLFSSL_SUCCESS) { + ret = WOLFSSL_FAILURE; + } + } + } + + return ret; +} + +/* Set the list of supported groups on the object. + * + * Group values may be wolfSSL named groups or curve NIDs. + * + * @param [in] ssl SSL/TLS object. + * @param [in] groups Array of group identifiers. + * @param [in] count Number of groups in the array. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when count is invalid or a group is not recognized. + */ +int wolfSSL_set1_groups(WOLFSSL* ssl, int* groups, int count) +{ + int _groups[WOLFSSL_MAX_GROUP_COUNT]; + int ret = WOLFSSL_SUCCESS; + + WOLFSSL_ENTER("wolfSSL_set1_groups"); + if (groups == NULL || count <= 0) { + WOLFSSL_MSG("Groups NULL or count not positive"); + ret = WOLFSSL_FAILURE; + } + else if (count > WOLFSSL_MAX_GROUP_COUNT) { + WOLFSSL_MSG("Group count exceeds maximum"); + ret = WOLFSSL_FAILURE; + } + else { + /* Translate the input list into named groups, then apply it. */ + ret = wolfssl_validate_groups(groups, count, _groups); + if (ret == WOLFSSL_SUCCESS) { + ret = wolfSSL_set_groups(ssl, _groups, count); + /* Normalize any non-success result to WOLFSSL_FAILURE. */ + if (ret != WOLFSSL_SUCCESS) { + ret = WOLFSSL_FAILURE; + } + } + } + + return ret; +} +#endif /* OPENSSL_EXTRA */ +#endif /* HAVE_SUPPORTED_CURVES */ + +/* Application-Layer Protocol Negotiation */ +#ifdef HAVE_ALPN + +/* Set the Application-Layer Protocol Negotiation extension on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] protocol_name_list Comma-separated list of protocol names. + * @param [in] protocol_name_listSz Length of the list in bytes. + * @param [in] options Bitmask of ALPN options. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when an argument is NULL, the list is too long or + * options are unsupported. + * @return MEMORY_ERROR on allocation failure. + */ +WOLFSSL_ABI +int wolfSSL_UseALPN(WOLFSSL* ssl, char *protocol_name_list, + word32 protocol_name_listSz, byte options) +{ + char* list = NULL; + char* ptr = NULL; + char** token = NULL; + word16 len; + int idx = 0; + int ret = WOLFSSL_SUCCESS; + + WOLFSSL_ENTER("wolfSSL_UseALPN"); + + if ((ssl == NULL) || (protocol_name_list == NULL)) { + ret = BAD_FUNC_ARG; + } + else if (protocol_name_listSz > (WOLFSSL_MAX_ALPN_NUMBER * + WOLFSSL_MAX_ALPN_PROTO_NAME_LEN + WOLFSSL_MAX_ALPN_NUMBER)) { + WOLFSSL_MSG("Invalid arguments, protocol name list too long"); + ret = BAD_FUNC_ARG; + } + else if ((!(options & WOLFSSL_ALPN_CONTINUE_ON_MISMATCH)) && + (!(options & WOLFSSL_ALPN_FAILED_ON_MISMATCH))) { + WOLFSSL_MSG("Invalid arguments, options not supported"); + ret = BAD_FUNC_ARG; + } + if (ret == WOLFSSL_SUCCESS) { + list = (char *)XMALLOC(protocol_name_listSz + 1, ssl->heap, + DYNAMIC_TYPE_ALPN); + token = (char **)XMALLOC(sizeof(char*) * (WOLFSSL_MAX_ALPN_NUMBER + 1), + ssl->heap, DYNAMIC_TYPE_ALPN); + if ((list == NULL) || (token == NULL)) { + WOLFSSL_MSG("Memory failure"); + ret = MEMORY_ERROR; + } + } + if (ret == WOLFSSL_SUCCESS) { + XMEMSET(token, 0, sizeof(char *) * (WOLFSSL_MAX_ALPN_NUMBER+1)); + + XSTRNCPY(list, protocol_name_list, protocol_name_listSz); + list[protocol_name_listSz] = '\0'; + + /* Read all protocol names from the list. */ + token[idx] = XSTRTOK(list, ",", &ptr); + while ((idx < WOLFSSL_MAX_ALPN_NUMBER) && (token[idx] != NULL)) { + token[++idx] = XSTRTOK(NULL, ",", &ptr); + } + + /* Add the protocol name list to the TLS extension in reverse order. */ + while ((idx--) > 0) { + len = (word16)XSTRLEN(token[idx]); + + ret = TLSX_UseALPN(&ssl->extensions, token[idx], len, options, + ssl->heap); + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("TLSX_UseALPN failure"); + break; + } + } + } + + XFREE(token, ssl->heap, DYNAMIC_TYPE_ALPN); + XFREE(list, ssl->heap, DYNAMIC_TYPE_ALPN); + + return ret; +} + +/* Get the ALPN protocol negotiated for the object. + * + * @param [in] ssl SSL/TLS object. + * @param [out] protocol_name Negotiated protocol name. + * @param [out] size Length of the protocol name in bytes. + * @return WOLFSSL_SUCCESS on success. + * @return Negative value on error. + */ +int wolfSSL_ALPN_GetProtocol(WOLFSSL* ssl, char **protocol_name, word16 *size) +{ + return TLSX_ALPN_GetRequest((ssl != NULL) ? ssl->extensions : NULL, + (void **)protocol_name, size); +} + +/* Get the ALPN protocol list offered by the peer as a comma-separated string. + * + * The returned list must be freed with wolfSSL_ALPN_FreePeerProtocol(). + * + * @param [in] ssl SSL/TLS object. + * @param [out] list Newly allocated comma-separated protocol list. + * @param [out] listSz Length of the list string. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when an argument is NULL. + * @return BUFFER_ERROR when the peer offered no protocols. + * @return MEMORY_ERROR on allocation failure. + */ +int wolfSSL_ALPN_GetPeerProtocol(WOLFSSL* ssl, char **list, word16 *listSz) +{ + int i, len; + char *p; + byte *s; + int ret = WOLFSSL_SUCCESS; + + if ((ssl == NULL) || (list == NULL) || (listSz == NULL)) { + ret = BAD_FUNC_ARG; + } + else if ((ssl->alpn_peer_requested == NULL) || + (ssl->alpn_peer_requested_length == 0)) { + ret = BUFFER_ERROR; + } + if (ret == WOLFSSL_SUCCESS) { + /* ssl->alpn_peer_requested are the original bytes sent in a + * ClientHello, formatted as (len-byte chars+)+. To turn n protocols + * into a comma-separated C string, one needs (n-1) commas and a final + * 0 byte which has the same length as the original. + * The returned length is the strlen() of the C string, so -1 of + * that. */ + *listSz = ssl->alpn_peer_requested_length-1; + *list = p = (char *)XMALLOC(ssl->alpn_peer_requested_length, ssl->heap, + DYNAMIC_TYPE_TLSX); + if (p == NULL) { + ret = MEMORY_ERROR; + } + } + if (ret == WOLFSSL_SUCCESS) { + s = ssl->alpn_peer_requested; + for (i = 0; i < ssl->alpn_peer_requested_length; p += len, i += len) { + if (i != 0) { + *p++ = ','; + } + len = s[i++]; + /* Guard against bad length bytes. */ + if ((i + len) > ssl->alpn_peer_requested_length) { + XFREE(*list, ssl->heap, DYNAMIC_TYPE_TLSX); + *list = NULL; + ret = WOLFSSL_FAILURE; + break; + } + XMEMCPY(p, s + i, (size_t)len); + } + if (ret == WOLFSSL_SUCCESS) { + *p = 0; + } + } + + return ret; +} + + +/* Free a peer protocol list returned by wolfSSL_ALPN_GetPeerProtocol(). + * + * @param [in] ssl SSL/TLS object. + * @param [in, out] list Protocol list to free; set to NULL on return. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL. + */ +int wolfSSL_ALPN_FreePeerProtocol(WOLFSSL* ssl, char **list) +{ + int ret; + + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + else { + XFREE(*list, ssl->heap, DYNAMIC_TYPE_TLSX); + *list = NULL; + ret = WOLFSSL_SUCCESS; + } + + return ret; +} + +#endif /* HAVE_ALPN */ + +/* Secure Renegotiation */ +#ifdef HAVE_SERVER_RENEGOTIATION_INFO + +/* Enable the Secure Renegotiation extension on the object. + * + * Use of secure renegotiation is discouraged. + * + * @param [in] ssl SSL/TLS object. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL. + * @return Negative value on error. + */ +int wolfSSL_UseSecureRenegotiation(WOLFSSL* ssl) +{ + int ret = WC_NO_ERR_TRACE(BAD_FUNC_ARG); +#if defined(NO_TLS) + (void)ssl; +#else + if (ssl != NULL) { + ret = TLSX_UseSecureRenegotiation(&ssl->extensions, ssl->heap); + } + else { + ret = BAD_FUNC_ARG; + } + + if (ret == WOLFSSL_SUCCESS) { + TLSX* extension = TLSX_Find(ssl->extensions, TLSX_RENEGOTIATION_INFO); + if (extension != NULL) { + ssl->secure_renegotiation = (SecureRenegotiation*)extension->data; + } + } +#endif /* !NO_TLS */ + return ret; +} + +/* Enable the Secure Renegotiation extension on the context. + * + * Use of secure renegotiation is discouraged. + * + * @param [in] ctx SSL/TLS context object. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx is NULL. + */ +int wolfSSL_CTX_UseSecureRenegotiation(WOLFSSL_CTX* ctx) +{ + int ret; + + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ctx->useSecureReneg = 1; + ret = WOLFSSL_SUCCESS; + } + + return ret; +} + +#ifdef HAVE_SECURE_RENEGOTIATION +/* Perform a secure renegotiation handshake on the object. + * + * User forced; use of secure renegotiation is discouraged. + * + * @param [in] ssl SSL/TLS object. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL. + * @return SECURE_RENEGOTIATION_E when renegotiation is not allowed. + * @return WOLFSSL_FATAL_ERROR on error. + */ +static int _Rehandshake(WOLFSSL* ssl) +{ + int ret; + + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + goto end; + } + + if (IsAtLeastTLSv1_3(ssl->version)) { + WOLFSSL_MSG("Secure Renegotiation not supported in TLS 1.3"); + ret = SECURE_RENEGOTIATION_E; + goto end; + } + + if (ssl->secure_renegotiation == NULL) { + WOLFSSL_MSG("Secure Renegotiation not forced on by user"); + ret = SECURE_RENEGOTIATION_E; + goto end; + } + + if (ssl->secure_renegotiation->enabled == 0) { + WOLFSSL_MSG("Secure Renegotiation not enabled at extension level"); + ret = SECURE_RENEGOTIATION_E; + goto end; + } + +#ifdef WOLFSSL_DTLS + if (ssl->options.dtls && (ssl->keys.dtls_epoch == 0xFFFF)) { + WOLFSSL_MSG("Secure Renegotiation not allowed. Epoch would wrap"); + ret = SECURE_RENEGOTIATION_E; + goto end; + } +#endif + + /* If the client started the renegotiation, the server will already + * have processed the client's hello. */ + if ((ssl->options.side != WOLFSSL_SERVER_END) || + (ssl->options.acceptState != ACCEPT_FIRST_REPLY_DONE)) { + + if (ssl->options.handShakeState != HANDSHAKE_DONE) { + if (!ssl->options.handShakeDone) { + WOLFSSL_MSG("Can't renegotiate until initial " + "handshake complete"); + ret = SECURE_RENEGOTIATION_E; + goto end; + } + else { + WOLFSSL_MSG("Renegotiation already started. " + "Moving it forward."); + ret = wolfSSL_negotiate(ssl); + if (ret == WOLFSSL_SUCCESS) { + ssl->secure_rene_count++; + } + goto end; + } + } + + /* Reset handshake states. */ + ssl->options.sendVerify = 0; + ssl->options.serverState = NULL_STATE; + ssl->options.clientState = NULL_STATE; + ssl->options.connectState = CONNECT_BEGIN; + ssl->options.acceptState = ACCEPT_BEGIN_RENEG; + ssl->options.handShakeState = NULL_STATE; + ssl->options.processReply = 0; /* TODO, move states in internal.h */ + + XMEMSET(&ssl->msgsReceived, 0, sizeof(ssl->msgsReceived)); + + ssl->secure_renegotiation->cache_status = SCR_CACHE_NEEDED; + +#if !defined(NO_WOLFSSL_SERVER) && !defined(WOLFSSL_NO_TLS12) + if (ssl->options.side == WOLFSSL_SERVER_END) { + ret = SendHelloRequest(ssl); + if (ret != 0) { + ssl->error = ret; + ret = WOLFSSL_FATAL_ERROR; + goto end; + } + } +#endif /* !NO_WOLFSSL_SERVER && !WOLFSSL_NO_TLS12 */ + + ret = InitHandshakeHashes(ssl); + if (ret != 0) { + ssl->error = ret; + ret = WOLFSSL_FATAL_ERROR; + goto end; + } + } + ret = wolfSSL_negotiate(ssl); + if (ret == WOLFSSL_SUCCESS) { + ssl->secure_rene_count++; + } + +end: + return ret; +} + + +/* Perform a secure renegotiation handshake on the object. + * + * User forced; use of secure renegotiation is discouraged. + * + * @param [in] ssl SSL/TLS object. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ssl is NULL. + * @return Negative value on error. + */ +int wolfSSL_Rehandshake(WOLFSSL* ssl) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_Rehandshake"); + + if (ssl == NULL) { + ret = WOLFSSL_FAILURE; + } + else { +#ifdef HAVE_SESSION_TICKET + ret = WOLFSSL_SUCCESS; +#endif + + if (ssl->options.side == WOLFSSL_SERVER_END) { + /* Reset option to send certificate verify. */ + ssl->options.sendVerify = 0; + /* Reset resuming flag to do full secure handshake. */ + ssl->options.resuming = 0; + } + else { + /* Reset resuming flag to do full secure handshake. */ + ssl->options.resuming = 0; + #if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_CLIENT) + /* Clearing the ticket. */ + ret = wolfSSL_UseSessionTicket(ssl); + #endif + } + /* CLIENT/SERVER: Reset peer authentication for full secure + * handshake. */ + ssl->options.peerAuthGood = 0; + +#ifdef HAVE_SESSION_TICKET + if (ret == WOLFSSL_SUCCESS) +#endif + { + ret = _Rehandshake(ssl); + } + } + + return ret; +} + + +#ifndef NO_WOLFSSL_CLIENT + +/* Perform a secure resumption handshake on the object. + * + * Client side only. User forced; use of secure renegotiation is discouraged. + * + * @param [in] ssl SSL/TLS object. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL. + * @return WOLFSSL_FATAL_ERROR when called on a server. + */ +int wolfSSL_SecureResume(WOLFSSL* ssl) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_SecureResume"); + + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + else if (ssl->options.side == WOLFSSL_SERVER_END) { + ssl->error = SIDE_ERROR; + ret = WOLFSSL_FATAL_ERROR; + } + else { + ret = _Rehandshake(ssl); + } + + return ret; +} + +#endif /* NO_WOLFSSL_CLIENT */ + +#endif /* HAVE_SECURE_RENEGOTIATION */ + +/* Get whether secure renegotiation is enabled for the object. + * + * @param [in] ssl SSL/TLS object. + * @return 1 when secure renegotiation is enabled. + * @return 0 when ssl is NULL or it is not enabled. + */ +long wolfSSL_SSL_get_secure_renegotiation_support(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_SSL_get_secure_renegotiation_support"); + + return (ssl != NULL) && (ssl->secure_renegotiation != NULL) && + ssl->secure_renegotiation->enabled; +} + +#endif /* HAVE_SECURE_RENEGOTIATION_INFO */ + +#if !defined(NO_WOLFSSL_CLIENT) && !defined(WOLFSSL_NO_TLS12) && \ + defined(WOLFSSL_HARDEN_TLS) && !defined(WOLFSSL_HARDEN_TLS_NO_SCR_CHECK) +/* Get whether the secure renegotiation check is enabled for the object. + * + * @param [in] ssl SSL/TLS object. + * @return Non-zero when the check is enabled, 0 otherwise. + * @return BAD_FUNC_ARG when ssl is NULL. + */ +WOLFSSL_API int wolfSSL_get_scr_check_enabled(const WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_get_scr_check_enabled"); + + return (ssl == NULL) ? BAD_FUNC_ARG : ssl->scr_check_enabled; +} + +/* Set whether the secure renegotiation check is enabled for the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] enabled Non-zero to enable the check, 0 to disable it. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL. + */ +WOLFSSL_API int wolfSSL_set_scr_check_enabled(WOLFSSL* ssl, byte enabled) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_set_scr_check_enabled"); + + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ssl->scr_check_enabled = !!enabled; + ret = WOLFSSL_SUCCESS; + } + + return ret; +} +#endif + +#if defined(HAVE_SESSION_TICKET) +/* Session Ticket */ + +#if !defined(NO_WOLFSSL_SERVER) +/* Disable use of session tickets with TLS 1.2 on the context. + * + * @param [in] ctx SSL/TLS context object. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx is NULL. + */ +int wolfSSL_CTX_NoTicketTLSv12(WOLFSSL_CTX* ctx) +{ + int ret; + + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ctx->noTicketTls12 = 1; + ret = WOLFSSL_SUCCESS; + } + + return ret; +} + +/* Disable use of session tickets with TLS 1.2 on the object. + * + * @param [in] ssl SSL/TLS object. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL. + */ +int wolfSSL_NoTicketTLSv12(WOLFSSL* ssl) +{ + int ret; + + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ssl->options.noTicketTls12 = 1; + ret = WOLFSSL_SUCCESS; + } + + return ret; +} + +/* Set the session ticket encryption callback on the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] cb Session ticket encryption callback. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx is NULL. + */ +int wolfSSL_CTX_set_TicketEncCb(WOLFSSL_CTX* ctx, SessionTicketEncCb cb) +{ + int ret; + + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ctx->ticketEncCb = cb; + ret = WOLFSSL_SUCCESS; + } + + return ret; +} + +/* Set the session ticket lifetime hint, in seconds, on the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] hint Lifetime hint in seconds. No more than 604800 (7 days). + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx is NULL or hint is out of range. + */ +int wolfSSL_CTX_set_TicketHint(WOLFSSL_CTX* ctx, int hint) +{ + int ret; + + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + /* RFC8446 Section 4.6.1: Servers MUST NOT use any value greater than + * 604800 seconds (7 days). */ + else if ((hint < 0) || (hint > 604800)) { + ret = BAD_FUNC_ARG; + } + else { + ctx->ticketHint = hint; + ret = WOLFSSL_SUCCESS; + } + + return ret; +} + +/* Set the user context passed to the session ticket encryption callback. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] userCtx User context for the ticket encryption callback. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx is NULL. + */ +int wolfSSL_CTX_set_TicketEncCtx(WOLFSSL_CTX* ctx, void* userCtx) +{ + int ret; + + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ctx->ticketEncCtx = userCtx; + ret = WOLFSSL_SUCCESS; + } + + return ret; +} + +/* Get the user context passed to the session ticket encryption callback. + * + * @param [in] ctx SSL/TLS context object. + * @return User context on success. + * @return NULL when ctx is NULL. + */ +void* wolfSSL_CTX_get_TicketEncCtx(WOLFSSL_CTX* ctx) +{ + void* ret; + + if (ctx == NULL) { + ret = NULL; + } + else { + ret = ctx->ticketEncCtx; + } + + return ret; +} + +#ifdef WOLFSSL_TLS13 +/* Set the maximum number of TLS 1.3 session tickets to send. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] mxTickets Maximum number of tickets to send. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ctx is NULL. + */ +int wolfSSL_CTX_set_num_tickets(WOLFSSL_CTX* ctx, size_t mxTickets) +{ + int ret; + + if (ctx == NULL) { + ret = WOLFSSL_FAILURE; + } + else { + ctx->maxTicketTls13 = (unsigned int)mxTickets; + ret = WOLFSSL_SUCCESS; + } + + return ret; +} + +/* Get the maximum number of TLS 1.3 session tickets to send. + * + * @param [in] ctx SSL/TLS context object. + * @return Maximum number of tickets to send, or 0 when ctx is NULL. + */ +size_t wolfSSL_CTX_get_num_tickets(WOLFSSL_CTX* ctx) +{ + size_t ret; + + if (ctx == NULL) { + ret = 0; + } + else { + ret = (size_t)ctx->maxTicketTls13; + } + + return ret; +} +#endif /* WOLFSSL_TLS13 */ +#endif /* !NO_WOLFSSL_SERVER */ + +#if !defined(NO_WOLFSSL_CLIENT) +/* Enable use of the session ticket extension on the object. + * + * @param [in] ssl SSL/TLS object. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL. + * @return Negative value on error. + */ +int wolfSSL_UseSessionTicket(WOLFSSL* ssl) +{ + int ret; + + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ret = TLSX_UseSessionTicket(&ssl->extensions, NULL, ssl->heap); + } + + return ret; +} + +/* Enable use of the session ticket extension on the context. + * + * @param [in] ctx SSL/TLS context object. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx is NULL. + * @return Negative value on error. + */ +int wolfSSL_CTX_UseSessionTicket(WOLFSSL_CTX* ctx) +{ + int ret; + + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ret = TLSX_UseSessionTicket(&ctx->extensions, NULL, ctx->heap); + } + + return ret; +} + +/* Get the session ticket stored on the object. + * + * When buf is NULL and *bufSz is 0, the length required is returned in bufSz. + * + * @param [in] ssl SSL/TLS object. + * @param [out] buf Buffer to hold the ticket. May be NULL for length. + * @param [in, out] bufSz In: size of buffer. Out: length of ticket. + * @return WOLFSSL_SUCCESS on success. + * @return LENGTH_ONLY_E when buf is NULL and bufSz has been set. + * @return BAD_FUNC_ARG when ssl or bufSz is NULL. + */ +int wolfSSL_get_SessionTicket(WOLFSSL* ssl, byte* buf, word32* bufSz) +{ + int ret; + + if ((ssl == NULL) || (bufSz == NULL)) { + ret = BAD_FUNC_ARG; + } + /* No buffer and zero size is a query for the required length. */ + else if ((*bufSz == 0) && (buf == NULL)) { + *bufSz = ssl->session->ticketLen; + ret = LENGTH_ONLY_E; + } + else if (buf == NULL) { + ret = BAD_FUNC_ARG; + } + else { + /* Copy the ticket when it fits, otherwise report zero length. */ + if (ssl->session->ticketLen <= *bufSz) { + XMEMCPY(buf, ssl->session->ticket, ssl->session->ticketLen); + *bufSz = ssl->session->ticketLen; + } + else { + *bufSz = 0; + } + ret = WOLFSSL_SUCCESS; + } + + return ret; +} + +/* Set the session ticket to use on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] buf Ticket data, may be NULL when bufSz is 0. + * @param [in] bufSz Length of ticket data in bytes. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL or buf is NULL with bufSz > 0. + * @return MEMORY_ERROR on allocation failure. + */ +int wolfSSL_set_SessionTicket(WOLFSSL* ssl, const byte* buf, word32 bufSz) +{ + int ret = WOLFSSL_SUCCESS; + + if ((ssl == NULL) || ((buf == NULL) && (bufSz > 0))) { + ret = BAD_FUNC_ARG; + } + else { + if (bufSz > 0) { + /* Ticket will fit into the static ticket buffer. */ + if (bufSz <= SESSION_TICKET_LEN) { + if (ssl->session->ticketLenAlloc > 0) { + XFREE(ssl->session->ticket, ssl->session->heap, + DYNAMIC_TYPE_SESSION_TICK); + ssl->session->ticketLenAlloc = 0; + ssl->session->ticket = ssl->session->staticTicket; + } + } + else { /* Ticket requires dynamic ticket storage */ + /* Is the dynamic buffer big enough? */ + if (ssl->session->ticketLen < bufSz) { + if (ssl->session->ticketLenAlloc > 0) { + XFREE(ssl->session->ticket, ssl->session->heap, + DYNAMIC_TYPE_SESSION_TICK); + } + ssl->session->ticket = (byte*)XMALLOC(bufSz, + ssl->session->heap, DYNAMIC_TYPE_SESSION_TICK); + if (ssl->session->ticket == NULL) { + ssl->session->ticket = ssl->session->staticTicket; + ssl->session->ticketLenAlloc = 0; + ret = MEMORY_ERROR; + } + else { + ssl->session->ticketLenAlloc = (word16)bufSz; + } + } + } + if (ret == WOLFSSL_SUCCESS) { + XMEMCPY(ssl->session->ticket, buf, bufSz); + } + } + if (ret == WOLFSSL_SUCCESS) { + ssl->session->ticketLen = (word16)bufSz; + } + } + + return ret; +} + + +/* Set the session ticket callback and user context on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] cb Session ticket callback. + * @param [in] ctx User context passed to the callback. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL. + */ +int wolfSSL_set_SessionTicket_cb(WOLFSSL* ssl, CallbackSessionTicket cb, + void* ctx) +{ + int ret; + + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ssl->session_ticket_cb = cb; + ssl->session_ticket_ctx = ctx; + ret = WOLFSSL_SUCCESS; + } + + return ret; +} +#endif /* !NO_WOLFSSL_CLIENT */ + +#endif /* HAVE_SESSION_TICKET */ + + +#ifdef HAVE_EXTENDED_MASTER +#ifndef NO_WOLFSSL_CLIENT + +/* Disable the Extended Master Secret extension on the context. + * + * @param [in] ctx SSL/TLS context object. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx is NULL. + */ +int wolfSSL_CTX_DisableExtendedMasterSecret(WOLFSSL_CTX* ctx) +{ + int ret; + + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ctx->haveEMS = 0; + ret = WOLFSSL_SUCCESS; + } + + return ret; +} + + +/* Disable the Extended Master Secret extension on the object. + * + * @param [in] ssl SSL/TLS object. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL. + */ +int wolfSSL_DisableExtendedMasterSecret(WOLFSSL* ssl) +{ + int ret; + + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ssl->options.haveEMS = 0; + ret = WOLFSSL_SUCCESS; + } + + return ret; +} + +#endif +#endif + +#endif /* !NO_TLS */ +/* ---- OpenSSL-compatibility TLS extension APIs (moved from ssl.c) ---- */ + +#ifdef OPENSSL_EXTRA + +#ifdef HAVE_PK_CALLBACKS +/* Set the debug argument passed to the logging callback on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] arg Debug argument. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ssl is NULL. + */ +long wolfSSL_set_tlsext_debug_arg(WOLFSSL* ssl, void *arg) +{ + long ret; + + if (ssl == NULL) { + ret = WOLFSSL_FAILURE; + } + else { + ssl->loggingCtx = arg; + ret = WOLFSSL_SUCCESS; + } + + return ret; +} +#endif /* HAVE_PK_CALLBACKS */ + +#ifndef NO_WOLFSSL_STUB +/* Get the certificate status request extensions on the object. + * + * Not implemented - stub for OpenSSL compatibility. + * + * @param [in] s SSL/TLS object. + * @param [in] arg Ignored. + * @return WOLFSSL_FAILURE always. + */ +long wolfSSL_get_tlsext_status_exts(WOLFSSL *s, void *arg) +{ + (void)s; + (void)arg; + WOLFSSL_STUB("wolfSSL_get_tlsext_status_exts"); + return WOLFSSL_FAILURE; +} +#endif + +/* Set the certificate status request extensions on the object. + * + * Not implemented - stub for OpenSSL compatibility. + * + * @param [in] s SSL/TLS object. + * @param [in] arg Ignored. + * @return WOLFSSL_FAILURE always. + */ +#ifndef NO_WOLFSSL_STUB +long wolfSSL_set_tlsext_status_exts(WOLFSSL *s, void *arg) +{ + (void)s; + (void)arg; + WOLFSSL_STUB("wolfSSL_set_tlsext_status_exts"); + return WOLFSSL_FAILURE; +} +#endif + +/* Get the certificate status request responder ids on the object. + * + * Not implemented - stub for OpenSSL compatibility. + * + * @param [in] s SSL/TLS object. + * @param [in] arg Ignored. + * @return WOLFSSL_FAILURE always. + */ +#ifndef NO_WOLFSSL_STUB +long wolfSSL_get_tlsext_status_ids(WOLFSSL *s, void *arg) +{ + (void)s; + (void)arg; + WOLFSSL_STUB("wolfSSL_get_tlsext_status_ids"); + return WOLFSSL_FAILURE; +} +#endif + +/* Set the certificate status request responder ids on the object. + * + * Not implemented - stub for OpenSSL compatibility. + * + * @param [in] s SSL/TLS object. + * @param [in] arg Ignored. + * @return WOLFSSL_FAILURE always. + */ +#ifndef NO_WOLFSSL_STUB +long wolfSSL_set_tlsext_status_ids(WOLFSSL *s, void *arg) +{ + (void)s; + (void)arg; + WOLFSSL_STUB("wolfSSL_set_tlsext_status_ids"); + return WOLFSSL_FAILURE; +} +#endif + +#ifdef HAVE_MAX_FRAGMENT +#if !defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS) +/* Set the Maximum Fragment Length extension on the context. + * + * @param [in] c SSL/TLS context object. + * @param [in] mode Maximum fragment length mode, e.g. WOLFSSL_MFL_2_9. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when c is NULL or mode is out of range. + */ +int wolfSSL_CTX_set_tlsext_max_fragment_length(WOLFSSL_CTX *c, + unsigned char mode) +{ + int ret; + + if ((c == NULL) || ((mode < WOLFSSL_MFL_2_9) || + (mode > WOLFSSL_MFL_2_12))) { + ret = BAD_FUNC_ARG; + } + else { + ret = wolfSSL_CTX_UseMaxFragment(c, mode); + } + + return ret; +} +/* Set the Maximum Fragment Length extension on the object. + * + * @param [in] s SSL/TLS object. + * @param [in] mode Maximum fragment length mode, e.g. WOLFSSL_MFL_2_9. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when s is NULL or mode is out of range. + */ +int wolfSSL_set_tlsext_max_fragment_length(WOLFSSL *s, unsigned char mode) +{ + int ret; + + if ((s == NULL) || ((mode < WOLFSSL_MFL_2_9) || + (mode > WOLFSSL_MFL_2_12))) { + ret = BAD_FUNC_ARG; + } + else { + ret = wolfSSL_UseMaxFragment(s, mode); + } + + return ret; +} +#endif /* !NO_WOLFSSL_CLIENT && !NO_TLS */ +#endif /* HAVE_MAX_FRAGMENT */ + +/* Set the signature algorithms list on the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] list Colon-separated list of + algorithms. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ctx or list is NULL or on error. + */ +int wolfSSL_CTX_set1_sigalgs_list(WOLFSSL_CTX* ctx, const char* list) +{ + int ret; + + WOLFSSL_MSG("wolfSSL_CTX_set1_sigalg_list"); + + if ((ctx == NULL) || (list == NULL)) { + WOLFSSL_MSG("Bad function arguments"); + ret = WOLFSSL_FAILURE; + } + /* Cipher suites must exist before the sig algs can be stored on them. */ + else if (AllocateCtxSuites(ctx) != 0) { + ret = WOLFSSL_FAILURE; + } + else { + ret = SetSuitesHashSigAlgo(ctx->suites, list); + } + + return ret; +} + +/* Set the signature algorithms list on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] list Colon-separated list of + algorithms. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ssl or list is NULL or on error. + */ +int wolfSSL_set1_sigalgs_list(WOLFSSL* ssl, const char* list) +{ + int ret; + + WOLFSSL_MSG("wolfSSL_set1_sigalg_list"); + + if ((ssl == NULL) || (list == NULL)) { + WOLFSSL_MSG("Bad function arguments"); + ret = WOLFSSL_FAILURE; + } + /* Cipher suites must exist before the sig algs can be stored on them. */ + else if (AllocateSuites(ssl) != 0) { + ret = WOLFSSL_FAILURE; + } + else { + ret = SetSuitesHashSigAlgo(ssl->suites, list); + } + + return ret; +} + +#ifdef HAVE_ECC + +#if defined(WOLFSSL_TLS13) && defined(HAVE_SUPPORTED_CURVES) +/* Set the supported groups list, by name, on the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] list Colon-separated list of group names. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ctx or list is NULL or on error. + */ +int wolfSSL_CTX_set1_groups_list(WOLFSSL_CTX *ctx, const char *list) +{ + int ret; + + if ((ctx == NULL) || (list == NULL)) { + ret = WOLFSSL_FAILURE; + } + else { + ret = set_curves_list(NULL, ctx, list, 0); + } + + return ret; +} + +/* Set the supported groups list, by name, on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] list Colon-separated list of group names. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ssl or list is NULL or on error. + */ +int wolfSSL_set1_groups_list(WOLFSSL *ssl, const char *list) +{ + int ret; + + if ((ssl == NULL) || (list == NULL)) { + ret = WOLFSSL_FAILURE; + } + else { + ret = set_curves_list(ssl, NULL, list, 0); + } + + return ret; +} +#endif /* WOLFSSL_TLS13 */ + +#endif /* HAVE_ECC */ + +#endif /* OPENSSL_EXTRA */ + +#if defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) + +#ifdef HAVE_SNI +/* Set the SNI host name extension on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] host_name Host name string. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL. + * @return Negative value on error. + */ +int wolfSSL_set_tlsext_host_name(WOLFSSL* ssl, const char* host_name) +{ + int ret; + WOLFSSL_ENTER("wolfSSL_set_tlsext_host_name"); + ret = wolfSSL_UseSNI(ssl, WOLFSSL_SNI_HOST_NAME, host_name, + (word16)XSTRLEN(host_name)); + WOLFSSL_LEAVE("wolfSSL_set_tlsext_host_name", ret); + return ret; +} + +#ifndef NO_WOLFSSL_SERVER +/* Get the SNI host name requested for the object. + * + * May be called by a server to get the accepted name or by a client to get + * the requested name. + * + * @param [in] ssl SSL/TLS object. + * @param [in] type SNI type. + * @return Requested server name on success. + * @return NULL when ssl is NULL or no name is set. + */ +const char * wolfSSL_get_servername(WOLFSSL* ssl, byte type) +{ + void * serverName = NULL; + + if (ssl != NULL) { + /* On a client request the name sent; on a server the name received. */ + TLSX_SNI_GetRequest(ssl->extensions, type, &serverName, + !wolfSSL_is_server(ssl)); + } + + return (const char *)serverName; +} +#endif + +#endif /* HAVE_SNI */ + +#ifdef HAVE_SNI +/* Set the SNI receive callback on the context. + * + * Compatibility function; consider using wolfSSL_CTX_set_servername_callback(). + * + * @param [in] ctx SSL/TLS context object. + * @param [in] cb SNI receive callback. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ctx is NULL. + */ +int wolfSSL_CTX_set_tlsext_servername_callback(WOLFSSL_CTX* ctx, + CallbackSniRecv cb) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_set_tlsext_servername_callback"); + + if (ctx == NULL) { + ret = WOLFSSL_FAILURE; + } + else { + ctx->sniRecvCb = cb; + ret = WOLFSSL_SUCCESS; + } + + return ret; +} + +#endif /* HAVE_SNI */ + +#endif /* OPENSSL_ALL || OPENSSL_EXTRA */ + +#ifdef HAVE_SNI + +/* Set the SNI receive callback on the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] cb SNI receive callback. + */ +void wolfSSL_CTX_set_servername_callback(WOLFSSL_CTX* ctx, CallbackSniRecv cb) +{ + WOLFSSL_ENTER("wolfSSL_CTX_set_servername_callback"); + + if (ctx != NULL) { + ctx->sniRecvCb = cb; + } +} + + +/* Set the user argument passed to the SNI receive callback on the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] arg User argument for the SNI receive callback. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ctx is NULL. + */ +int wolfSSL_CTX_set_servername_arg(WOLFSSL_CTX* ctx, void* arg) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_set_servername_arg"); + + if (ctx == NULL) { + ret = WOLFSSL_FAILURE; + } + else { + ctx->sniRecvCbArg = arg; + ret = WOLFSSL_SUCCESS; + } + + return ret; +} + +#endif /* HAVE_SNI */ + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) \ + || defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) + +#if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_SERVER) +/* Expected return values from implementations of OpenSSL ticket key callback. + */ +#define TICKET_KEY_CB_RET_FAILURE (-1) +#define TICKET_KEY_CB_RET_NOT_FOUND 0 +#define TICKET_KEY_CB_RET_OK 1 +#define TICKET_KEY_CB_RET_RENEW 2 + +/* Encrypt the ticket data in place and compute the HMAC over it. + * + * @param [in] evpCtx Cipher context initialized by the callback. + * @param [in] hmacCtx HMAC context initialized by the callback. + * @param [in, out] encTicket Ticket data, encrypted in place. + * @param [in] encTicketLen Length of the plaintext ticket data in bytes. + * @param [in] encSz Capacity of the ticket buffer in bytes. + * @param [out] mac HMAC of the encrypted data. + * @param [out] outSz Length of the encrypted data in bytes. + * @return 1 on success. + * @return 0 on error. + */ +static int wolfssl_ticket_key_enc(WOLFSSL_EVP_CIPHER_CTX* evpCtx, + WOLFSSL_HMAC_CTX* hmacCtx, unsigned char* encTicket, int encTicketLen, + int encSz, unsigned char* mac, int* outSz) +{ + int ret = 1; + int len = 0; + int totalSz = 0; + unsigned int mdSz = 0; + + /* Encrypt in place. */ + if (!wolfSSL_EVP_CipherUpdate(evpCtx, encTicket, &len, encTicket, + encTicketLen)) { + ret = 0; + } + if (ret == 1) { + totalSz = len; + /* Encrypted data must fit in the output buffer. */ + if (totalSz > encSz) { + ret = 0; + } + } + if ((ret == 1) && + (!wolfSSL_EVP_EncryptFinal(evpCtx, &encTicket[len], &len))) { + ret = 0; + } + if (ret == 1) { + /* Total length of encrypted data. */ + totalSz += len; + if (totalSz > encSz) { + ret = 0; + } + } + /* HMAC the encrypted data into the parameter 'mac'. */ + if ((ret == 1) && (!wolfSSL_HMAC_Update(hmacCtx, encTicket, totalSz))) { + ret = 0; + } + if ((ret == 1) && (!wolfSSL_HMAC_Final(hmacCtx, mac, &mdSz))) { + ret = 0; + } + if (ret == 1) { + *outSz = totalSz; + } + + return ret; +} + +/* Verify the ticket HMAC then decrypt the ticket data in place. + * + * @param [in] evpCtx Cipher context initialized by the callback. + * @param [in] hmacCtx HMAC context initialized by the callback. + * @param [in, out] encTicket Ticket data, decrypted in place. + * @param [in] encTicketLen Length of the encrypted ticket data in bytes. + * @param [in] mac Expected HMAC of the encrypted data. + * @param [out] outSz Length of the decrypted data in bytes. + * @return 1 on success. + * @return 0 on error or when the HMAC does not match. + */ +static int wolfssl_ticket_key_dec(WOLFSSL_EVP_CIPHER_CTX* evpCtx, + WOLFSSL_HMAC_CTX* hmacCtx, unsigned char* encTicket, int encTicketLen, + const unsigned char* mac, int* outSz) +{ + int ret = 1; + int len = 0; + int totalSz = 0; + unsigned int mdSz = 0; + byte digest[WC_MAX_DIGEST_SIZE]; + + /* HMAC the encrypted data and compare it to the passed in data. */ + if (!wolfSSL_HMAC_Update(hmacCtx, encTicket, encTicketLen)) { + ret = 0; + } + if ((ret == 1) && (!wolfSSL_HMAC_Final(hmacCtx, digest, &mdSz))) { + ret = 0; + } + if ((ret == 1) && (ConstantCompare(mac, digest, (int)mdSz) != 0)) { + ret = 0; + } + /* Decrypt the ticket data in place. */ + if ((ret == 1) && + (!wolfSSL_EVP_CipherUpdate(evpCtx, encTicket, &len, encTicket, + encTicketLen))) { + ret = 0; + } + if (ret == 1) { + totalSz = len; + /* Decrypted data must fit in the buffer. */ + if (totalSz > encTicketLen) { + ret = 0; + } + } + if ((ret == 1) && + (!wolfSSL_EVP_DecryptFinal(evpCtx, &encTicket[len], &len))) { + ret = 0; + } + if (ret == 1) { + /* Total length of decrypted data. */ + totalSz += len; + if (totalSz > encTicketLen) { + ret = 0; + } + } + if (ret == 1) { + *outSz = totalSz; + } + + return ret; +} + +/* Encrypt or decrypt a session ticket using the OpenSSL ticket key callback. + * + * Wraps the application's OpenSSL-style callback that initializes the cipher + * and HMAC. + * + * @param [in] ssl SSL/TLS object. + * @param [in] keyName Key name identifying the key to use. + * @param [in] iv IV to use. + * @param [in, out] mac MAC of the encrypted data. + * @param [in] enc 1 to encrypt the ticket, 0 to decrypt. + * @param [in, out] encTicket Ticket data, encrypted/decrypted in place. + * @param [in] encTicketLen Length of the ticket data in bytes. + * @param [out] encLen Output length of the ticket data. + * @param [in] ctx Ignored. Application specific data. + * @return WOLFSSL_TICKET_RET_OK on success. + * @return WOLFSSL_TICKET_RET_CREATE when a new ticket is required. + * @return WOLFSSL_TICKET_RET_FATAL on error. + */ +static int wolfSSL_TicketKeyCb(WOLFSSL* ssl, + unsigned char keyName[WOLFSSL_TICKET_NAME_SZ], + unsigned char iv[WOLFSSL_TICKET_IV_SZ], + unsigned char mac[WOLFSSL_TICKET_MAC_SZ], + int enc, unsigned char* encTicket, + int encTicketLen, int* encLen, void* ctx) +{ + WC_DECLARE_VAR(evpCtx, WOLFSSL_EVP_CIPHER_CTX, 1, 0); + int ret = WOLFSSL_TICKET_RET_OK; + + (void)ctx; + + WOLFSSL_ENTER("wolfSSL_TicketKeyCb"); + + if ((ssl == NULL) || (ssl->ctx == NULL) || + (ssl->ctx->ticketEncWrapCb == NULL)) { + WOLFSSL_MSG("Bad parameter"); + ret = WOLFSSL_TICKET_RET_FATAL; + } + +#ifdef WOLFSSL_SMALL_STACK + if (ret == WOLFSSL_TICKET_RET_OK) { + evpCtx = (WOLFSSL_EVP_CIPHER_CTX *)XMALLOC(sizeof(*evpCtx), ssl->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (evpCtx == NULL) { + WOLFSSL_MSG("out of memory"); + ret = WOLFSSL_TICKET_RET_FATAL; + } + } +#endif + + if (ret == WOLFSSL_TICKET_RET_OK) { + WOLFSSL_HMAC_CTX hmacCtx; + + /* Initialize the cipher and HMAC. */ + wolfSSL_EVP_CIPHER_CTX_init(evpCtx); + + if (wolfSSL_HMAC_CTX_Init(&hmacCtx) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("wolfSSL_HMAC_CTX_Init error"); + ret = WOLFSSL_TICKET_RET_FATAL; + } + + if (ret == WOLFSSL_TICKET_RET_OK) { + int res; + int totalSz = 0; + + res = ssl->ctx->ticketEncWrapCb(ssl, keyName, iv, evpCtx, &hmacCtx, + enc); + if ((res != TICKET_KEY_CB_RET_OK) && + (res != TICKET_KEY_CB_RET_RENEW)) { + WOLFSSL_MSG("Ticket callback error"); + ret = WOLFSSL_TICKET_RET_FATAL; + } + + if (ret == WOLFSSL_TICKET_RET_OK) { + if (wolfSSL_HMAC_size(&hmacCtx) > WOLFSSL_TICKET_MAC_SZ) { + WOLFSSL_MSG("Ticket cipher MAC size error"); + ret = WOLFSSL_TICKET_RET_FATAL; + } + } + + if (ret == WOLFSSL_TICKET_RET_OK) { + if (enc) { + if (!wolfssl_ticket_key_enc(evpCtx, &hmacCtx, encTicket, + encTicketLen, *encLen, mac, &totalSz)) { + ret = WOLFSSL_TICKET_RET_FATAL; + } + } + else { + if (!wolfssl_ticket_key_dec(evpCtx, &hmacCtx, encTicket, + encTicketLen, mac, &totalSz)) { + ret = WOLFSSL_TICKET_RET_FATAL; + } + } + } + + if (ret == WOLFSSL_TICKET_RET_OK) { + *encLen = totalSz; + + if ((res == TICKET_KEY_CB_RET_RENEW) && + (!IsAtLeastTLSv1_3(ssl->version)) && (!enc)) { + ret = WOLFSSL_TICKET_RET_CREATE; + } + else { + ret = WOLFSSL_TICKET_RET_OK; + } + } + + (void)wc_HmacFree(&hmacCtx.hmac); + } + (void)wolfSSL_EVP_CIPHER_CTX_cleanup(evpCtx); + WC_FREE_VAR_EX(evpCtx, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + } + + return ret; +} + +/* Set the OpenSSL-style session ticket key callback on the context. + * + * Installs a wrapper as the ticket encryption callback. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] cb OpenSSL session ticket key callback. + * @return WOLFSSL_SUCCESS on success. + */ +int wolfSSL_CTX_set_tlsext_ticket_key_cb(WOLFSSL_CTX *ctx, ticketCompatCb cb) +{ + + /* Set the ticket encryption callback to be a wrapper around OpenSSL + * callback. + */ + ctx->ticketEncCb = wolfSSL_TicketKeyCb; + ctx->ticketEncWrapCb = cb; + + return WOLFSSL_SUCCESS; +} + +#endif /* HAVE_SESSION_TICKET */ + +#endif /* OPENSSL_ALL || WOLFSSL_NGINX || WOLFSSL_HAPROXY || + OPENSSL_EXTRA || HAVE_LIGHTY */ + +#if defined(HAVE_SESSION_TICKET) && !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \ + !defined(NO_WOLFSSL_SERVER) +/* Serialize the session ticket encryption keys. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] keys Buffer to hold session ticket keys. + * @param [in] keylen Length of buffer. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ctx is NULL, keys is NULL or keylen is not the + * correct length. + */ +long wolfSSL_CTX_get_tlsext_ticket_keys(WOLFSSL_CTX *ctx, + unsigned char *keys, int keylen) +{ + long ret = WOLFSSL_SUCCESS; + + if ((ctx == NULL) || (keys == NULL)) { + ret = WOLFSSL_FAILURE; + } + else if (keylen != WOLFSSL_TICKET_KEYS_SZ) { + ret = WOLFSSL_FAILURE; + } + else { + /* Serialize as: name | key[0] | key[1] | expiry[0] | expiry[1]. */ + XMEMCPY(keys, ctx->ticketKeyCtx.name, WOLFSSL_TICKET_NAME_SZ); + keys += WOLFSSL_TICKET_NAME_SZ; + XMEMCPY(keys, ctx->ticketKeyCtx.key[0], WOLFSSL_TICKET_KEY_SZ); + keys += WOLFSSL_TICKET_KEY_SZ; + XMEMCPY(keys, ctx->ticketKeyCtx.key[1], WOLFSSL_TICKET_KEY_SZ); + keys += WOLFSSL_TICKET_KEY_SZ; + /* Expiry times are stored big-endian. */ + c32toa(ctx->ticketKeyCtx.expirary[0], keys); + keys += OPAQUE32_LEN; + c32toa(ctx->ticketKeyCtx.expirary[1], keys); + } + + return ret; +} + +/* Deserialize the session ticket encryption keys. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] keys Session ticket keys. + * @param [in] keylen Length of data. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ctx is NULL, keys is NULL or keylen is not the + * correct length. + */ +long wolfSSL_CTX_set_tlsext_ticket_keys(WOLFSSL_CTX *ctx, + const void *keys_vp, int keylen) +{ + const byte* keys = (const byte*)keys_vp; + long ret = WOLFSSL_SUCCESS; + + if ((ctx == NULL) || (keys == NULL)) { + ret = WOLFSSL_FAILURE; + } + else if (keylen != WOLFSSL_TICKET_KEYS_SZ) { + ret = WOLFSSL_FAILURE; + } + else { + /* Parse as: name | key[0] | key[1] | expiry[0] | expiry[1]. */ + XMEMCPY(ctx->ticketKeyCtx.name, keys, WOLFSSL_TICKET_NAME_SZ); + keys += WOLFSSL_TICKET_NAME_SZ; + XMEMCPY(ctx->ticketKeyCtx.key[0], keys, WOLFSSL_TICKET_KEY_SZ); + keys += WOLFSSL_TICKET_KEY_SZ; + XMEMCPY(ctx->ticketKeyCtx.key[1], keys, WOLFSSL_TICKET_KEY_SZ); + keys += WOLFSSL_TICKET_KEY_SZ; + /* Expiry times are stored big-endian. */ + ato32(keys, &ctx->ticketKeyCtx.expirary[0]); + keys += OPAQUE32_LEN; + ato32(keys, &ctx->ticketKeyCtx.expirary[1]); + } + + return ret; +} +#endif + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || \ + defined(WOLFSSL_HAPROXY) || defined(HAVE_LIGHTY) || \ + defined(WOLFSSL_QUIC) +#ifdef HAVE_ALPN +/* Get the ALPN protocol selected for the object. + * + * @param [in] ssl SSL/TLS object. + * @param [out] data Selected protocol data. + * @param [out] len Length of the protocol data in bytes. + */ +void wolfSSL_get0_alpn_selected(const WOLFSSL *ssl, const unsigned char **data, + unsigned int *len) +{ + word16 nameLen = 0; + + if ((ssl != NULL) && (data != NULL) && (len != NULL)) { + TLSX_ALPN_GetRequest(ssl->extensions, (void **)data, &nameLen); + *len = nameLen; + } +} + +/* Determine whether a protocol appears in the client's protocol list. + * + * The client's list is in wire format: each entry is a length byte followed + * by that many protocol-name bytes. + * + * @param [in] proto Protocol name to look for. + * @param [in] protoLen Length of the protocol name in bytes. + * @param [in] clientNames Client's protocol list. + * @param [in] clientLen Length of the client's list in bytes. + * @return 1 when the protocol is in the list. + * @return 0 when the protocol is not in the list. + */ +static int wolfssl_protocol_in_list(const unsigned char* proto, byte protoLen, + const unsigned char* clientNames, unsigned int clientLen) +{ + unsigned int j; + byte lenClient; + int found = 0; + + /* Compare against each of the client's length-prefixed names. */ + for (j = 0; j < clientLen; j += lenClient) { + lenClient = clientNames[j++]; + if ((lenClient == 0) || (j + lenClient > clientLen)) { + break; + } + + if ((protoLen == lenClient) && + (XMEMCMP(proto, clientNames + j, protoLen) == 0)) { + found = 1; + break; + } + } + + return found; +} + +/* Select the next protocol from the peer's list that matches the client's. + * + * On no overlap, the first client protocol is selected. + * + * @param [out] out Selected protocol data. + * @param [out] outLen Length of the selected protocol in bytes. + * @param [in] in Peer's protocol list. + * @param [in] inLen Length of the peer's list in bytes. + * @param [in] clientNames Client's protocol list. + * @param [in] clientLen Length of the client's list in bytes. + * @return WOLFSSL_NPN_NEGOTIATED when a match was found. + * @return WOLFSSL_NPN_NO_OVERLAP when no match was found. + * @return WOLFSSL_NPN_UNSUPPORTED when an argument is NULL. + */ +int wolfSSL_select_next_proto(unsigned char **out, unsigned char *outLen, + const unsigned char *in, unsigned int inLen, + const unsigned char *clientNames, unsigned int clientLen) +{ + unsigned int i; + byte lenIn; + int ret = WOLFSSL_NPN_NO_OVERLAP; + + if ((out == NULL) || (outLen == NULL) || (in == NULL) || + (clientNames == NULL)) { + ret = WOLFSSL_NPN_UNSUPPORTED; + } + else { + /* Walk the peer's list; each entry is a length byte then that many + * protocol-name bytes. */ + for (i = 0; i < inLen; i += lenIn) { + lenIn = in[i++]; + /* Stop on an empty entry or one that runs past the buffer. */ + if ((lenIn == 0) || (i + lenIn > inLen)) { + break; + } + /* Select this peer protocol if the client also offered it. */ + if (wolfssl_protocol_in_list(in + i, lenIn, clientNames, + clientLen)) { + *out = (unsigned char *)(in + i); + *outLen = lenIn; + ret = WOLFSSL_NPN_NEGOTIATED; + break; + } + } + + if (ret != WOLFSSL_NPN_NEGOTIATED) { + /* No overlap: fall back to the client's first protocol. */ + if ((clientLen > 0) && + ((unsigned int)clientNames[0] + 1 <= clientLen)) { + *out = (unsigned char *)clientNames + 1; + *outLen = clientNames[0]; + } + else { + *out = (unsigned char *)clientNames; + *outLen = 0; + } + ret = WOLFSSL_NPN_NO_OVERLAP; + } + } + + return ret; +} + +/* Set the ALPN selection callback on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] cb ALPN selection callback. + * @param [in] arg User argument passed to the callback. + */ +void wolfSSL_set_alpn_select_cb(WOLFSSL *ssl, + int (*cb)(WOLFSSL *ssl, const unsigned char **out, unsigned char *outlen, + const unsigned char *in, unsigned int inlen, void *arg), + void *arg) +{ + if (ssl != NULL) { + ssl->alpnSelect = cb; + ssl->alpnSelectArg = arg; + } +} + +/* Set the ALPN selection callback on the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] cb ALPN selection callback. + * @param [in] arg User argument passed to the callback. + */ +void wolfSSL_CTX_set_alpn_select_cb(WOLFSSL_CTX *ctx, + int (*cb)(WOLFSSL *ssl, const unsigned char **out, unsigned char *outlen, + const unsigned char *in, unsigned int inlen, void *arg), + void *arg) +{ + if (ctx != NULL) { + ctx->alpnSelect = cb; + ctx->alpnSelectArg = arg; + } +} + +/* Set the NPN advertised-protocols callback on the context. + * + * Not implemented - stub for OpenSSL compatibility. + * + * @param [in] s SSL/TLS context object. + * @param [in] cb NPN advertised-protocols callback. + * @param [in] arg User argument passed to the callback. + */ +void wolfSSL_CTX_set_next_protos_advertised_cb(WOLFSSL_CTX *s, + int (*cb)(WOLFSSL *ssl, const unsigned char **out, unsigned int *outlen, + void *arg), void *arg) +{ + (void)s; + (void)cb; + (void)arg; + WOLFSSL_STUB("wolfSSL_CTX_set_next_protos_advertised_cb"); +} + +/* Set the NPN protocol-selection callback on the context. + * + * Not implemented - stub for OpenSSL compatibility. + * + * @param [in] s SSL/TLS context object. + * @param [in] cb NPN protocol-selection callback. + * @param [in] arg User argument passed to the callback. + */ +void wolfSSL_CTX_set_next_proto_select_cb(WOLFSSL_CTX *s, + int (*cb)(WOLFSSL *ssl, unsigned char **out, unsigned char *outlen, + const unsigned char *in, unsigned int inlen, void *arg), + void *arg) +{ + (void)s; + (void)cb; + (void)arg; + WOLFSSL_STUB("wolfSSL_CTX_set_next_proto_select_cb"); +} + +/* Get the NPN protocol negotiated for the object. + * + * Not implemented - stub for OpenSSL compatibility. + * + * @param [in] s SSL/TLS object. + * @param [out] data Negotiated protocol data. + * @param [out] len Length of the protocol data in bytes. + */ +void wolfSSL_get0_next_proto_negotiated(const WOLFSSL *s, + const unsigned char **data, unsigned *len) +{ + (void)s; + (void)data; + (void)len; + WOLFSSL_STUB("wolfSSL_get0_next_proto_negotiated"); +} +#endif /* HAVE_ALPN */ + +#endif /* WOLFSSL_NGINX / WOLFSSL_HAPROXY */ + +#if defined(OPENSSL_EXTRA) || defined(HAVE_CURL) + +/* Determine whether an elliptic curve is disabled for the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] curve_id Curve identifier. + * @return 1 when the curve is disabled or out of range. + * @return 0 when the curve is enabled or is an FFDHE group. + */ +int wolfSSL_curve_is_disabled(const WOLFSSL* ssl, word16 curve_id) +{ + int ret = 0; + + WOLFSSL_ENTER("wolfSSL_curve_is_disabled"); + WOLFSSL_MSG_EX("wolfSSL_curve_is_disabled checking for %d", curve_id); + + /* (curve_id >= WOLFSSL_FFDHE_START) - DH parameters are never disabled. */ + if (curve_id < WOLFSSL_FFDHE_START) { + if (curve_id > WOLFSSL_ECC_MAX_AVAIL) { + WOLFSSL_MSG("Curve id out of supported range"); + /* Disabled if not in valid range. */ + ret = 1; + } + else if (curve_id >= 32) { + /* 0 is for invalid and 1-14 aren't used otherwise. */ + ret = (ssl->disabledCurves & (1U << (curve_id - 32))) != 0; + } + else { + ret = (ssl->disabledCurves & (1U << curve_id)) != 0; + } + } + + WOLFSSL_LEAVE("wolfSSL_curve_is_disabled", ret); + return ret; +} + +#if (defined(HAVE_ECC) || \ + defined(HAVE_CURVE25519) || defined(HAVE_CURVE448)) + +/* Set the supported curves list, by name, on the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] names Colon-separated list of curve names. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ctx or names is NULL or on error. + */ +int wolfSSL_CTX_set1_curves_list(WOLFSSL_CTX* ctx, const char* names) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_set1_curves_list"); + + if ((ctx == NULL) || (names == NULL)) { + WOLFSSL_MSG("ctx or names was NULL"); + ret = WOLFSSL_FAILURE; + } + else { + ret = set_curves_list(NULL, ctx, names, 1); + } + + return ret; +} + +/* Set the supported curves list, by name, on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] names Colon-separated list of curve names. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ssl or names is NULL or on error. + */ +int wolfSSL_set1_curves_list(WOLFSSL* ssl, const char* names) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_set1_curves_list"); + + if ((ssl == NULL) || (names == NULL)) { + WOLFSSL_MSG("ssl or names was NULL"); + ret = WOLFSSL_FAILURE; + } + else { + ret = set_curves_list(ssl, NULL, names, 1); + } + + return ret; +} + +#endif /* HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448 */ +#endif /* OPENSSL_EXTRA || HAVE_CURL */ + +#ifdef OPENSSL_EXTRA + +/* Set the ALPN protocol list, in wire format, on the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] p ALPN protocol list in wire format (length-prefixed). + * @param [in] p_len Length of the protocol list in bytes. + * @return WOLFSSL_SUCCESS (or 0 with WOLFSSL_ERROR_CODE_OPENSSL) on success. + * @return BAD_FUNC_ARG when ctx or p is NULL. + * @return WOLFSSL_FAILURE (or 1 with WOLFSSL_ERROR_CODE_OPENSSL) on error. + */ +int wolfSSL_CTX_set_alpn_protos(WOLFSSL_CTX *ctx, const unsigned char *p, + unsigned int p_len) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_set_alpn_protos"); + + if ((ctx == NULL) || (p == NULL)) { + ret = BAD_FUNC_ARG; + } + else { + if (ctx->alpn_cli_protos != NULL) { + XFREE((void*)ctx->alpn_cli_protos, ctx->heap, DYNAMIC_TYPE_OPENSSL); + } + + ctx->alpn_cli_protos = (const unsigned char*)XMALLOC(p_len, + ctx->heap, DYNAMIC_TYPE_OPENSSL); + if (ctx->alpn_cli_protos == NULL) { +#if defined(WOLFSSL_ERROR_CODE_OPENSSL) + /* 0 on success in OpenSSL, non-0 on failure in OpenSSL + * the function reverses the return value convention. + */ + ret = 1; +#else + ret = WOLFSSL_FAILURE; +#endif + } + else { + XMEMCPY((void*)ctx->alpn_cli_protos, p, p_len); + ctx->alpn_cli_protos_len = p_len; + +#if defined(WOLFSSL_ERROR_CODE_OPENSSL) + /* 0 on success in OpenSSL, non-0 on failure in OpenSSL + * the function reverses the return value convention. + */ + ret = 0; +#else + ret = WOLFSSL_SUCCESS; +#endif + } + } + + return ret; +} + + +#ifdef HAVE_ALPN +#ifndef NO_BIO +/* Convert a wire-format ALPN protocol list into a comma-separated string. + * + * The wire format is a sequence of entries, each a length byte followed by + * that many protocol-name bytes. + * + * @param [in] p ALPN protocol list in wire format. + * @param [in] p_len Length of the protocol list in bytes. + * @param [out] pt Buffer to hold the comma-separated list. Must hold at + * least p_len bytes. + * @param [out] ptLen Length of the comma-separated list written. + * @return 1 on success. + * @return 0 when the wire format is invalid. + */ +static int wolfssl_alpn_protos_to_list(const unsigned char* p, + unsigned int p_len, char* pt, unsigned int* ptLen) +{ + unsigned int idx = 0; + unsigned int ptIdx = 0; + unsigned int sz; + int ret = 1; + + /* Convert into a comma separated list. */ + while (idx < p_len - 1) { + unsigned int i; + + sz = p[idx++]; + if (idx + sz > p_len) { + WOLFSSL_MSG("Bad list format"); + ret = 0; + break; + } + if (sz > 0) { + for (i = 0; i < sz; i++) { + pt[ptIdx++] = p[idx++]; + } + if (idx < p_len - 1) { + pt[ptIdx++] = ','; + } + } + } + + if (ret == 1) { + *ptLen = ptIdx; + } + + return ret; +} + +/* Set the ALPN protocol list, in wire format, on the object. + * + * The list is length-prefixed, e.g. + * unsigned char p[] = { 8, 'h','t','t','p','/','1','.','1' }; + * + * @param [in] ssl SSL/TLS object. + * @param [in] p ALPN protocol list in wire format (length-prefixed). + * @param [in] p_len Length of the protocol list in bytes. + * @return WOLFSSL_SUCCESS (or 0 with WOLFSSL_ERROR_CODE_OPENSSL) on success. + * @return WOLFSSL_FAILURE (or 1 with WOLFSSL_ERROR_CODE_OPENSSL) on error. + */ +int wolfSSL_set_alpn_protos(WOLFSSL* ssl, + const unsigned char* p, unsigned int p_len) +{ + char* pt = NULL; + unsigned int ptIdx = 0; + /* RFC 7301: a server that does not select any of the client's offered + * protocols MUST send no_application_protocol. Match that contract on + * the OpenSSL-compat surface rather than silently continuing. */ + int alpn_opt = WOLFSSL_ALPN_FAILED_ON_MISMATCH; +#if defined(WOLFSSL_ERROR_CODE_OPENSSL) + int ret = 1; +#else + int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); +#endif + + WOLFSSL_ENTER("wolfSSL_set_alpn_protos"); + + if ((ssl != NULL) && (p_len > 1) && (p != NULL)) { + /* Replacing leading number with trailing ',' and adding '\0'. */ + pt = (char*)XMALLOC(p_len + 1, ssl->heap, DYNAMIC_TYPE_OPENSSL); + if (pt != NULL) { + if (wolfssl_alpn_protos_to_list(p, p_len, pt, &ptIdx)) { + pt[ptIdx++] = '\0'; + + /* Clear out all currently set ALPN extensions. */ + TLSX_Remove(&ssl->extensions, TLSX_APPLICATION_LAYER_PROTOCOL, + ssl->heap); + + if (wolfSSL_UseALPN(ssl, pt, ptIdx, (byte)alpn_opt) == + WOLFSSL_SUCCESS) { + #if defined(WOLFSSL_ERROR_CODE_OPENSSL) + ret = 0; + #else + ret = WOLFSSL_SUCCESS; + #endif + } + } + + XFREE(pt, ssl->heap, DYNAMIC_TYPE_OPENSSL); + } + } + + return ret; +} +#endif /* !NO_BIO */ +#endif /* HAVE_ALPN */ + +#endif /* OPENSSL_EXTRA */ + +#endif /* !WOLFCRYPT_ONLY */ + +#endif /* !WOLFSSL_SSL_API_EXT_INCLUDED */ diff --git a/src/ssl_api_pk.c b/src/ssl_api_pk.c index 1b42ac1493..118004be52 100644 --- a/src/ssl_api_pk.c +++ b/src/ssl_api_pk.c @@ -137,7 +137,7 @@ static int check_cert_key_dev(word32 keyOID, byte* privKey, word32 privSz, } } #else - /* devId was set, don't check, for now */ + /* devId was set, so don't check for now. */ /* TODO: Add callback for private key check? */ (void) pubKey; (void) pubSz; @@ -242,7 +242,7 @@ static int check_cert_key(const DerBuffer* cert, const DerBuffer* key, } } else { - /* fall through if unavailable */ + /* Fall through if unavailable. */ ret = CRYPTOCB_UNAVAILABLE; } @@ -270,7 +270,7 @@ static int check_cert_key(const DerBuffer* cert, const DerBuffer* key, } #ifdef WOLF_PRIVATE_KEY_ID if (altDevId != INVALID_DEVID) { - /* We have to decode the public key first */ + /* We have to decode the public key first. */ /* Default to max pub key size. */ word32 pubKeyLen = MAX_PUBLIC_KEY_SZ; byte* decodedPubKey = (byte*)XMALLOC(pubKeyLen, heap, @@ -280,7 +280,7 @@ static int check_cert_key(const DerBuffer* cert, const DerBuffer* key, } if (ret == WOLFSSL_SUCCESS) { if ((der->sapkiOID == RSAk) || (der->sapkiOID == ECDSAk)) { - /* Simply copy the data */ + /* Simply copy the data. */ XMEMCPY(decodedPubKey, der->sapkiDer, der->sapkiLen); pubKeyLen = der->sapkiLen; ret = 0; @@ -307,7 +307,7 @@ static int check_cert_key(const DerBuffer* cert, const DerBuffer* key, } } else { - /* fall through if unavailable */ + /* Fall through if unavailable. */ ret = CRYPTOCB_UNAVAILABLE; } @@ -1606,4 +1606,1240 @@ void* wolfSSL_GetDhAgreeCtx(WOLFSSL* ssl) } #endif /* HAVE_PK_CALLBACKS && !NO_DH */ +#ifndef WOLFCRYPT_ONLY + +#ifndef NO_TLS +#ifdef HAVE_ECC +/* Set the minimum ECC key size, in bits, allowed with the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] keySz Minimum ECC key size in bits. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx is NULL or keySz is negative. + * @return CRYPTO_POLICY_FORBIDDEN when below the active crypto-policy minimum. + */ +int wolfSSL_CTX_SetMinEccKey_Sz(WOLFSSL_CTX* ctx, short keySz) +{ + int ret = WOLFSSL_SUCCESS; + + WOLFSSL_ENTER("wolfSSL_CTX_SetMinEccKey_Sz"); + + if ((ctx == NULL) || (keySz < 0)) { + WOLFSSL_MSG("Key size must be positive value or ctx was null"); + ret = BAD_FUNC_ARG; + } + else { + short keySzBytes = (keySz + 7) / 8; + + #if defined(WOLFSSL_SYS_CRYPTO_POLICY) + if (crypto_policy.enabled && (ctx->minEccKeySz > keySzBytes)) { + ret = CRYPTO_POLICY_FORBIDDEN; + } + else + #endif /* WOLFSSL_SYS_CRYPTO_POLICY */ + { + ctx->minEccKeySz = keySzBytes; + #ifndef NO_CERTS + ctx->cm->minEccKeySz = keySzBytes; + #endif + } + } + + return ret; +} + + +/* Set the minimum ECC key size, in bits, allowed with the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] keySz Minimum ECC key size in bits. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL or keySz is negative. + * @return CRYPTO_POLICY_FORBIDDEN when below the active crypto-policy minimum. + */ +int wolfSSL_SetMinEccKey_Sz(WOLFSSL* ssl, short keySz) +{ + int ret = WOLFSSL_SUCCESS; + + WOLFSSL_ENTER("wolfSSL_SetMinEccKey_Sz"); + + if ((ssl == NULL) || (keySz < 0)) { + WOLFSSL_MSG("Key size must be positive value or ctx was null"); + ret = BAD_FUNC_ARG; + } + else { + short keySzBytes = (keySz + 7) / 8; + + #if defined(WOLFSSL_SYS_CRYPTO_POLICY) + if (crypto_policy.enabled && (ssl->options.minEccKeySz > keySzBytes)) { + ret = CRYPTO_POLICY_FORBIDDEN; + } + else + #endif /* WOLFSSL_SYS_CRYPTO_POLICY */ + { + ssl->options.minEccKeySz = keySzBytes; + } + } + + return ret; +} + +#endif /* HAVE_ECC */ + +#ifndef NO_RSA +/* Set the minimum RSA key size, in bits, allowed with the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] keySz Minimum RSA key size in bits. Must be a multiple of 8. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx is NULL or keySz is negative or not a + * multiple of 8. + * @return CRYPTO_POLICY_FORBIDDEN when below the active crypto-policy minimum. + */ +int wolfSSL_CTX_SetMinRsaKey_Sz(WOLFSSL_CTX* ctx, short keySz) +{ + int ret = WOLFSSL_SUCCESS; + + if ((ctx == NULL) || (keySz < 0) || ((keySz % 8) != 0)) { + WOLFSSL_MSG("Key size must be divisible by 8 or ctx was null"); + ret = BAD_FUNC_ARG; + } +#if defined(WOLFSSL_SYS_CRYPTO_POLICY) + else if (crypto_policy.enabled && (ctx->minRsaKeySz > (keySz / 8))) { + ret = CRYPTO_POLICY_FORBIDDEN; + } +#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ + else { + ctx->minRsaKeySz = keySz / 8; + ctx->cm->minRsaKeySz = keySz / 8; + } + + return ret; +} + + +/* Set the minimum RSA key size, in bits, allowed with the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] keySz Minimum RSA key size in bits. Must be a multiple of 8. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL or keySz is negative or not a + * multiple of 8. + * @return CRYPTO_POLICY_FORBIDDEN when below the active crypto-policy minimum. + */ +int wolfSSL_SetMinRsaKey_Sz(WOLFSSL* ssl, short keySz) +{ + int ret = WOLFSSL_SUCCESS; + + if ((ssl == NULL) || (keySz < 0) || ((keySz % 8) != 0)) { + WOLFSSL_MSG("Key size must be divisible by 8 or ssl was null"); + ret = BAD_FUNC_ARG; + } +#if defined(WOLFSSL_SYS_CRYPTO_POLICY) + else if (crypto_policy.enabled && (ssl->options.minRsaKeySz > (keySz / 8))) { + ret = CRYPTO_POLICY_FORBIDDEN; + } +#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ + else { + ssl->options.minRsaKeySz = keySz / 8; + } + + return ret; +} +#endif /* !NO_RSA */ + +#ifndef NO_DH + +#if !defined(WOLFSSL_OLD_PRIME_CHECK) && !defined(HAVE_FIPS) && \ + !defined(HAVE_SELFTEST) +/* Enable or disable the DH key prime test on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] enable 1 to enable the prime test and 0 to disable it. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL. + */ +int wolfSSL_SetEnableDhKeyTest(WOLFSSL* ssl, int enable) +{ + int ret = WOLFSSL_SUCCESS; + + WOLFSSL_ENTER("wolfSSL_SetEnableDhKeyTest"); + + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + else { + /* Store the flag normalized to a boolean. */ + ssl->options.dhDoKeyTest = (enable != 0); + } + + WOLFSSL_LEAVE("wolfSSL_SetEnableDhKeyTest", ret); + return ret; +} +#endif + +/* Set the minimum DH key size, in bits, allowed with the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] keySz_bits Minimum DH key size in bits. No more than 16000 and + * a multiple of 8. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx is NULL or keySz_bits is invalid. + * @return CRYPTO_POLICY_FORBIDDEN when below the active crypto-policy minimum. + */ +int wolfSSL_CTX_SetMinDhKey_Sz(WOLFSSL_CTX* ctx, word16 keySz_bits) +{ + int ret = WOLFSSL_SUCCESS; + + if ((ctx == NULL) || (keySz_bits > 16000) || ((keySz_bits % 8) != 0)) { + ret = BAD_FUNC_ARG; + } +#if defined(WOLFSSL_SYS_CRYPTO_POLICY) + else if (crypto_policy.enabled && (ctx->minDhKeySz > (keySz_bits / 8))) { + ret = CRYPTO_POLICY_FORBIDDEN; + } +#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ + else { + ctx->minDhKeySz = keySz_bits / 8; + } + + return ret; +} + + +/* Set the minimum DH key size, in bits, allowed with the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] keySz_bits Minimum DH key size in bits. No more than 16000 and + * a multiple of 8. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL or keySz_bits is invalid. + * @return CRYPTO_POLICY_FORBIDDEN when below the active crypto-policy minimum. + */ +int wolfSSL_SetMinDhKey_Sz(WOLFSSL* ssl, word16 keySz_bits) +{ + int ret = WOLFSSL_SUCCESS; + + if ((ssl == NULL) || (keySz_bits > 16000) || ((keySz_bits % 8) != 0)) { + ret = BAD_FUNC_ARG; + } +#if defined(WOLFSSL_SYS_CRYPTO_POLICY) + else if (crypto_policy.enabled && + (ssl->options.minDhKeySz > (keySz_bits / 8))) { + ret = CRYPTO_POLICY_FORBIDDEN; + } +#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ + else { + ssl->options.minDhKeySz = keySz_bits / 8; + } + + return ret; +} + + +/* Set the maximum DH key size, in bits, allowed with the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] keySz_bits Maximum DH key size in bits. No more than 16000 and + * a multiple of 8. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx is NULL or keySz_bits is invalid. + */ +int wolfSSL_CTX_SetMaxDhKey_Sz(WOLFSSL_CTX* ctx, word16 keySz_bits) +{ + int ret = WOLFSSL_SUCCESS; + + if ((ctx == NULL) || (keySz_bits > 16000) || (keySz_bits % 8 != 0)) { + ret = BAD_FUNC_ARG; + } +#if defined(WOLFSSL_SYS_CRYPTO_POLICY) + else if (crypto_policy.enabled && (ctx->minDhKeySz > (keySz_bits / 8))) { + ret = CRYPTO_POLICY_FORBIDDEN; + } +#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ + else { + ctx->maxDhKeySz = keySz_bits / 8; + } + + return ret; +} + + +/* Set the maximum DH key size, in bits, allowed with the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] keySz_bits Maximum DH key size in bits. No more than 16000 and + * a multiple of 8. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ssl is NULL or keySz_bits is invalid. + */ +int wolfSSL_SetMaxDhKey_Sz(WOLFSSL* ssl, word16 keySz_bits) +{ + int ret = WOLFSSL_SUCCESS; + + if ((ssl == NULL) || (keySz_bits > 16000) || ((keySz_bits % 8) != 0)) { + ret = BAD_FUNC_ARG; + } +#if defined(WOLFSSL_SYS_CRYPTO_POLICY) + else if (crypto_policy.enabled && + (ssl->options.minDhKeySz > (keySz_bits / 8))) { + ret = CRYPTO_POLICY_FORBIDDEN; + } +#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ + else { + ssl->options.maxDhKeySz = keySz_bits / 8; + } + + return ret; +} + + +/* Get the size, in bits, of the DH key being used by the object. + * + * @param [in] ssl SSL/TLS object. + * @return DH key size in bits on success. + * @return BAD_FUNC_ARG when ssl is NULL. + */ +int wolfSSL_GetDhKey_Sz(WOLFSSL* ssl) +{ + int ret; + + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + else { + /* Key size is stored in bytes; report it in bits. */ + ret = ssl->options.dhKeySz * 8; + } + + return ret; +} + +#endif /* !NO_DH */ + +#endif /* !NO_TLS */ + +#ifdef OPENSSL_EXTRA +#ifndef NO_WOLFSSL_STUB +/* Get the private key of the object. + * + * Not implemented - stub for OpenSSL compatibility. + * + * @param [in] ssl SSL/TLS object. + * @return NULL always. + */ +WOLFSSL_EVP_PKEY *wolfSSL_get_privatekey(const WOLFSSL *ssl) +{ + (void)ssl; + WOLFSSL_STUB("SSL_get_privatekey"); + return NULL; +} +#endif + +#endif /* OPENSSL_EXTRA */ + +#ifdef OPENSSL_EXTRA +/* Map a wolfSSL MAC/hash algorithm identifier to a NID. + * + * @param [in] hashAlgo MAC/hash algorithm identifier. + * @param [out] nid NID corresponding to the hash algorithm. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when the algorithm is not recognized. + */ +static int HashToNid(byte hashAlgo, int* nid) +{ + int ret = WOLFSSL_SUCCESS; + + /* Cast for compiler to check everything is implemented. */ + switch ((enum wc_MACAlgorithm)hashAlgo) { + case no_mac: + case rmd_mac: + *nid = WC_NID_undef; + break; + case md5_mac: + *nid = WC_NID_md5; + break; + case sha_mac: + *nid = WC_NID_sha1; + break; + case sha224_mac: + *nid = WC_NID_sha224; + break; + case sha256_mac: + *nid = WC_NID_sha256; + break; + case sha384_mac: + *nid = WC_NID_sha384; + break; + case sha512_mac: + *nid = WC_NID_sha512; + break; + case blake2b_mac: + *nid = WC_NID_blake2b512; + break; + case sm3_mac: + *nid = WC_NID_sm3; + break; + default: + ret = WOLFSSL_FAILURE; + break; + } + + return ret; +} + +/* Map a wolfSSL signature algorithm identifier to a NID. + * + * @param [in] sa Signature algorithm identifier. + * @param [out] nid NID corresponding to the signature algorithm. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when the algorithm is not recognized or not + * compiled in. + */ +static int SaToNid(byte sa, int* nid) +{ + int ret = WOLFSSL_SUCCESS; + + /* Cast for compiler to check everything is implemented. */ + switch ((enum SignatureAlgorithm)sa) { + case anonymous_sa_algo: + *nid = WC_NID_undef; + break; + case rsa_sa_algo: + *nid = WC_NID_rsaEncryption; + break; + case dsa_sa_algo: + *nid = WC_NID_dsa; + break; + case ecc_dsa_sa_algo: + case ecc_brainpool_sa_algo: + *nid = WC_NID_X9_62_id_ecPublicKey; + break; + case rsa_pss_sa_algo: + *nid = WC_NID_rsassaPss; + break; + case ed25519_sa_algo: +#ifdef HAVE_ED25519 + *nid = WC_NID_ED25519; +#else + ret = WOLFSSL_FAILURE; +#endif + break; + case rsa_pss_pss_algo: + *nid = WC_NID_rsassaPss; + break; + case ed448_sa_algo: +#ifdef HAVE_ED448 + *nid = WC_NID_ED448; +#else + ret = WOLFSSL_FAILURE; +#endif + break; + case falcon_level1_sa_algo: + *nid = CTC_FALCON_LEVEL1; + break; + case falcon_level5_sa_algo: + *nid = CTC_FALCON_LEVEL5; + break; + case mldsa_44_sa_algo: + *nid = CTC_ML_DSA_44; + break; + case mldsa_65_sa_algo: + *nid = CTC_ML_DSA_65; + break; + case mldsa_87_sa_algo: + *nid = CTC_ML_DSA_87; + break; + case sm2_sa_algo: + *nid = WC_NID_sm2; + break; + case invalid_sa_algo: + case any_sa_algo: + default: + ret = WOLFSSL_FAILURE; + break; + } + return ret; +} + +/* Get the NID of the hash algorithm used for signing by this side. + * + * @param [in] ssl SSL/TLS object. + * @param [out] nid NID of the hash algorithm. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ssl or nid is NULL or the algorithm is not + * recognized. + */ +int wolfSSL_get_signature_nid(WOLFSSL *ssl, int* nid) +{ + int ret; + + WOLFSSL_MSG("wolfSSL_get_signature_nid"); + + if ((ssl == NULL) || (nid == NULL)) { + WOLFSSL_MSG("Bad function arguments"); + ret = WOLFSSL_FAILURE; + } + else { + /* Map this side's signing hash algorithm to its NID. */ + ret = HashToNid(ssl->options.hashAlgo, nid); + } + + return ret; +} + +/* Get the NID of the signature algorithm used for signing by this side. + * + * @param [in] ssl SSL/TLS object. + * @param [out] nid NID of the signature algorithm. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ssl or nid is NULL or the algorithm is not + * recognized. + */ +int wolfSSL_get_signature_type_nid(const WOLFSSL* ssl, int* nid) +{ + int ret; + + WOLFSSL_MSG("wolfSSL_get_signature_type_nid"); + + if ((ssl == NULL) || (nid == NULL)) { + WOLFSSL_MSG("Bad function arguments"); + ret = WOLFSSL_FAILURE; + } + else { + /* Map this side's signature algorithm to its NID. */ + ret = SaToNid(ssl->options.sigAlgo, nid); + } + + return ret; +} + +/* Get the NID of the hash algorithm used for signing by the peer. + * + * @param [in] ssl SSL/TLS object. + * @param [out] nid NID of the hash algorithm. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ssl or nid is NULL or the algorithm is not + * recognized. + */ +int wolfSSL_get_peer_signature_nid(WOLFSSL* ssl, int* nid) +{ + int ret; + + WOLFSSL_MSG("wolfSSL_get_peer_signature_nid"); + + if ((ssl == NULL) || (nid == NULL)) { + WOLFSSL_MSG("Bad function arguments"); + ret = WOLFSSL_FAILURE; + } + else { + /* Map the peer's signing hash algorithm to its NID. */ + ret = HashToNid(ssl->options.peerHashAlgo, nid); + } + + return ret; +} + +/* Get the NID of the signature algorithm used for signing by the peer. + * + * @param [in] ssl SSL/TLS object. + * @param [out] nid NID of the signature algorithm. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE when ssl or nid is NULL or the algorithm is not + * recognized. + */ +int wolfSSL_get_peer_signature_type_nid(const WOLFSSL* ssl, int* nid) +{ + int ret; + + WOLFSSL_MSG("wolfSSL_get_peer_signature_type_nid"); + + if ((ssl == NULL) || (nid == NULL)) { + WOLFSSL_MSG("Bad function arguments"); + ret = WOLFSSL_FAILURE; + } + else { + /* Map the peer's signature algorithm to its NID. */ + ret = SaToNid(ssl->options.peerSigAlgo, nid); + } + + return ret; +} + +#endif /* OPENSSL_EXTRA */ + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) \ + || defined(OPENSSL_EXTRA) || defined(HAVE_LIGHTY) +#ifdef HAVE_ECC +/* Set the temporary ECDH key's curve on the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] ecdh EC key whose curve is to be used. + * @return WOLFSSL_SUCCESS on success. + * @return BAD_FUNC_ARG when ctx or ecdh is NULL. + */ +int wolfSSL_SSL_CTX_set_tmp_ecdh(WOLFSSL_CTX *ctx, WOLFSSL_EC_KEY *ecdh) +{ + int ret = WOLFSSL_SUCCESS; + + WOLFSSL_ENTER("wolfSSL_SSL_CTX_set_tmp_ecdh"); + + if ((ctx == NULL) || (ecdh == NULL)) { + ret = BAD_FUNC_ARG; + } + else { + /* Only the curve of the EC key is used for ephemeral ECDH. */ + ctx->ecdhCurveOID = (word32)ecdh->group->curve_oid; + } + + return ret; +} +#endif + +#endif + +#ifdef WOLFSSL_STATIC_EPHEMERAL +/* Decode the loaded static ephemeral key into the given key object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] keyAlgo Key algorithm: WC_PK_TYPE_DH, WC_PK_TYPE_ECDH, + * WC_PK_TYPE_CURVE25519 or WC_PK_TYPE_CURVE448. + * @param [out] keyPtr Key object to decode into. + * @return 0 on success. + * @return BAD_FUNC_ARG when ssl, its context or keyPtr is NULL. + * @return BUFFER_E when no static key has been set. + * @return NOT_COMPILED_IN when the key algorithm is not supported. + * @return Other negative value on error. + */ +int wolfSSL_StaticEphemeralKeyLoad(WOLFSSL* ssl, int keyAlgo, void* keyPtr) +{ + int ret = 0; + word32 idx = 0; + DerBuffer* der = NULL; + + if ((ssl == NULL) || (ssl->ctx == NULL) || (keyPtr == NULL)) { + ret = BAD_FUNC_ARG; + } +#ifndef SINGLE_THREADED + else if (!ssl->ctx->staticKELockInit) { + ret = BUFFER_E; /* no keys set */ + } + else { + ret = wc_LockMutex(&ssl->ctx->staticKELock); + } +#endif + + if (ret == 0) { + ret = BUFFER_E; /* set default error */ + switch (keyAlgo) { + #ifndef NO_DH + case WC_PK_TYPE_DH: + if (ssl != NULL) + der = ssl->staticKE.dhKey; + if (der == NULL) + der = ssl->ctx->staticKE.dhKey; + if (der != NULL) { + DhKey* key = (DhKey*)keyPtr; + WOLFSSL_MSG("Using static DH key"); + ret = wc_DhKeyDecode(der->buffer, &idx, key, der->length); + } + break; + #endif + #ifdef HAVE_ECC + case WC_PK_TYPE_ECDH: + if (ssl != NULL) + der = ssl->staticKE.ecKey; + if (der == NULL) + der = ssl->ctx->staticKE.ecKey; + if (der != NULL) { + ecc_key* key = (ecc_key*)keyPtr; + WOLFSSL_MSG("Using static ECDH key"); + ret = wc_EccPrivateKeyDecode(der->buffer, &idx, key, + der->length); + } + break; + #endif + #ifdef HAVE_CURVE25519 + case WC_PK_TYPE_CURVE25519: + if (ssl != NULL) + der = ssl->staticKE.x25519Key; + if (der == NULL) + der = ssl->ctx->staticKE.x25519Key; + if (der != NULL) { + curve25519_key* key = (curve25519_key*)keyPtr; + WOLFSSL_MSG("Using static X25519 key"); + #ifdef WOLFSSL_CURVE25519_BLINDING + ret = wc_curve25519_set_rng(key, ssl->rng); + if (ret == 0) + #endif + { + ret = wc_Curve25519PrivateKeyDecode(der->buffer, &idx, + key, der->length); + } + } + break; + #endif + #ifdef HAVE_CURVE448 + case WC_PK_TYPE_CURVE448: + if (ssl != NULL) + der = ssl->staticKE.x448Key; + if (der == NULL) + der = ssl->ctx->staticKE.x448Key; + if (der != NULL) { + curve448_key* key = (curve448_key*)keyPtr; + WOLFSSL_MSG("Using static X448 key"); + ret = wc_Curve448PrivateKeyDecode(der->buffer, &idx, key, + der->length); + } + break; + #endif + default: + /* Not supported. */ + ret = NOT_COMPILED_IN; + break; + } + + #ifndef SINGLE_THREADED + wc_UnLockMutex(&ssl->ctx->staticKELock); + #endif + } + + return ret; +} + +/* Detect the algorithm of an ASN.1 DER encoded private key. + * + * Attempts to decode the key as each supported algorithm in turn, setting + * keyAlgo to the first type that decodes successfully. Detection is only + * performed when keyAlgo is WC_PK_TYPE_NONE on entry. + * + * @param [in] keyBuf ASN.1 DER encoded private key data. + * @param [in] keySz Length of key data in bytes. + * @param [in] heap Heap hint for dynamic memory allocation. + * @param [in, out] keyAlgo Key algorithm. Detected when WC_PK_TYPE_NONE on + * entry; left unchanged otherwise. + * @return 0 on success. + * @return MEMORY_E when dynamic memory allocation fails. + * @return Other negative value on key initialization error. + */ +static int DetectStaticEphemeralKeyType(const byte* keyBuf, unsigned int keySz, + void* heap, int* keyAlgo) +{ + int ret = 0; + +#ifdef HAVE_ECC + { + word32 idx = 0; + WC_DECLARE_VAR(eccKey, ecc_key, 1, heap); + WC_ALLOC_VAR_EX(eccKey, ecc_key, 1, heap, DYNAMIC_TYPE_ECC, + ret = MEMORY_E); + if (ret == 0) { + ret = wc_ecc_init_ex(eccKey, heap, INVALID_DEVID); + } + if (ret == 0) { + ret = wc_EccPrivateKeyDecode(keyBuf, &idx, eccKey, keySz); + if (ret == 0) { + *keyAlgo = WC_PK_TYPE_ECDH; + } + wc_ecc_free(eccKey); + ret = 0; /* clear error to enable key-type detect cascade */ + } + WC_FREE_VAR_EX(eccKey, heap, DYNAMIC_TYPE_ECC); + } +#endif +#if !defined(NO_DH) && defined(WOLFSSL_DH_EXTRA) + if (*keyAlgo == WC_PK_TYPE_NONE) { + word32 idx = 0; + WC_DECLARE_VAR(dhKey, DhKey, 1, heap); + WC_ALLOC_VAR_EX(dhKey, DhKey, 1, heap, DYNAMIC_TYPE_DH, + ret = MEMORY_E); + if (ret == 0) { + ret = wc_InitDhKey_ex(dhKey, heap, INVALID_DEVID); + } + if (ret == 0) { + ret = wc_DhKeyDecode(keyBuf, &idx, dhKey, keySz); + if (ret == 0) { + *keyAlgo = WC_PK_TYPE_DH; + } + wc_FreeDhKey(dhKey); + ret = 0; /* clear error to enable key-type detect cascade */ + } + WC_FREE_VAR_EX(dhKey, heap, DYNAMIC_TYPE_DH); + } +#endif +#ifdef HAVE_CURVE25519 + if (*keyAlgo == WC_PK_TYPE_NONE) { + word32 idx = 0; + WC_DECLARE_VAR(x25519Key, curve25519_key, 1, heap); + WC_ALLOC_VAR_EX(x25519Key, curve25519_key, 1, heap, + DYNAMIC_TYPE_CURVE25519, ret = MEMORY_E); + if (ret == 0) { + ret = wc_curve25519_init_ex(x25519Key, heap, INVALID_DEVID); + } + if (ret == 0) { + ret = wc_Curve25519PrivateKeyDecode(keyBuf, &idx, + x25519Key, keySz); + if (ret == 0) { + *keyAlgo = WC_PK_TYPE_CURVE25519; + } + wc_curve25519_free(x25519Key); + ret = 0; /* clear error to enable key-type detect cascade */ + } + WC_FREE_VAR_EX(x25519Key, heap, DYNAMIC_TYPE_CURVE25519); + } +#endif +#ifdef HAVE_CURVE448 + if (*keyAlgo == WC_PK_TYPE_NONE) { + word32 idx = 0; + WC_DECLARE_VAR(x448Key, curve448_key, 1, heap); + WC_ALLOC_VAR_EX(x448Key, curve448_key, 1, heap, + DYNAMIC_TYPE_CURVE448, ret = MEMORY_E); + if (ret == 0) { + ret = wc_curve448_init(x448Key); + } + if (ret == 0) { + ret = wc_Curve448PrivateKeyDecode(keyBuf, &idx, x448Key, + keySz); + if (ret == 0) { + *keyAlgo = WC_PK_TYPE_CURVE448; + } + wc_curve448_free(x448Key); + ret = 0; /* clear error to enable key-type detect cascade */ + } + WC_FREE_VAR_EX(x448Key, heap, DYNAMIC_TYPE_CURVE448); + } +#endif + + (void)keyBuf; + (void)keySz; + (void)heap; + (void)keyAlgo; + + return ret; +} + +/* Load and store a static ephemeral key into the static key exchange info. + * + * An empty key (key NULL) frees the stored buffer. A file is loaded when key + * is a path and keySz is 0. The key algorithm is auto-detected when keyAlgo + * is WC_PK_TYPE_NONE. + * + * @param [in] ctx SSL/TLS context object (used for the mutex). + * @param [in, out] staticKE Static key exchange info to store the key in. + * @param [in] keyAlgo Key algorithm or WC_PK_TYPE_NONE to detect. + * @param [in] key Key data or file path, may be NULL to free. + * @param [in] keySz Length of key data in bytes, 0 to load a file. + * @param [in] format WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. + * @param [in] heap Heap hint for dynamic memory allocation. + * @return 0 on success. + * @return BAD_FUNC_ARG when staticKE is NULL or key is NULL with keySz > 0. + * @return NOT_COMPILED_IN when the key algorithm is not supported. + * @return Other negative value on error. + */ +static int SetStaticEphemeralKey(WOLFSSL_CTX* ctx, + StaticKeyExchangeInfo_t* staticKE, int keyAlgo, const char* key, + unsigned int keySz, int format, void* heap) +{ + int ret = 0; + DerBuffer* der = NULL; + byte* keyBuf = NULL; +#ifndef NO_FILESYSTEM + const char* keyFile = NULL; +#endif + + WOLFSSL_ENTER("SetStaticEphemeralKey"); + + /* Allow an empty key to free the buffer. */ + if ((staticKE == NULL) || ((key == NULL) && (keySz > 0))) { + ret = BAD_FUNC_ARG; + } + + /* If just freeing the key then skip loading. */ + if ((ret == 0) && (key != NULL)) { + #ifndef NO_FILESYSTEM + /* Load the file from the filesystem. */ + if ((key != NULL) && (keySz == 0)) { + size_t keyBufSz = 0; + keyFile = (const char*)key; + ret = wc_FileLoad(keyFile, &keyBuf, &keyBufSz, heap); + if (ret == 0) { + keySz = (unsigned int)keyBufSz; + } + } + else + #endif + { + /* Use as the key buffer directly. */ + keyBuf = (byte*)key; + } + + if (ret != 0) { + /* File load failed - nothing more to process. */ + } + else if (format == WOLFSSL_FILETYPE_PEM) { + #ifdef WOLFSSL_PEM_TO_DER + int keyFormat = 0; + ret = PemToDer(keyBuf, keySz, PRIVATEKEY_TYPE, &der, + heap, NULL, &keyFormat); + /* Auto-detect the key type. */ + if ((ret == 0) && (keyAlgo == WC_PK_TYPE_NONE)) { + if (keyFormat == ECDSAk) { + keyAlgo = WC_PK_TYPE_ECDH; + } + else if (keyFormat == X25519k) { + keyAlgo = WC_PK_TYPE_CURVE25519; + } + else { + keyAlgo = WC_PK_TYPE_DH; + } + } + #else + ret = NOT_COMPILED_IN; + #endif + } + else { + /* Detect the key type if not specified. */ + if (keyAlgo == WC_PK_TYPE_NONE) { + ret = DetectStaticEphemeralKeyType(keyBuf, keySz, heap, + &keyAlgo); + } + if ((ret == 0) && (keyAlgo != WC_PK_TYPE_NONE)) { + ret = AllocDer(&der, keySz, PRIVATEKEY_TYPE, heap); + if (ret == 0) { + XMEMCPY(der->buffer, keyBuf, keySz); + } + } + } + } + +#ifndef NO_FILESYSTEM + /* Done with the keyFile buffer. */ + if ((keyFile != NULL) && (keyBuf != NULL)) { + ForceZero(keyBuf, keySz); + XFREE(keyBuf, heap, DYNAMIC_TYPE_TMP_BUFFER); + } +#endif + +#ifndef SINGLE_THREADED + if ((ret == 0) && (!ctx->staticKELockInit)) { + ret = wc_InitMutex(&ctx->staticKELock); + if (ret == 0) { + ctx->staticKELockInit = 1; + } + } +#endif + if ((ret == 0) + #ifndef SINGLE_THREADED + && ((ret = wc_LockMutex(&ctx->staticKELock)) == 0) + #endif + ) { + switch (keyAlgo) { + #ifndef NO_DH + case WC_PK_TYPE_DH: + FreeDer(&staticKE->dhKey); + staticKE->dhKey = der; + der = NULL; + break; + #endif + #ifdef HAVE_ECC + case WC_PK_TYPE_ECDH: + FreeDer(&staticKE->ecKey); + staticKE->ecKey = der; + der = NULL; + break; + #endif + #ifdef HAVE_CURVE25519 + case WC_PK_TYPE_CURVE25519: + FreeDer(&staticKE->x25519Key); + staticKE->x25519Key = der; + der = NULL; + break; + #endif + #ifdef HAVE_CURVE448 + case WC_PK_TYPE_CURVE448: + FreeDer(&staticKE->x448Key); + staticKE->x448Key = der; + der = NULL; + break; + #endif + default: + /* Not supported. */ + ret = NOT_COMPILED_IN; + break; + } + + #ifndef SINGLE_THREADED + wc_UnLockMutex(&ctx->staticKELock); + #endif + } + + if (ret != 0) { + FreeDer(&der); + } + + (void)ctx; /* not used for single threaded */ + + WOLFSSL_LEAVE("SetStaticEphemeralKey", ret); + + return ret; +} + +/* Set the static ephemeral key on the context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] keyAlgo Key algorithm or WC_PK_TYPE_NONE to detect. + * @param [in] key Key data or file path. + * @param [in] keySz Length of key data in bytes, 0 to load a file. + * @param [in] format WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. + * @return 0 on success. + * @return BAD_FUNC_ARG when ctx is NULL. + * @return Other negative value on error. + */ +int wolfSSL_CTX_set_ephemeral_key(WOLFSSL_CTX* ctx, int keyAlgo, + const char* key, unsigned int keySz, int format) +{ + int ret; + + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + else { + /* Store into the context's static ephemeral key store. */ + ret = SetStaticEphemeralKey(ctx, &ctx->staticKE, keyAlgo, key, keySz, + format, ctx->heap); + } + + return ret; +} +/* Set the static ephemeral key on the object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] keyAlgo Key algorithm or WC_PK_TYPE_NONE to detect. + * @param [in] key Key data or file path. + * @param [in] keySz Length of key data in bytes, 0 to load a file. + * @param [in] format WOLFSSL_FILETYPE_PEM or WOLFSSL_FILETYPE_ASN1. + * @return 0 on success. + * @return BAD_FUNC_ARG when ssl or its context is NULL. + * @return Other negative value on error. + */ +int wolfSSL_set_ephemeral_key(WOLFSSL* ssl, int keyAlgo, const char* key, + unsigned int keySz, int format) +{ + int ret; + + if ((ssl == NULL) || (ssl->ctx == NULL)) { + ret = BAD_FUNC_ARG; + } + else { + /* Store into the object's own static ephemeral key store. */ + ret = SetStaticEphemeralKey(ssl->ctx, &ssl->staticKE, keyAlgo, key, + keySz, format, ssl->heap); + } + + return ret; +} + +/* Get the loaded static ephemeral key as ASN.1 DER data. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] ssl SSL/TLS object, may be NULL to use only the context. + * @param [in] keyAlgo Key algorithm to retrieve. + * @param [out] key Pointer to the key's DER data. May be NULL. + * @param [out] keySz Length of the key's DER data. May be NULL. + * @return 0 on success. + * @return NOT_COMPILED_IN when the key algorithm is not supported. + * @return Other negative value on error. + */ +static int GetStaticEphemeralKey(WOLFSSL_CTX* ctx, WOLFSSL* ssl, int keyAlgo, + const unsigned char** key, unsigned int* keySz) +{ + int ret = 0; + DerBuffer* der = NULL; + + if (key != NULL) { + *key = NULL; + } + if (keySz != NULL) { + *keySz = 0; + } + +#ifndef SINGLE_THREADED + if (ctx->staticKELockInit) { + ret = wc_LockMutex(&ctx->staticKELock); + } +#endif + + if (ret == 0) { + switch (keyAlgo) { + #ifndef NO_DH + case WC_PK_TYPE_DH: + if (ssl != NULL) { + der = ssl->staticKE.dhKey; + } + if (der == NULL) { + der = ctx->staticKE.dhKey; + } + break; + #endif + #ifdef HAVE_ECC + case WC_PK_TYPE_ECDH: + if (ssl != NULL) { + der = ssl->staticKE.ecKey; + } + if (der == NULL) { + der = ctx->staticKE.ecKey; + } + break; + #endif + #ifdef HAVE_CURVE25519 + case WC_PK_TYPE_CURVE25519: + if (ssl != NULL) { + der = ssl->staticKE.x25519Key; + } + if (der == NULL) { + der = ctx->staticKE.x25519Key; + } + break; + #endif + #ifdef HAVE_CURVE448 + case WC_PK_TYPE_CURVE448: + if (ssl != NULL) { + der = ssl->staticKE.x448Key; + } + if (der == NULL) { + der = ctx->staticKE.x448Key; + } + break; + #endif + default: + /* Not supported. */ + ret = NOT_COMPILED_IN; + break; + } + + if (der != NULL) { + if (key != NULL) { + *key = der->buffer; + } + if (keySz != NULL) { + *keySz = der->length; + } + } + + #ifndef SINGLE_THREADED + wc_UnLockMutex(&ctx->staticKELock); + #endif + } + + return ret; +} + +/* Get the static ephemeral key set on the context as ASN.1 DER data. + * + * The returned data can be converted to PEM using wc_DerToPem(). + * + * @param [in] ctx SSL/TLS context object. + * @param [in] keyAlgo Key algorithm to retrieve. + * @param [out] key Pointer to the key's DER data. May be NULL. + * @param [out] keySz Length of the key's DER data. May be NULL. + * @return 0 on success. + * @return BAD_FUNC_ARG when ctx is NULL. + * @return Other negative value on error. + */ +int wolfSSL_CTX_get_ephemeral_key(WOLFSSL_CTX* ctx, int keyAlgo, + const unsigned char** key, unsigned int* keySz) +{ + int ret; + + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + else { + /* No object given, so look the key up on the context only. */ + ret = GetStaticEphemeralKey(ctx, NULL, keyAlgo, key, keySz); + } + + return ret; +} +/* Get the static ephemeral key in use by the object as ASN.1 DER data. + * + * @param [in] ssl SSL/TLS object. + * @param [in] keyAlgo Key algorithm to retrieve. + * @param [out] key Pointer to the key's DER data. May be NULL. + * @param [out] keySz Length of the key's DER data. May be NULL. + * @return 0 on success. + * @return BAD_FUNC_ARG when ssl or its context is NULL. + * @return Other negative value on error. + */ +int wolfSSL_get_ephemeral_key(WOLFSSL* ssl, int keyAlgo, + const unsigned char** key, unsigned int* keySz) +{ + int ret; + + if ((ssl == NULL) || (ssl->ctx == NULL)) { + ret = BAD_FUNC_ARG; + } + else { + /* Prefer the object's key, falling back to the context's. */ + ret = GetStaticEphemeralKey(ssl->ctx, ssl, keyAlgo, key, keySz); + } + + return ret; +} + +#endif /* WOLFSSL_STATIC_EPHEMERAL */ + + +#ifdef OPENSSL_EXTRA +/* Enable or disable automatic ECDH curve selection on the object. + * + * Provided for compatibility with SSL_set_ecdh_auto(). Automatic selection is + * always enabled in wolfSSL so this is a stub. + * + * @param [in] ssl SSL/TLS object. + * @param [in] onoff Ignored. + * @return WOLFSSL_SUCCESS always. + */ +int wolfSSL_set_ecdh_auto(WOLFSSL* ssl, int onoff) +{ + (void)ssl; + (void)onoff; + return WOLFSSL_SUCCESS; +} +/* Enable or disable automatic ECDH curve selection on the context. + * + * Provided for compatibility with SSL_CTX_set_ecdh_auto(). Automatic selection + * is always enabled in wolfSSL so this is a stub. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] onoff Ignored. + * @return WOLFSSL_SUCCESS always. + */ +int wolfSSL_CTX_set_ecdh_auto(WOLFSSL_CTX* ctx, int onoff) +{ + (void)ctx; + (void)onoff; + return WOLFSSL_SUCCESS; +} + +/* Enable or disable automatic DH parameter selection on the context. + * + * Provided for compatibility with SSL_CTX_set_dh_auto(). Automatic selection + * is always enabled in wolfSSL so this is a stub. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] onoff Ignored. + * @return WOLFSSL_SUCCESS always. + */ +int wolfSSL_CTX_set_dh_auto(WOLFSSL_CTX* ctx, int onoff) +{ + (void)ctx; + (void)onoff; + return WOLFSSL_SUCCESS; +} + +#endif /* OPENSSL_EXTRA */ + +#endif /* !WOLFCRYPT_ONLY */ + #endif /* !WOLFSSL_SSL_API_PK_INCLUDED */ diff --git a/src/ssl_asn1.c b/src/ssl_asn1.c index 8dd158ef19..2b7c25f01b 100644 --- a/src/ssl_asn1.c +++ b/src/ssl_asn1.c @@ -913,7 +913,7 @@ WOLFSSL_ASN1_BIT_STRING* wolfSSL_d2i_ASN1_BIT_STRING( WOLFSSL_ENTER("wolfSSL_d2i_ASN1_BIT_STRING"); - if (src == NULL || *src == NULL || len == 0) + if (src == NULL || *src == NULL || len <= 0) return NULL; if (GetASNTag(*src, &idx, &tag, (word32)len) < 0) @@ -2984,7 +2984,7 @@ static WOLFSSL_ASN1_STRING* d2i_ASN1_STRING(WOLFSSL_ASN1_STRING** out, WOLFSSL_ENTER("d2i_ASN1_STRING"); - if (src == NULL || *src == NULL || len == 0) + if (src == NULL || *src == NULL || len <= 0) return NULL; if (GetASNTag(*src, &idx, &tag, (word32)len) < 0) @@ -3159,6 +3159,11 @@ int wolfSSL_ASN1_STRING_set(WOLFSSL_ASN1_STRING* asn1, const void* data, int sz) } if (ret == 1) { + /* Cast to size_t BEFORE adding 1 to prevent signed overflow + * when sz == INT_MAX. By this point sz >= 0 (negative sz is + * handled above as OpenSSL -1/strlen compat). */ + size_t allocSz = (size_t)sz + 1; + /* Dispose of any existing dynamic data. */ if (asn1->isDynamic) { XFREE(asn1->data, NULL, DYNAMIC_TYPE_OPENSSL); @@ -3166,9 +3171,9 @@ int wolfSSL_ASN1_STRING_set(WOLFSSL_ASN1_STRING* asn1, const void* data, int sz) } /* Check string will fit - including NUL. */ - if (sz + 1 > CTC_NAME_SIZE) { + if (allocSz > CTC_NAME_SIZE) { /* Allocate new buffer. */ - asn1->data = (char*)XMALLOC((size_t)(sz + 1), NULL, + asn1->data = (char*)XMALLOC(allocSz, NULL, DYNAMIC_TYPE_OPENSSL); if (asn1->data == NULL) { ret = 0; @@ -3760,8 +3765,6 @@ int wolfSSL_ASN1_GENERALIZEDTIME_print(WOLFSSL_BIO* bio, * ASN1_TIME APIs ******************************************************************************/ -#ifndef NO_ASN_TIME - #ifdef OPENSSL_EXTRA /* Allocate a new ASN.1 TIME object. * @@ -3811,6 +3814,7 @@ WOLFSSL_ASN1_TIME *wolfSSL_ASN1_TIME_set(WOLFSSL_ASN1_TIME *a, time_t t) } #endif /* !NO_WOLFSSL_STUB */ +#ifndef NO_ASN_TIME /* Convert time to Unix time (GMT). * * @param [in] sec Second in minute. 0-59. @@ -4005,6 +4009,7 @@ WOLFSSL_ASN1_TIME* wolfSSL_ASN1_TIME_adj(WOLFSSL_ASN1_TIME* a, time_t t, return ret; } #endif /* !USER_TIME && !TIME_OVERRIDES */ +#endif /* !NO_ASN_TIME */ /* Get the length of the ASN.1 TIME data. * @@ -4048,6 +4053,7 @@ unsigned char* wolfSSL_ASN1_TIME_get_data(const WOLFSSL_ASN1_TIME *t) return data; } +#ifndef NO_ASN_TIME /* Check format of string in ASN.1 TIME object. * * @param [in] a ASN.1 TIME object. @@ -4069,6 +4075,7 @@ int wolfSSL_ASN1_TIME_check(const WOLFSSL_ASN1_TIME* a) return ret; } +#endif /* !NO_ASN_TIME */ /* Set the time as a string into ASN.1 TIME object. * @@ -4112,6 +4119,7 @@ int wolfSSL_ASN1_TIME_set_string(WOLFSSL_ASN1_TIME *t, const char *str) return ret; } +#ifndef NO_ASN_TIME int wolfSSL_ASN1_TIME_set_string_X509(WOLFSSL_ASN1_TIME *t, const char *str) { int ret = WOLFSSL_SUCCESS; @@ -4126,6 +4134,7 @@ int wolfSSL_ASN1_TIME_set_string_X509(WOLFSSL_ASN1_TIME *t, const char *str) ret = wolfSSL_ASN1_TIME_check(t); return ret; } +#endif /* !NO_ASN_TIME */ /* Convert ASN.1 TIME object to ASN.1 GENERALIZED TIME object. * @@ -4199,7 +4208,7 @@ WOLFSSL_ASN1_TIME* wolfSSL_ASN1_TIME_to_generalizedtime(WOLFSSL_ASN1_TIME *t, return ret; } -#if !defined(USER_TIME) && !defined(TIME_OVERRIDES) +#if !defined(NO_ASN_TIME) && !defined(USER_TIME) && !defined(TIME_OVERRIDES) WOLFSSL_ASN1_TIME* wolfSSL_ASN1_UTCTIME_set(WOLFSSL_ASN1_TIME *s, time_t t) { WOLFSSL_ASN1_TIME* ret = s; @@ -4228,7 +4237,8 @@ WOLFSSL_ASN1_TIME* wolfSSL_ASN1_UTCTIME_set(WOLFSSL_ASN1_TIME *s, time_t t) #endif /* !USER_TIME && !TIME_OVERRIDES */ #endif /* OPENSSL_EXTRA */ -#if defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(OPENSSL_EXTRA) +#if !defined(NO_ASN_TIME) && \ + (defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(OPENSSL_EXTRA)) /* Get string from ASN.1 TIME object. * * Not an OpenSSL compatibility API. @@ -4607,9 +4617,9 @@ int wolfSSL_ASN1_TIME_print(WOLFSSL_BIO* bio, const WOLFSSL_ASN1_TIME* asnTime) } #endif /* !NO_BIO */ -#endif /* WOLFSSL_MYSQL_COMPATIBLE || OPENSSL_EXTRA */ +#endif /* !NO_ASN_TIME && (WOLFSSL_MYSQL_COMPATIBLE || OPENSSL_EXTRA) */ -#ifdef OPENSSL_EXTRA +#if !defined(NO_ASN_TIME) && defined(OPENSSL_EXTRA) #ifndef NO_BIO /* Print the ASN.1 UTC TIME object as a string to BIO. @@ -4647,9 +4657,7 @@ int wolfSSL_ASN1_UTCTIME_print(WOLFSSL_BIO* bio, const WOLFSSL_ASN1_UTCTIME* a) } #endif /* !NO_BIO */ -#endif /* OPENSSL_EXTRA */ - -#endif /* !NO_ASN_TIME */ +#endif /* !NO_ASN_TIME && OPENSSL_EXTRA */ /******************************************************************************* * ASN1_TYPE APIs diff --git a/src/ssl_crypto.c b/src/ssl_crypto.c index 3393f25fef..92ae36e582 100644 --- a/src/ssl_crypto.c +++ b/src/ssl_crypto.c @@ -611,7 +611,8 @@ int wolfSSL_SHA512_Final(byte* output, WOLFSSL_SHA512_CTX* sha512) #if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || \ (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION > 2))) && \ - !defined(WOLFSSL_KCAPI_HASH) /* doesn't support direct transform */ + !defined(WOLFSSL_KCAPI_HASH) /* doesn't support direct transform */ && \ + !defined(WOLF_CRYPTO_CB_ONLY_SHA512) /* no wc_Sha512Transform in CB-only */ /* Apply SHA-512 transformation to the data. * * @param [in, out] sha512 SHA512 context object. @@ -687,7 +688,8 @@ int wolfSSL_SHA512_224_Final(byte* output, WOLFSSL_SHA512_224_CTX* sha512) } #if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || \ - (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION > 2))) + (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION > 2))) && \ + !defined(WOLF_CRYPTO_CB_ONLY_SHA512) /* no wc_Sha512_224Transform in CB-only */ /* Apply SHA-512-224 transformation to the data. * * @param [in, out] sha512 SHA512 context object. @@ -765,7 +767,8 @@ int wolfSSL_SHA512_256_Final(byte* output, WOLFSSL_SHA512_256_CTX* sha512) } #if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || \ - (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION > 2))) + (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION > 2))) && \ + !defined(WOLF_CRYPTO_CB_ONLY_SHA512) /* no wc_Sha512_256Transform in CB-only */ /* Apply SHA-512-256 transformation to the data. * * @param [in, out] sha512 SHA512 context object. diff --git a/src/ssl_load.c b/src/ssl_load.c index b52eadf62c..5e88452556 100644 --- a/src/ssl_load.c +++ b/src/ssl_load.c @@ -2430,6 +2430,10 @@ int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, long sz, if ((ret == 0) && (type == CHAIN_CERT_TYPE)) { ret = BAD_FUNC_ARG; } + /* Reject negative size - would wrap to huge word32. */ + if ((ret == 0) && (sz < 0)) { + ret = BAD_FUNC_ARG; + } #ifdef WOLFSSL_SMALL_STACK if (ret == 0) { diff --git a/src/ssl_sess.c b/src/ssl_sess.c index 647851ac17..cfc5eb4813 100644 --- a/src/ssl_sess.c +++ b/src/ssl_sess.c @@ -2715,6 +2715,16 @@ int wolfSSL_i2d_SSL_SESSION(WOLFSSL_SESSION* sess, unsigned char** p) #ifdef HAVE_SESSION_TICKET /* ticket len | ticket */ size += OPAQUE16_LEN + sess->ticketLen; +#if !defined(NO_WOLFSSL_SERVER) && !defined(NO_TLS) +#ifdef HAVE_SNI + /* sniHash */ + size += TICKET_BINDING_HASH_SZ; +#endif +#ifdef HAVE_ALPN + /* alpnHash */ + size += TICKET_BINDING_HASH_SZ; +#endif +#endif /* !NO_WOLFSSL_SERVER && !NO_TLS */ #endif if (p != NULL) { @@ -2800,6 +2810,16 @@ int wolfSSL_i2d_SSL_SESSION(WOLFSSL_SESSION* sess, unsigned char** p) c16toa(sess->ticketLen, data + idx); idx += OPAQUE16_LEN; XMEMCPY(data + idx, sess->ticket, sess->ticketLen); idx += sess->ticketLen; +#if !defined(NO_WOLFSSL_SERVER) && !defined(NO_TLS) +#ifdef HAVE_SNI + XMEMCPY(data + idx, sess->sniHash, TICKET_BINDING_HASH_SZ); + idx += TICKET_BINDING_HASH_SZ; +#endif +#ifdef HAVE_ALPN + XMEMCPY(data + idx, sess->alpnHash, TICKET_BINDING_HASH_SZ); + idx += TICKET_BINDING_HASH_SZ; +#endif +#endif /* !NO_WOLFSSL_SERVER && !NO_TLS */ #endif } #endif @@ -3086,6 +3106,26 @@ WOLFSSL_SESSION* wolfSSL_d2i_SSL_SESSION(WOLFSSL_SESSION** sess, goto end; } XMEMCPY(s->ticket, data + idx, s->ticketLen); idx += s->ticketLen; +#if !defined(NO_WOLFSSL_SERVER) && !defined(NO_TLS) +#ifdef HAVE_SNI + /* sniHash - SNI binding for stateful resumption (RFC 6066 section 3) */ + if (i - idx < TICKET_BINDING_HASH_SZ) { + ret = BUFFER_ERROR; + goto end; + } + XMEMCPY(s->sniHash, data + idx, TICKET_BINDING_HASH_SZ); + idx += TICKET_BINDING_HASH_SZ; +#endif +#ifdef HAVE_ALPN + /* alpnHash - ALPN binding for stateful resumption */ + if (i - idx < TICKET_BINDING_HASH_SZ) { + ret = BUFFER_ERROR; + goto end; + } + XMEMCPY(s->alpnHash, data + idx, TICKET_BINDING_HASH_SZ); + idx += TICKET_BINDING_HASH_SZ; +#endif +#endif /* !NO_WOLFSSL_SERVER && !NO_TLS */ #endif (void)idx; @@ -3664,6 +3704,16 @@ void SetupSession(WOLFSSL* ssl) session->sessionCtxSz = ssl->sessionCtxSz; } #endif +#if defined(HAVE_SESSION_TICKET) && \ + !defined(NO_WOLFSSL_SERVER) && !defined(NO_TLS) + /* Bind the current SNI/ALPN to the session to verify on later resumption */ +#ifdef HAVE_SNI + (void)TicketSniHash(ssl, session->sniHash); +#endif +#ifdef HAVE_ALPN + (void)TicketAlpnHash(ssl, session->alpnHash); +#endif +#endif /* HAVE_SESSION_TICKET && !NO_WOLFSSL_SERVER && !NO_TLS */ session->timeout = ssl->timeout; #ifndef NO_ASN_TIME session->bornOn = LowResTimer(); diff --git a/src/tls.c b/src/tls.c index 53d2da7314..da848cedca 100644 --- a/src/tls.c +++ b/src/tls.c @@ -391,15 +391,17 @@ ProtocolVersion MakeTLSv1_3(void) * ctx SSL/TLS context object. * groups Array of groups. * count Number of groups in array. - * returns BAD_FUNC_ARG when ctx or groups is NULL, not using TLS v1.3 or - * count is greater than WOLFSSL_MAX_GROUP_COUNT and WOLFSSL_SUCCESS on success. + * returns BAD_FUNC_ARG when ctx or groups is NULL, not using TLS v1.3, count is + * not positive or count is greater than WOLFSSL_MAX_GROUP_COUNT and + * WOLFSSL_SUCCESS on success. */ int wolfSSL_CTX_set_groups(WOLFSSL_CTX* ctx, int* groups, int count) { int ret, i; WOLFSSL_ENTER("wolfSSL_CTX_set_groups"); - if (ctx == NULL || groups == NULL || count > WOLFSSL_MAX_GROUP_COUNT) + if (ctx == NULL || groups == NULL || count <= 0 || + count > WOLFSSL_MAX_GROUP_COUNT) return BAD_FUNC_ARG; if (!IsTLS_ex(ctx->method->version)) return BAD_FUNC_ARG; @@ -436,15 +438,17 @@ int wolfSSL_CTX_set_groups(WOLFSSL_CTX* ctx, int* groups, int count) * ssl SSL/TLS object. * groups Array of groups. * count Number of groups in array. - * returns BAD_FUNC_ARG when ssl or groups is NULL, not using TLS v1.3 or - * count is greater than WOLFSSL_MAX_GROUP_COUNT and WOLFSSL_SUCCESS on success. + * returns BAD_FUNC_ARG when ssl or groups is NULL, not using TLS v1.3, count is + * not positive or count is greater than WOLFSSL_MAX_GROUP_COUNT and + * WOLFSSL_SUCCESS on success. */ int wolfSSL_set_groups(WOLFSSL* ssl, int* groups, int count) { int ret, i; WOLFSSL_ENTER("wolfSSL_set_groups"); - if (ssl == NULL || groups == NULL || count > WOLFSSL_MAX_GROUP_COUNT) + if (ssl == NULL || groups == NULL || count <= 0 || + count > WOLFSSL_MAX_GROUP_COUNT) return BAD_FUNC_ARG; if (!IsTLS_ex(ssl->version)) return BAD_FUNC_ARG; @@ -2026,6 +2030,7 @@ static int TLSX_ALPN_ParseAndSet(WOLFSSL *ssl, const byte *input, word16 length, word16 size = 0, offset = 0, wlen; int r = WC_NO_ERR_TRACE(BUFFER_ERROR); const byte *s; + word16 entryCount = 0; if (OPAQUE16_LEN > length) return BUFFER_ERROR; @@ -2042,6 +2047,15 @@ static int TLSX_ALPN_ParseAndSet(WOLFSSL *ssl, const byte *input, word16 length, wlen = *s++; if (wlen == 0 || (s + wlen - input) > length) return BUFFER_ERROR; + entryCount++; + } + + /* RFC 7301 Section 3.1: the server's ProtocolNameList in its ALPN + * response MUST contain exactly one ProtocolName. */ + if (!isRequest && entryCount != 1) { + SendAlert(ssl, alert_fatal, decode_error); + WOLFSSL_ERROR_VERBOSE(BUFFER_ERROR); + return BUFFER_ERROR; } if (isRequest) { @@ -2065,6 +2079,15 @@ static int TLSX_ALPN_ParseAndSet(WOLFSSL *ssl, const byte *input, word16 length, byte sel_len = 0; TLSX *extension = NULL; + /* RFC 7301 Section 3.1: a ServerHello ALPN extension MUST contain + * exactly one protocol name. The first name's length byte plus its + * payload must therefore span the whole list. */ + if ((word16)(input[offset] + OPAQUE8_LEN) != size) { + SendAlert(ssl, alert_fatal, illegal_parameter); + WOLFSSL_ERROR_VERBOSE(BUFFER_ERROR); + return BUFFER_ERROR; + } + r = ALPN_find_match(ssl, &extension, &sel, &sel_len, input + offset, size); if (r != 0) return r; @@ -3257,9 +3280,27 @@ static int TLSX_MFL_Parse(WOLFSSL* ssl, const byte* input, word16 length, #ifdef WOLFSSL_OLD_UNSUPPORTED_EXTENSION (void) isRequest; #else - if (!isRequest) + if (!isRequest) { + TLSX* extension; + if (TLSX_CheckUnsupportedExtension(ssl, TLSX_MAX_FRAGMENT_LENGTH)) return TLSX_HandleUnsupportedExtension(ssl); + + /* RFC 6066 Section 4: the server's response value must match the + * value the client requested. The request may have been configured on + * the WOLFSSL object or inherited from the WOLFSSL_CTX. */ + extension = TLSX_Find(ssl->extensions, TLSX_MAX_FRAGMENT_LENGTH); + if (extension == NULL) { + extension = TLSX_Find(ssl->ctx->extensions, + TLSX_MAX_FRAGMENT_LENGTH); + } + if (extension == NULL || extension->data == NULL || + ((byte*)extension->data)[0] != *input) { + SendAlert(ssl, alert_fatal, illegal_parameter); + WOLFSSL_ERROR_VERBOSE(UNKNOWN_MAX_FRAG_LEN_E); + return UNKNOWN_MAX_FRAG_LEN_E; + } + } #endif switch (*input) { @@ -4590,16 +4631,72 @@ int TLSX_UseCertificateStatusRequestV2(TLSX** extensions, byte status_type, #endif /* HAVE_CERTIFICATE_STATUS_REQUEST_V2 */ +/* ML-KEM client support requires generating a key pair (encapsulation key) and + * decapsulating the server's ciphertext. */ +#if defined(WOLFSSL_HAVE_MLKEM) && !defined(WOLFSSL_MLKEM_NO_MAKE_KEY) && \ + !defined(WOLFSSL_MLKEM_NO_DECAPSULATE) + #define WOLFSSL_HAVE_MLKEM_CLIENT_SUPPORT +#endif +/* ML-KEM server support requires encapsulating to the client's key. */ +#if defined(WOLFSSL_HAVE_MLKEM) && !defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) + #define WOLFSSL_HAVE_MLKEM_SERVER_SUPPORT +#endif + #if defined(HAVE_SUPPORTED_CURVES) || \ (defined(WOLFSSL_TLS13) && defined(HAVE_SUPPORTED_CURVES)) +#ifdef WOLFSSL_HAVE_MLKEM +/* Returns whether ML-KEM groups are supported for the given side. + * + * ML-KEM groups require side specific crypto support. The client needs to + * generate a key and decapsulate, while the server needs to encapsulate. + * + * side The side of the connection the check is for: WOLFSSL_CLIENT_END, + * WOLFSSL_SERVER_END or WOLFSSL_NEITHER_END when the side is not known. + * returns 1 when supported or 0 otherwise. + */ +static int TLSX_IsMlKemGroupSupported(int side) +{ + if (side == WOLFSSL_CLIENT_END) { + #ifdef WOLFSSL_HAVE_MLKEM_CLIENT_SUPPORT + return 1; + #else + return 0; + #endif + } + else if (side == WOLFSSL_SERVER_END) { + #ifdef WOLFSSL_HAVE_MLKEM_SERVER_SUPPORT + return 1; + #else + return 0; + #endif + } + else { + /* Side not known - supported if either side has the crypto support. */ + #if defined(WOLFSSL_HAVE_MLKEM_CLIENT_SUPPORT) || \ + defined(WOLFSSL_HAVE_MLKEM_SERVER_SUPPORT) + return 1; + #else + return 0; + #endif + } +} +#endif /* WOLFSSL_HAVE_MLKEM */ + /* Returns whether this group is supported. * * namedGroup The named group to check. + * side The side of the connection the check is for: WOLFSSL_CLIENT_END, + * WOLFSSL_SERVER_END or WOLFSSL_NEITHER_END when the side is not + * known. Used to determine whether the local side has the crypto + * support required to use the group (e.g. ML-KEM requires + * decapsulation on the client and encapsulation on the server). * returns 1 when supported or 0 otherwise. */ -int TLSX_IsGroupSupported(int namedGroup) +int TLSX_IsGroupSupported(int namedGroup, int side) { + (void)side; + switch (namedGroup) { #ifdef HAVE_FFDHE_2048 case WOLFSSL_FFDHE_2048: @@ -4711,14 +4808,14 @@ int TLSX_IsGroupSupported(int namedGroup) #ifndef WOLFSSL_NO_ML_KEM_512 #ifndef WOLFSSL_TLS_NO_MLKEM_STANDALONE case WOLFSSL_ML_KEM_512: - break; + return TLSX_IsMlKemGroupSupported(side); #endif /* !WOLFSSL_TLS_NO_MLKEM_STANDALONE */ #ifdef WOLFSSL_EXTRA_PQC_HYBRIDS case WOLFSSL_SECP256R1MLKEM512: #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256 case WOLFSSL_X25519MLKEM512: #endif /* HAVE_CURVE25519 */ - break; + return TLSX_IsMlKemGroupSupported(side); #endif /* WOLFSSL_EXTRA_PQC_HYBRIDS */ #endif /* WOLFSSL_NO_ML_KEM_512 */ #ifndef WOLFSSL_NO_ML_KEM_768 @@ -4737,7 +4834,7 @@ int TLSX_IsGroupSupported(int namedGroup) case WOLFSSL_X448MLKEM768: #endif /* HAVE_CURVE448 */ #endif /* WOLFSSL_EXTRA_PQC_HYBRIDS */ - break; + return TLSX_IsMlKemGroupSupported(side); #endif /* WOLFSSL_NO_ML_KEM_768 */ #ifndef WOLFSSL_NO_ML_KEM_1024 #ifndef WOLFSSL_TLS_NO_MLKEM_STANDALONE @@ -4749,14 +4846,14 @@ int TLSX_IsGroupSupported(int namedGroup) #ifdef WOLFSSL_EXTRA_PQC_HYBRIDS case WOLFSSL_SECP521R1MLKEM1024: #endif /* WOLFSSL_EXTRA_PQC_HYBRIDS */ - break; + return TLSX_IsMlKemGroupSupported(side); #endif #if defined(WOLFSSL_ML_KEM_USE_OLD_IDS) && \ defined (WOLFSSL_EXTRA_PQC_HYBRIDS) case WOLFSSL_P256_ML_KEM_512_OLD: case WOLFSSL_P384_ML_KEM_768_OLD: case WOLFSSL_P521_ML_KEM_1024_OLD: - break; + return TLSX_IsMlKemGroupSupported(side); #endif /* WOLFSSL_ML_KEM_USE_OLD_IDS && WOLFSSL_EXTRA_PQC_HYBRIDS */ #endif /* WOLFSSL_NO_ML_KEM */ #ifdef WOLFSSL_MLKEM_KYBER @@ -4782,7 +4879,7 @@ int TLSX_IsGroupSupported(int namedGroup) case WOLFSSL_KYBER_LEVEL5: case WOLFSSL_P521_KYBER_LEVEL5: #endif - break; + return TLSX_IsMlKemGroupSupported(side); #endif #endif /* WOLFSSL_HAVE_MLKEM */ default: @@ -5141,8 +5238,13 @@ int TLSX_SupportedCurve_Parse(const WOLFSSL* ssl, const byte* input, if (length != OPAQUE16_LEN + offset) return BUFFER_ERROR; offset = OPAQUE16_LEN; - if (offset == length) - return 0; + if (offset == length) { + /* An empty named group list is malformed (named_group_list<2..2^16-1>, + * RFC 8422 / RFC 8446). BUFFER_ERROR yields a decode_error alert (see + * TranslateErrorToAlert()). Accepting it would also make an explicit + * empty extension look absent and impose no group restriction. */ + return BUFFER_ERROR; + } extension = TLSX_Find(*extensions, TLSX_SUPPORTED_GROUPS); if (extension == NULL) { @@ -5150,7 +5252,8 @@ int TLSX_SupportedCurve_Parse(const WOLFSSL* ssl, const byte* input, for (; offset < length; offset += OPAQUE16_LEN) { ato16(input + offset, &name); - ret = TLSX_UseSupportedCurve(extensions, name, ssl->heap); + ret = TLSX_UseSupportedCurve(extensions, name, ssl->heap, + ssl->options.side); /* If it is BAD_FUNC_ARG then it is a group we do not support, but * that is fine. */ if (ret != WOLFSSL_SUCCESS && @@ -5158,6 +5261,14 @@ int TLSX_SupportedCurve_Parse(const WOLFSSL* ssl, const byte* input, break; ret = 0; } + /* All advertised groups are unsupported, so no node was added above. + * Record an empty node so suite selection still sees the restriction + * (e.g. ECC/ECDHE must not be chosen) instead of treating the + * extension as absent. */ + if (ret == 0 && isRequest && + TLSX_Find(*extensions, TLSX_SUPPORTED_GROUPS) == NULL) { + ret = TLSX_Push(extensions, TLSX_SUPPORTED_GROUPS, NULL, ssl->heap); + } } else { /* Find the intersection with what the user has set */ @@ -5539,7 +5650,8 @@ int TLSX_SupportedCurve_Preferred(WOLFSSL* ssl, int checkSupported) curve = (SupportedCurve*)extension->data; while (curve != NULL) { - if (!checkSupported || TLSX_IsGroupSupported(curve->name)) + if (!checkSupported || + TLSX_IsGroupSupported(curve->name, ssl->options.side)) return curve->name; curve = curve->next; } @@ -5561,6 +5673,26 @@ static int TLSX_PointFormat_Parse(WOLFSSL* ssl, const byte* input, return BUFFER_ERROR; if (isRequest) { + #if defined(HAVE_TLS_EXTENSIONS) && defined(HAVE_SUPPORTED_CURVES) + /* RFC 8422 Section 5.1.2: a client that sends the ec_point_formats + * extension MUST include the uncompressed (0) format. Record whether + * it is missing so DoClientHello() can abort with an illegal_parameter + * alert if the client also advertised ECC named groups. The decision + * is deferred to after all extensions are parsed so it does not depend + * on the relative order of the supported_groups and ec_point_formats + * extensions in the ClientHello. */ + word16 i; + int found = 0; + + for (i = 0; i < input[0]; i++) { + if (input[ENUM_LEN + i] == WOLFSSL_EC_PF_UNCOMPRESSED) { + found = 1; + break; + } + } + ssl->options.peerNoUncompPF = (found == 0); + #endif + /* adding uncompressed point format to response */ ret = TLSX_UsePointFormat(&ssl->extensions, WOLFSSL_EC_PF_UNCOMPRESSED, ssl->heap); @@ -5942,7 +6074,10 @@ int TLSX_SupportedCurve_Copy(TLSX* src, TLSX** dst, void* heap) SupportedCurve* curve; for (curve = (SupportedCurve*)extension->data; curve != NULL; curve = curve->next) { - ret = TLSX_UseSupportedCurve(dst, curve->name, heap); + /* Copying an already validated list - don't drop a group based on + * the side, so accept when either side has the crypto support. */ + ret = TLSX_UseSupportedCurve(dst, curve->name, heap, + WOLFSSL_NEITHER_END); if (ret != WOLFSSL_SUCCESS) return MEMORY_E; } @@ -5951,7 +6086,7 @@ int TLSX_SupportedCurve_Copy(TLSX* src, TLSX** dst, void* heap) return 0; } -int TLSX_UseSupportedCurve(TLSX** extensions, word16 name, void* heap) +int TLSX_UseSupportedCurve(TLSX** extensions, word16 name, void* heap, int side) { TLSX* extension = NULL; SupportedCurve* curve = NULL; @@ -5961,7 +6096,7 @@ int TLSX_UseSupportedCurve(TLSX** extensions, word16 name, void* heap) return BAD_FUNC_ARG; } - if (! TLSX_IsGroupSupported(name)) { + if (!TLSX_IsGroupSupported(name, side)) { return BAD_FUNC_ARG; } @@ -7942,7 +8077,8 @@ static int TLSX_SetSignatureAlgorithmsCert(TLSX** extensions, /******************************************************************************/ #ifndef MAX_KEYSHARE_NAMED_GROUPS - #if defined(WOLFSSL_HAVE_MLKEM) && !defined(WOLFSSL_MLKEM_NO_MAKE_KEY) + #if defined(WOLFSSL_HAVE_MLKEM) && !defined(WOLFSSL_MLKEM_NO_MAKE_KEY) && \ + !defined(WOLFSSL_MLKEM_NO_DECAPSULATE) #define MAX_KEYSHARE_NAMED_GROUPS 24 #else #define MAX_KEYSHARE_NAMED_GROUPS 12 @@ -8591,7 +8727,7 @@ static int TLSX_KeyShare_GenEccKey(WOLFSSL *ssl, KeyShareEntry* kse) #if (defined(WOLFSSL_MLKEM_CACHE_A) || \ (defined(HAVE_PKCS11) && !defined(NO_PKCS11_MLKEM))) && \ !defined(WOLFSSL_TLSX_PQC_MLKEM_STORE_PRIV_KEY) - /* Store KyberKey object rather than private key bytes in key share entry. + /* Store MlKemKey object rather than private key bytes in key share entry. * Improves performance at cost of more dynamic memory being used. */ #define WOLFSSL_TLSX_PQC_MLKEM_STORE_OBJ #endif @@ -8601,7 +8737,8 @@ static int TLSX_KeyShare_GenEccKey(WOLFSSL *ssl, KeyShareEntry* kse) "WOLFSSL_TLSX_PQC_MLKEM_STORE_OBJ" #endif -#if !defined(WOLFSSL_MLKEM_NO_MAKE_KEY) || \ +#if (!defined(WOLFSSL_MLKEM_NO_MAKE_KEY) && \ + !defined(WOLFSSL_MLKEM_NO_DECAPSULATE)) || \ !defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) || \ (!defined(WOLFSSL_MLKEM_NO_DECAPSULATE) && \ !defined(WOLFSSL_TLSX_PQC_MLKEM_STORE_OBJ)) @@ -8738,7 +8875,8 @@ static void findEccPqc(int *ecc, int *pqc, int *pqc_first, int group) } } -#ifndef WOLFSSL_MLKEM_NO_MAKE_KEY +#if !defined(WOLFSSL_MLKEM_NO_MAKE_KEY) && \ + !defined(WOLFSSL_MLKEM_NO_DECAPSULATE) /* Create a key share entry using pqc parameters group on the client side. * Generates a key pair. * @@ -8751,11 +8889,11 @@ static int TLSX_KeyShare_GenPqcKeyClient(WOLFSSL *ssl, KeyShareEntry* kse) int ret = 0; int type = 0; #ifndef WOLFSSL_TLSX_PQC_MLKEM_STORE_OBJ - WC_DECLARE_VAR(kem, KyberKey, 1, 0); + WC_DECLARE_VAR(kem, MlKemKey, 1, 0); byte* privKey = NULL; word32 privSz = 0; #else - KyberKey* kem = NULL; + MlKemKey* kem = NULL; #endif /* This gets called twice. Once during parsing of the key share and once @@ -8768,7 +8906,7 @@ static int TLSX_KeyShare_GenPqcKeyClient(WOLFSSL *ssl, KeyShareEntry* kse) /* Get the type of key we need from the key share group. */ ret = mlkem_id2type(kse->group, &type); if (ret == WC_NO_ERR_TRACE(NOT_COMPILED_IN)) { - WOLFSSL_MSG("Invalid Kyber algorithm specified."); + WOLFSSL_MSG("Invalid ML-KEM algorithm specified."); ret = BAD_FUNC_ARG; } @@ -8776,7 +8914,7 @@ static int TLSX_KeyShare_GenPqcKeyClient(WOLFSSL *ssl, KeyShareEntry* kse) #ifdef WOLFSSL_SMALL_STACK if (ret == 0) { - kem = (KyberKey *)XMALLOC(sizeof(*kem), ssl->heap, + kem = (MlKemKey *)XMALLOC(sizeof(*kem), ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY); if (kem == NULL) { WOLFSSL_MSG("KEM memory allocation failure"); @@ -8786,17 +8924,17 @@ static int TLSX_KeyShare_GenPqcKeyClient(WOLFSSL *ssl, KeyShareEntry* kse) #endif /* WOLFSSL_SMALL_STACK */ if (ret == 0) { - ret = wc_KyberKey_Init(type, kem, ssl->heap, ssl->devId); + ret = wc_MlKemKey_Init(kem, type, ssl->heap, ssl->devId); if (ret != 0) { - WOLFSSL_MSG("Failed to initialize Kyber Key."); + WOLFSSL_MSG("Failed to initialize ML-KEM Key."); } } if (ret == 0) { - ret = wc_KyberKey_PrivateKeySize(kem, &privSz); + ret = wc_MlKemKey_PrivateKeySize(kem, &privSz); } if (ret == 0) { - ret = wc_KyberKey_PublicKeySize(kem, &kse->pubKeyLen); + ret = wc_MlKemKey_PublicKeySize(kem, &kse->pubKeyLen); } if (ret == 0) { @@ -8808,8 +8946,8 @@ static int TLSX_KeyShare_GenPqcKeyClient(WOLFSSL *ssl, KeyShareEntry* kse) } #else if (ret == 0) { - /* Allocate a Kyber key to hold private key. */ - kem = (KyberKey*)XMALLOC(sizeof(KyberKey), ssl->heap, + /* Allocate an ML-KEM key to hold private key. */ + kem = (MlKemKey*)XMALLOC(sizeof(MlKemKey), ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY); if (kem == NULL) { WOLFSSL_MSG("KEM memory allocation failure"); @@ -8817,13 +8955,13 @@ static int TLSX_KeyShare_GenPqcKeyClient(WOLFSSL *ssl, KeyShareEntry* kse) } } if (ret == 0) { - ret = wc_KyberKey_Init(type, kem, ssl->heap, ssl->devId); + ret = wc_MlKemKey_Init(kem, type, ssl->heap, ssl->devId); if (ret != 0) { - WOLFSSL_MSG("Failed to initialize Kyber Key."); + WOLFSSL_MSG("Failed to initialize ML-KEM Key."); } } if (ret == 0) { - ret = wc_KyberKey_PublicKeySize(kem, &kse->pubKeyLen); + ret = wc_MlKemKey_PublicKeySize(kem, &kse->pubKeyLen); } #endif @@ -8837,32 +8975,32 @@ static int TLSX_KeyShare_GenPqcKeyClient(WOLFSSL *ssl, KeyShareEntry* kse) } if (ret == 0) { - ret = wc_KyberKey_MakeKey(kem, ssl->rng); + ret = wc_MlKemKey_MakeKey(kem, ssl->rng); if (ret != 0) { - WOLFSSL_MSG("Kyber keygen failure"); + WOLFSSL_MSG("ML-KEM keygen failure"); } } if (ret == 0) { - ret = wc_KyberKey_EncodePublicKey(kem, kse->pubKey, + ret = wc_MlKemKey_EncodePublicKey(kem, kse->pubKey, kse->pubKeyLen); } #ifndef WOLFSSL_TLSX_PQC_MLKEM_STORE_OBJ if (ret == 0) { PRIVATE_KEY_UNLOCK(); - ret = wc_KyberKey_EncodePrivateKey(kem, privKey, privSz); + ret = wc_MlKemKey_EncodePrivateKey(kem, privKey, privSz); PRIVATE_KEY_LOCK(); } #endif #ifdef WOLFSSL_DEBUG_TLS - WOLFSSL_MSG("Public Kyber Key"); + WOLFSSL_MSG("Public ML-KEM Key"); WOLFSSL_BUFFER(kse->pubKey, kse->pubKeyLen ); #endif if (ret != 0) { /* Data owned by key share entry otherwise. */ - wc_KyberKey_Free(kem); + wc_MlKemKey_Free(kem); XFREE(kse->pubKey, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); kse->pubKey = NULL; #ifndef WOLFSSL_TLSX_PQC_MLKEM_STORE_OBJ @@ -8878,7 +9016,7 @@ static int TLSX_KeyShare_GenPqcKeyClient(WOLFSSL *ssl, KeyShareEntry* kse) } else { #ifndef WOLFSSL_TLSX_PQC_MLKEM_STORE_OBJ - wc_KyberKey_Free(kem); + wc_MlKemKey_Free(kem); kse->privKey = (byte*)privKey; kse->privKeyLen = privSz; #else @@ -9037,7 +9175,7 @@ static int TLSX_KeyShare_GenPqcHybridKeyClient(WOLFSSL *ssl, KeyShareEntry* kse) kse->privKeyLen = pqc_kse->privKeyLen; pqc_kse->privKey = NULL; #else - /* PQC private key is a pointer to KyberKey object */ + /* PQC private key is a pointer to MlKemKey object */ kse->privKey = (byte*)pqc_kse->key; kse->privKeyLen = 0; pqc_kse->key = NULL; @@ -9049,7 +9187,7 @@ static int TLSX_KeyShare_GenPqcHybridKeyClient(WOLFSSL *ssl, KeyShareEntry* kse) } #ifdef WOLFSSL_DEBUG_TLS - WOLFSSL_MSG("Public Kyber Key"); + WOLFSSL_MSG("Public ML-KEM Key"); WOLFSSL_BUFFER(kse->pubKey, kse->pubKeyLen ); #endif @@ -9058,7 +9196,7 @@ static int TLSX_KeyShare_GenPqcHybridKeyClient(WOLFSSL *ssl, KeyShareEntry* kse) return ret; } -#endif /* !WOLFSSL_MLKEM_NO_MAKE_KEY */ +#endif /* !WOLFSSL_MLKEM_NO_MAKE_KEY && !WOLFSSL_MLKEM_NO_DECAPSULATE */ #endif /* WOLFSSL_HAVE_MLKEM */ /* Generate a secret/key using the key share entry. @@ -9076,7 +9214,8 @@ int TLSX_KeyShare_GenKey(WOLFSSL *ssl, KeyShareEntry *kse) ret = TLSX_KeyShare_GenX25519Key(ssl, kse); else if (kse->group == WOLFSSL_ECC_X448) ret = TLSX_KeyShare_GenX448Key(ssl, kse); -#if defined(WOLFSSL_HAVE_MLKEM) && !defined(WOLFSSL_MLKEM_NO_MAKE_KEY) +#if defined(WOLFSSL_HAVE_MLKEM) && !defined(WOLFSSL_MLKEM_NO_MAKE_KEY) && \ + !defined(WOLFSSL_MLKEM_NO_DECAPSULATE) else if (WOLFSSL_NAMED_GROUP_IS_PQC(kse->group)) ret = TLSX_KeyShare_GenPqcKeyClient(ssl, kse); else if (WOLFSSL_NAMED_GROUP_IS_PQC_HYBRID(kse->group)) @@ -9137,7 +9276,7 @@ static void TLSX_KeyShare_FreeAll(KeyShareEntry* list, void* heap) } else if (WOLFSSL_NAMED_GROUP_IS_PQC(current->group)) { #ifdef WOLFSSL_HAVE_MLKEM - wc_KyberKey_Free((KyberKey*)current->key); + wc_MlKemKey_Free((MlKemKey*)current->key); #ifndef WOLFSSL_TLSX_PQC_MLKEM_STORE_OBJ if (current->privKey != NULL) { ForceZero(current->privKey, current->privKeyLen); @@ -9152,7 +9291,7 @@ static void TLSX_KeyShare_FreeAll(KeyShareEntry* list, void* heap) /* Free PQC private key */ #ifdef WOLFSSL_TLSX_PQC_MLKEM_STORE_OBJ - wc_KyberKey_Free((KyberKey*)current->privKey); + wc_MlKemKey_Free((MlKemKey*)current->privKey); #else if (current->privKey != NULL) { ForceZero(current->privKey, current->privKeyLen); @@ -9901,7 +10040,7 @@ static int TLSX_KeyShare_ProcessEcc(WOLFSSL* ssl, KeyShareEntry* keyShareEntry) } #if defined(WOLFSSL_HAVE_MLKEM) && !defined(WOLFSSL_MLKEM_NO_DECAPSULATE) -/* Process the Kyber key share extension on the client side. +/* Process the ML-KEM key share extension on the client side. * * ssl The SSL/TLS object. * keyShareEntry The key share entry object to use to calculate shared secret. @@ -9916,7 +10055,7 @@ static int TLSX_KeyShare_ProcessPqcClient_ex(WOLFSSL* ssl, word32* ssOutSz) { int ret = 0; - KyberKey* kem = (KyberKey*)keyShareEntry->key; + MlKemKey* kem = (MlKemKey*)keyShareEntry->key; #ifndef WOLFSSL_TLSX_PQC_MLKEM_STORE_OBJ word32 privSz = 0; #endif @@ -9940,8 +10079,8 @@ static int TLSX_KeyShare_ProcessPqcClient_ex(WOLFSSL* ssl, if (kem == NULL) { int type = 0; - /* Allocate a Kyber key to hold private key. */ - kem = (KyberKey*) XMALLOC(sizeof(KyberKey), ssl->heap, + /* Allocate an ML-KEM key to hold private key. */ + kem = (MlKemKey*) XMALLOC(sizeof(MlKemKey), ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY); if (kem == NULL) { WOLFSSL_MSG("GenPqcKey memory error"); @@ -9955,29 +10094,29 @@ static int TLSX_KeyShare_ProcessPqcClient_ex(WOLFSSL* ssl, ret = BAD_FUNC_ARG; } if (ret == 0) { - ret = wc_KyberKey_Init(type, kem, ssl->heap, ssl->devId); + ret = wc_MlKemKey_Init(kem, type, ssl->heap, ssl->devId); if (ret != 0) { - WOLFSSL_MSG("Error creating Kyber KEM"); + WOLFSSL_MSG("Error creating ML-KEM key"); } } } #else if (kem == NULL || keyShareEntry->privKeyLen != 0) { - WOLFSSL_MSG("Invalid Kyber key."); + WOLFSSL_MSG("Invalid ML-KEM key."); ret = BAD_FUNC_ARG; } #endif if (ret == 0) { - ret = wc_KyberKey_SharedSecretSize(kem, &ssSz); + ret = wc_MlKemKey_SharedSecretSize(kem, &ssSz); } if (ret == 0) { - ret = wc_KyberKey_CipherTextSize(kem, &ctSz); + ret = wc_MlKemKey_CipherTextSize(kem, &ctSz); } #ifndef WOLFSSL_TLSX_PQC_MLKEM_STORE_OBJ if (ret == 0) { - ret = wc_KyberKey_PrivateKeySize(kem, &privSz); + ret = wc_MlKemKey_PrivateKeySize(kem, &privSz); } if (ret == 0 && privSz != keyShareEntry->privKeyLen) { WOLFSSL_MSG("Invalid private key size."); @@ -9985,7 +10124,7 @@ static int TLSX_KeyShare_ProcessPqcClient_ex(WOLFSSL* ssl, } if (ret == 0) { PRIVATE_KEY_UNLOCK(); - ret = wc_KyberKey_DecodePrivateKey(kem, keyShareEntry->privKey, privSz); + ret = wc_MlKemKey_DecodePrivateKey(kem, keyShareEntry->privKey, privSz); PRIVATE_KEY_LOCK(); } #endif @@ -9996,11 +10135,11 @@ static int TLSX_KeyShare_ProcessPqcClient_ex(WOLFSSL* ssl, } if (ret == 0) { PRIVATE_KEY_UNLOCK(); - ret = wc_KyberKey_Decapsulate(kem, ssOutput, + ret = wc_MlKemKey_Decapsulate(kem, ssOutput, keyShareEntry->ke, ctSz); PRIVATE_KEY_LOCK(); if (ret != 0) { - WOLFSSL_MSG("wc_KyberKey decapsulation failure."); + WOLFSSL_MSG("wc_MlKemKey decapsulation failure."); ret = BAD_FUNC_ARG; } } @@ -10008,7 +10147,7 @@ static int TLSX_KeyShare_ProcessPqcClient_ex(WOLFSSL* ssl, *ssOutSz = ssSz; } - wc_KyberKey_Free(kem); + wc_MlKemKey_Free(kem); XFREE(kem, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY); keyShareEntry->key = NULL; @@ -10019,7 +10158,7 @@ static int TLSX_KeyShare_ProcessPqcClient_ex(WOLFSSL* ssl, return ret; } -/* Process the Kyber key share extension on the client side. +/* Process the ML-KEM key share extension on the client side. * * ssl The SSL/TLS object. * keyShareEntry The key share entry object to use to calculate shared secret. @@ -10107,11 +10246,11 @@ static int TLSX_KeyShare_ProcessPqcHybridClient(WOLFSSL* ssl, ret = mlkem_id2type(pqc_group, &type); if (ret != 0) { - WOLFSSL_MSG("Invalid Kyber algorithm specified."); + WOLFSSL_MSG("Invalid ML-KEM algorithm specified."); ret = BAD_FUNC_ARG; } if (ret == 0) { - pqc_kse->key = XMALLOC(sizeof(KyberKey), ssl->heap, + pqc_kse->key = XMALLOC(sizeof(MlKemKey), ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY); if (pqc_kse->key == NULL) { WOLFSSL_MSG("GenPqcKey memory error"); @@ -10119,10 +10258,10 @@ static int TLSX_KeyShare_ProcessPqcHybridClient(WOLFSSL* ssl, } } if (ret == 0) { - ret = wc_KyberKey_Init(type, (KyberKey*)pqc_kse->key, + ret = wc_MlKemKey_Init((MlKemKey*)pqc_kse->key, type, ssl->heap, ssl->devId); if (ret != 0) { - WOLFSSL_MSG("Error creating Kyber KEM"); + WOLFSSL_MSG("Error creating ML-KEM key"); } } #else @@ -10133,11 +10272,11 @@ static int TLSX_KeyShare_ProcessPqcHybridClient(WOLFSSL* ssl, pqc_kse->privKeyLen = keyShareEntry->privKeyLen; if (ret == 0) { - ret = wc_KyberKey_SharedSecretSize((KyberKey*)pqc_kse->key, + ret = wc_MlKemKey_SharedSecretSize((MlKemKey*)pqc_kse->key, &ssSzPqc); } if (ret == 0) { - ret = wc_KyberKey_CipherTextSize((KyberKey*)pqc_kse->key, + ret = wc_MlKemKey_CipherTextSize((MlKemKey*)pqc_kse->key, &ctSz); if (ret == 0 && keyShareEntry->keLen <= ctSz) { WOLFSSL_MSG("Invalid ciphertext size."); @@ -10671,7 +10810,7 @@ static int TLSX_KeyShare_New(KeyShareEntry** list, int group, void *heap, } #if defined(WOLFSSL_HAVE_MLKEM) && !defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) -/* Process the Kyber key share extension on the server side. +/* Process the ML-KEM key share extension on the server side. * * ssl The SSL/TLS object. * keyShareEntry The key share entry object to be sent to the client. @@ -10689,7 +10828,7 @@ static int TLSX_KeyShare_HandlePqcKeyServer(WOLFSSL* ssl, /* We are on the server side. The key share contains a PQC KEM public key * that we are using for an encapsulate operation. The resulting ciphertext * is stored in the server key share. */ - KyberKey* kemKey = (KyberKey*)keyShareEntry->key; + MlKemKey* kemKey = (MlKemKey*)keyShareEntry->key; byte* ciphertext = NULL; int ret = 0; word32 pubSz = 0; @@ -10704,8 +10843,8 @@ static int TLSX_KeyShare_HandlePqcKeyServer(WOLFSSL* ssl, if (kemKey == NULL) { int type = 0; - /* Allocate a Kyber key to hold private key. */ - kemKey = (KyberKey*) XMALLOC(sizeof(KyberKey), ssl->heap, + /* Allocate an ML-KEM key to hold private key. */ + kemKey = (MlKemKey*) XMALLOC(sizeof(MlKemKey), ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY); if (kemKey == NULL) { WOLFSSL_MSG("GenPqcKey memory error"); @@ -10719,21 +10858,21 @@ static int TLSX_KeyShare_HandlePqcKeyServer(WOLFSSL* ssl, ret = BAD_FUNC_ARG; } if (ret == 0) { - ret = wc_KyberKey_Init(type, kemKey, ssl->heap, ssl->devId); + ret = wc_MlKemKey_Init(kemKey, type, ssl->heap, ssl->devId); if (ret != 0) { - WOLFSSL_MSG("Error creating Kyber KEM"); + WOLFSSL_MSG("Error creating ML-KEM key"); } } } if (ret == 0) { - ret = wc_KyberKey_PublicKeySize(kemKey, &pubSz); + ret = wc_MlKemKey_PublicKeySize(kemKey, &pubSz); } if (ret == 0) { - ret = wc_KyberKey_CipherTextSize(kemKey, &ctSz); + ret = wc_MlKemKey_CipherTextSize(kemKey, &ctSz); } if (ret == 0) { - ret = wc_KyberKey_SharedSecretSize(kemKey, &ssSz); + ret = wc_MlKemKey_SharedSecretSize(kemKey, &ssSz); } if (ret == 0 && clientLen != pubSz) { @@ -10751,13 +10890,13 @@ static int TLSX_KeyShare_HandlePqcKeyServer(WOLFSSL* ssl, } if (ret == 0) { - ret = wc_KyberKey_DecodePublicKey(kemKey, clientData, pubSz); + ret = wc_MlKemKey_DecodePublicKey(kemKey, clientData, pubSz); } if (ret == 0) { - ret = wc_KyberKey_Encapsulate(kemKey, ciphertext, + ret = wc_MlKemKey_Encapsulate(kemKey, ciphertext, ssOutput, ssl->rng); if (ret != 0) { - WOLFSSL_MSG("wc_KyberKey encapsulation failure."); + WOLFSSL_MSG("wc_MlKemKey encapsulation failure."); } } @@ -10780,7 +10919,7 @@ static int TLSX_KeyShare_HandlePqcKeyServer(WOLFSSL* ssl, XFREE(ciphertext, ssl->heap, DYNAMIC_TYPE_TLSX); - wc_KyberKey_Free(kemKey); + wc_MlKemKey_Free(kemKey); XFREE(kemKey, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY); keyShareEntry->key = NULL; return ret; @@ -10840,8 +10979,8 @@ int TLSX_KeyShare_HandlePqcHybridKeyServer(WOLFSSL* ssl, * decode these sizes to properly concatenate the KEM ciphertext with the * ECDH public key. */ if (ret == 0) { - /* Allocate a Kyber key to hold private key. */ - pqc_kse->key = (KyberKey*) XMALLOC(sizeof(KyberKey), ssl->heap, + /* Allocate an ML-KEM key to hold private key. */ + pqc_kse->key = (MlKemKey*) XMALLOC(sizeof(MlKemKey), ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY); if (pqc_kse->key == NULL) { WOLFSSL_MSG("GenPqcKey memory error"); @@ -10855,22 +10994,22 @@ int TLSX_KeyShare_HandlePqcHybridKeyServer(WOLFSSL* ssl, ret = BAD_FUNC_ARG; } if (ret == 0) { - ret = wc_KyberKey_Init(type, (KyberKey*)pqc_kse->key, + ret = wc_MlKemKey_Init((MlKemKey*)pqc_kse->key, type, ssl->heap, ssl->devId); if (ret != 0) { - WOLFSSL_MSG("Error creating Kyber KEM"); + WOLFSSL_MSG("Error creating ML-KEM key"); } } if (ret == 0) { - ret = wc_KyberKey_SharedSecretSize((KyberKey*)pqc_kse->key, + ret = wc_MlKemKey_SharedSecretSize((MlKemKey*)pqc_kse->key, &ssSzPqc); } if (ret == 0) { - ret = wc_KyberKey_CipherTextSize((KyberKey*)pqc_kse->key, + ret = wc_MlKemKey_CipherTextSize((MlKemKey*)pqc_kse->key, &ctSz); } if (ret == 0) { - ret = wc_KyberKey_PublicKeySize((KyberKey*)pqc_kse->key, + ret = wc_MlKemKey_PublicKeySize((MlKemKey*)pqc_kse->key, &pubSz); } } @@ -11400,18 +11539,18 @@ static const word16 preferredGroup[] = { * directly into an assignment, so wrap non-trivial expressions in parentheses. */ #ifndef WOLFSSL_KEY_SHARE_DEFAULT_GROUP -#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_HAVE_MLKEM) && \ +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_HAVE_MLKEM_CLIENT_SUPPORT) && \ !defined(WOLFSSL_NO_ML_KEM) && defined(WOLFSSL_PQC_HYBRIDS) && \ !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_CURVE25519) && \ ECC_MIN_KEY_SZ <= 256 #define WOLFSSL_KEY_SHARE_DEFAULT_GROUP WOLFSSL_X25519MLKEM768 -#elif defined(WOLFSSL_TLS13) && defined(WOLFSSL_HAVE_MLKEM) && \ +#elif defined(WOLFSSL_TLS13) && defined(WOLFSSL_HAVE_MLKEM_CLIENT_SUPPORT) && \ !defined(WOLFSSL_NO_ML_KEM) && defined(WOLFSSL_PQC_HYBRIDS) && \ !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_ECC) && \ (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && \ ECC_MIN_KEY_SZ <= 256 #define WOLFSSL_KEY_SHARE_DEFAULT_GROUP WOLFSSL_SECP256R1MLKEM768 -#elif defined(WOLFSSL_TLS13) && defined(WOLFSSL_HAVE_MLKEM) && \ +#elif defined(WOLFSSL_TLS13) && defined(WOLFSSL_HAVE_MLKEM_CLIENT_SUPPORT) && \ !defined(WOLFSSL_NO_ML_KEM) && defined(WOLFSSL_PQC_HYBRIDS) && \ !defined(WOLFSSL_NO_ML_KEM_1024) && defined(HAVE_ECC) && \ (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && \ @@ -11505,7 +11644,7 @@ int TLSX_KeyShare_SetSupported(const WOLFSSL* ssl, TLSX** extensions) for (; curve != NULL; curve = curve->next) { /* Use server's preference order. Common group was found but key share * was missing */ - if (!TLSX_IsGroupSupported(curve->name)) + if (!TLSX_IsGroupSupported(curve->name, ssl->options.side)) continue; if (wolfSSL_curve_is_disabled(ssl, curve->name)) continue; @@ -11784,7 +11923,7 @@ int TLSX_KeyShare_Choose(const WOLFSSL *ssl, TLSX* extensions, if (wolfSSL_curve_is_disabled(ssl, clientKSE->group)) continue; } - if (!TLSX_IsGroupSupported(clientKSE->group)) + if (!TLSX_IsGroupSupported(clientKSE->group, ssl->options.side)) continue; rank = TLSX_KeyShare_GroupRank(ssl, clientKSE->group); @@ -13651,10 +13790,15 @@ void TLSX_Remove(TLSX** list, TLSX_Type type, void* heap) static int TLSX_GreaseECH_Use(TLSX** extensions, void* heap, WC_RNG* rng) { int ret = 0; + TLSX* echX; WOLFSSL_ECH* ech; if (extensions == NULL) return BAD_FUNC_ARG; + /* skip if we already have an ech extension, we will for hrr */ + echX = TLSX_Find(*extensions, TLSX_ECH); + if (echX != NULL) + return 0; ech = (WOLFSSL_ECH*)XMALLOC(sizeof(WOLFSSL_ECH), heap, DYNAMIC_TYPE_TMP_BUFFER); @@ -13846,7 +13990,7 @@ static int TLSX_ECH_Write(WOLFSSL_ECH* ech, byte msgType, byte* writeBuf, *writeBuf_p = ech->configId; writeBuf_p += sizeof(ech->configId); /* encLen */ - if (ech->hpkeContext == NULL) { + if (ech->innerCount == 0) { c16toa(ech->encLen, writeBuf_p); } else { @@ -13855,50 +13999,59 @@ static int TLSX_ECH_Write(WOLFSSL_ECH* ech, byte msgType, byte* writeBuf, } writeBuf_p += 2; if (ech->state == ECH_WRITE_GREASE) { - WC_ALLOC_VAR_EX(hpke, Hpke, 1, NULL, DYNAMIC_TYPE_TMP_BUFFER, ret = MEMORY_E); - WC_ALLOC_VAR_EX(rng, WC_RNG, 1, NULL, DYNAMIC_TYPE_RNG, ret = MEMORY_E); - /* hpke init */ - if (ret == 0) { - ret = wc_HpkeInit(hpke, ech->kemId, ech->cipherSuite.kdfId, - ech->cipherSuite.aeadId, NULL); - } + word32 size; + WC_ALLOC_VAR_EX(rng, WC_RNG, 1, NULL, DYNAMIC_TYPE_RNG, + ret = MEMORY_E); + if (ret == 0) rngRet = ret = wc_InitRng(rng); - /* create the ephemeralKey */ - if (ret == 0) - ret = wc_HpkeGenerateKeyPair(hpke, &ephemeralKey, rng); - /* enc */ - if (ret == 0) { - ret = wc_HpkeSerializePublicKey(hpke, ephemeralKey, writeBuf_p, - &ech->encLen); - writeBuf_p += ech->encLen; - } - if (ret == 0) { - /* innerClientHelloLen */ - c16toa(GREASE_ECH_SIZE + ((writeBuf_p + 2 - writeBuf) % 32), - writeBuf_p); - writeBuf_p += 2; + if (ret == 0 && ech->innerCount == 0) { + WC_ALLOC_VAR_EX(hpke, Hpke, 1, NULL, DYNAMIC_TYPE_TMP_BUFFER, + ret = MEMORY_E); - /* innerClientHello */ - ret = wc_RNG_GenerateBlock(rng, writeBuf_p, GREASE_ECH_SIZE + - ((writeBuf_p - writeBuf) % 32)); - writeBuf_p += GREASE_ECH_SIZE + ((writeBuf_p - writeBuf) % 32); + /* hpke init */ + if (ret == 0) + ret = wc_HpkeInit(hpke, ech->kemId, ech->cipherSuite.kdfId, + ech->cipherSuite.aeadId, NULL); + /* create the ephemeralKey */ + if (ret == 0) + ret = wc_HpkeGenerateKeyPair(hpke, &ephemeralKey, rng); + /* enc */ + if (ret == 0) { + ret = wc_HpkeSerializePublicKey(hpke, ephemeralKey, + writeBuf_p, &ech->encLen); + writeBuf_p += ech->encLen; + } + + if (ephemeralKey != NULL) + wc_HpkeFreeKey(hpke, hpke->kem, ephemeralKey, hpke->heap); + WC_FREE_VAR_EX(hpke, NULL, DYNAMIC_TYPE_TMP_BUFFER); } + + if (ret == 0) { + size = GREASE_ECH_SIZE + (ech->configId / 4); + size += ECH_PADDING_TO_32(size) + WC_AES_BLOCK_SIZE; + + /* innerClientHelloLen */ + c16toa((word16)size, writeBuf_p); + writeBuf_p += 2; + /* innerClientHello */ + ret = wc_RNG_GenerateBlock(rng, writeBuf_p, size); + writeBuf_p += size; + } + if (rngRet == 0) wc_FreeRng(rng); - if (ephemeralKey != NULL) - wc_HpkeFreeKey(hpke, hpke->kem, ephemeralKey, hpke->heap); - WC_FREE_VAR_EX(hpke, NULL, DYNAMIC_TYPE_TMP_BUFFER); WC_FREE_VAR_EX(rng, NULL, DYNAMIC_TYPE_RNG); } else { - /* only write enc if this is our first ech, no hpke context */ - if (ech->hpkeContext == NULL) { + if (ech->innerCount == 0) { /* write enc to writeBuf_p */ ret = wc_HpkeSerializePublicKey(ech->hpke, ech->ephemeralKey, writeBuf_p, &ech->encLen); writeBuf_p += ech->encLen; } + /* innerClientHelloLen */ c16toa((word16)ech->innerClientHelloLen, writeBuf_p); writeBuf_p += 2; @@ -13921,11 +14074,19 @@ static int TLSX_ECH_GetSize(WOLFSSL_ECH* ech, byte msgType) word32 size = 0; if (ech->state == ECH_WRITE_GREASE) { + word32 payload; size = sizeof(ech->type) + sizeof(ech->cipherSuite) + - sizeof(ech->configId) + sizeof(word16) + ech->encLen + - sizeof(word16); - - size += GREASE_ECH_SIZE + (size % 32); + sizeof(ech->configId) + sizeof(word16) + sizeof(word16); + /* enc only printed on CH1 */ + if (ech->innerCount == 0) + size += ech->encLen; + /* GREASE payload mimics the regular sealed inner: + * plaintext length divisible by 32 and the AEAD tag + * configId is used to randomize the GREASE length + * (divide by 4 to save space) */ + payload = GREASE_ECH_SIZE + (ech->configId / 4); + payload += ECH_PADDING_TO_32(payload) + WC_AES_BLOCK_SIZE; + size += payload; } else if (msgType == hello_retry_request) { size = ECH_ACCEPT_CONFIRMATION_SZ; @@ -13950,14 +14111,50 @@ static int TLSX_ECH_GetSize(WOLFSSL_ECH* ech, byte msgType) size = sizeof(ech->type) + sizeof(ech->cipherSuite) + sizeof(ech->configId) + sizeof(word16) + sizeof(word16) + ech->innerClientHelloLen; - /* only set encLen if this is inner hello 1 */ - if (ech->hpkeContext == NULL) + /* enc only printed on CH1 */ + if (ech->innerCount == 0) size += ech->encLen; } return (int)size; } +#ifdef HAVE_SECRET_CALLBACK +/* log ECH_SECRET and ECH_CONFIG + * returns 0 on success, TLS13_SECRET_CB_E otherwise */ +static int EchWriteKeyLog(WOLFSSL* ssl, const byte* secret, word32 secretSz, + const byte* config, word32 configSz) +{ + int ret = 0; + if (ssl->tls13SecretCb != NULL) { + ret = ssl->tls13SecretCb(ssl, ECH_SECRET, secret, (int)secretSz, + ssl->tls13SecretCtx); + if (ret == 0) { + ret = ssl->tls13SecretCb(ssl, ECH_CONFIG, config, (int)configSz, + ssl->tls13SecretCtx); + } + if (ret != 0) { + WOLFSSL_ERROR_VERBOSE(TLS13_SECRET_CB_E); + ret = TLS13_SECRET_CB_E; + } + } +#ifdef OPENSSL_EXTRA + if (ret == 0 && ssl->tls13KeyLogCb != NULL) { + ret = ssl->tls13KeyLogCb(ssl, ECH_SECRET, secret, (int)secretSz, NULL); + if (ret == 0) { + ret = ssl->tls13KeyLogCb(ssl, ECH_CONFIG, config, (int)configSz, + NULL); + } + if (ret != 0) { + WOLFSSL_ERROR_VERBOSE(TLS13_SECRET_CB_E); + ret = TLS13_SECRET_CB_E; + } + } +#endif /* OPENSSL_EXTRA */ + return ret; +} +#endif /* HAVE_SECRET_CALLBACK */ + /* rough check that inner hello fields do not exceed length of decrypted * information. Additionally, this function will check that all padding bytes * are zero and decrease the innerHelloLen accordingly if so. @@ -14367,8 +14564,8 @@ static int TLSX_ECH_ExpandOuterExtensions(WOLFSSL* ssl, WOLFSSL_ECH* ech, /* return status after attempting to open the hpke encrypted ech extension, if * successful the inner client hello will be stored in * ech->innerClientHelloLen */ -static int TLSX_ExtractEch(WOLFSSL_ECH* ech, WOLFSSL_EchConfig* echConfig, - byte* aad, word32 aadLen, void* heap) +static int TLSX_ExtractEch(WOLFSSL* ssl, WOLFSSL_ECH* ech, + WOLFSSL_EchConfig* echConfig, byte* aad, word32 aadLen) { int ret = 0; int i; @@ -14376,7 +14573,7 @@ static int TLSX_ExtractEch(WOLFSSL_ECH* ech, WOLFSSL_EchConfig* echConfig, word32 rawConfigLen = 0; byte* info = NULL; word32 infoLen = 0; - if (ech == NULL || echConfig == NULL || aad == NULL) + if (ssl == NULL || ech == NULL || echConfig == NULL || aad == NULL) return BAD_FUNC_ARG; /* verify the kem and key len */ if (wc_HpkeKemGetEncLen(echConfig->kemId) != ech->encLen) @@ -14394,13 +14591,14 @@ static int TLSX_ExtractEch(WOLFSSL_ECH* ech, WOLFSSL_EchConfig* echConfig, /* check if hpke already exists, may if HelloRetryRequest */ if (ech->hpke == NULL) { allocatedHpke = 1; - ech->hpke = (Hpke*)XMALLOC(sizeof(Hpke), heap, DYNAMIC_TYPE_TMP_BUFFER); + ech->hpke = (Hpke*)XMALLOC(sizeof(Hpke), ssl->heap, + DYNAMIC_TYPE_TMP_BUFFER); if (ech->hpke == NULL) ret = MEMORY_E; /* init the hpke struct */ if (ret == 0) { ret = wc_HpkeInit(ech->hpke, echConfig->kemId, - ech->cipherSuite.kdfId, ech->cipherSuite.aeadId, heap); + ech->cipherSuite.kdfId, ech->cipherSuite.aeadId, ssl->heap); } if (ret == 0) { /* allocate hpkeContext */ @@ -14418,7 +14616,7 @@ static int TLSX_ExtractEch(WOLFSSL_ECH* ech, WOLFSSL_EchConfig* echConfig, /* create info */ if (ret == 0) { infoLen = TLS_INFO_CONST_STRING_SZ + 1 + rawConfigLen; - info = (byte*)XMALLOC(infoLen, heap, DYNAMIC_TYPE_TMP_BUFFER); + info = (byte*)XMALLOC(infoLen, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); if (info == NULL) ret = MEMORY_E; @@ -14429,6 +14627,16 @@ static int TLSX_ExtractEch(WOLFSSL_ECH* ech, WOLFSSL_EchConfig* echConfig, TLS_INFO_CONST_STRING_SZ + 1, &rawConfigLen); } } +#ifdef HAVE_SECRET_CALLBACK + /* allocate secret buffer for wc_HpkeInitOpenContext to copy into */ + if (ret == 0 && (ssl->tls13SecretCb != NULL +#ifdef OPENSSL_EXTRA + || ssl->tls13KeyLogCb != NULL +#endif + )) { + ret = wc_HpkeInitEchSecret(ech->hpke); + } +#endif /* HAVE_SECRET_CALLBACK */ /* init the context for opening */ if (ret == 0) { ret = wc_HpkeInitOpenContext(ech->hpke, ech->hpkeContext, @@ -14442,17 +14650,29 @@ static int TLSX_ExtractEch(WOLFSSL_ECH* ech, WOLFSSL_EchConfig* echConfig, ech->outerClientPayload, ech->innerClientHelloLen, ech->innerClientHello + HANDSHAKE_HEADER_SZ); } + +#ifdef HAVE_SECRET_CALLBACK + if (ret == 0 && ech->hpke->echSecret != NULL) { + ret = EchWriteKeyLog(ssl, ech->hpke->echSecret, ech->hpke->Nsecret, + info + TLS_INFO_CONST_STRING_SZ + 1, rawConfigLen); + } + wc_HpkeFreeEchSecret(ech->hpke); +#endif /* HAVE_SECRET_CALLBACK */ + /* only free hpke/hpkeContext if allocated in this call; otherwise preserve * them for clientHello2 */ if (ret != 0 && allocatedHpke) { - XFREE(ech->hpke, heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(ech->hpke, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); ech->hpke = NULL; - XFREE(ech->hpkeContext, heap, DYNAMIC_TYPE_TMP_BUFFER); - ech->hpkeContext = NULL; + if (ech->hpkeContext != NULL) { + ForceZero(ech->hpkeContext, sizeof(HpkeBaseContext)); + XFREE(ech->hpkeContext, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + ech->hpkeContext = NULL; + } } if (info != NULL) - XFREE(info, heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(info, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); return ret; } @@ -14656,9 +14876,9 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size, echConfig = ssl->ctx->echConfigs; while (echConfig != NULL) { if (echConfig->configId == ech->configId) { - ret = TLSX_ExtractEch(ech, echConfig, aadCopy, ech->aadLen, - ssl->heap); - if (ret == 0) + ret = TLSX_ExtractEch(ssl, ech, echConfig, aadCopy, + ech->aadLen); + if (ret == 0 || ret == WC_NO_ERR_TRACE(TLS13_SECRET_CB_E)) break; } echConfig = echConfig->next; @@ -14668,42 +14888,46 @@ static int TLSX_ECH_Parse(WOLFSSL* ssl, const byte* readBuf, word16 size, echConfig = ssl->ctx->echConfigs; while (echConfig != NULL) { if (echConfig->configId != ech->configId) { - ret = TLSX_ExtractEch(ech, echConfig, aadCopy, ech->aadLen, - ssl->heap); - if (ret == 0) + ret = TLSX_ExtractEch(ssl, ech, echConfig, aadCopy, + ech->aadLen); + if (ret == 0 || ret == WC_NO_ERR_TRACE(TLS13_SECRET_CB_E)) break; } echConfig = echConfig->next; } } - /* if we failed to extract/expand */ - if (ret != 0 || echConfig == NULL) { - WOLFSSL_MSG("ECH rejected"); + /* TLS13_SECRET_CB_E isn't correlated with ECH acceptance so skip both + * paths */ + if (ret != WC_NO_ERR_TRACE(TLS13_SECRET_CB_E)) { + /* if we failed to extract/expand */ + if (ret != 0 || echConfig == NULL) { + WOLFSSL_MSG("ECH rejected"); - if (ssl->options.echAccepted == 1) { - /* on SH2 this is fatal */ - SendAlert(ssl, alert_fatal, decrypt_error); - WOLFSSL_ERROR_VERBOSE(DECRYPT_ERROR); - ret = DECRYPT_ERROR; + if (ssl->options.echAccepted == 0) { + /* on SH1 prepare to write retry configs */ + XFREE(ech->innerClientHello, ssl->heap, + DYNAMIC_TYPE_TMP_BUFFER); + ech->innerClientHello = NULL; + ech->state = ECH_WRITE_RETRY_CONFIGS; + ret = 0; + } + else { + /* on SH2 failure to decrypt is fatal */ + SendAlert(ssl, alert_fatal, decrypt_error); + WOLFSSL_ERROR_VERBOSE(DECRYPT_ERROR); + ret = DECRYPT_ERROR; + } } else { - /* on SH1 prepare to write retry configs */ - XFREE(ech->innerClientHello, ssl->heap, - DYNAMIC_TYPE_TMP_BUFFER); - ech->innerClientHello = NULL; - ech->state = ECH_WRITE_RETRY_CONFIGS; - ret = 0; - } - } - else { - WOLFSSL_MSG("ECH accepted"); - ssl->options.echAccepted = 1; + WOLFSSL_MSG("ECH accepted"); + ssl->options.echAccepted = 1; - ret = TLSX_ECH_CheckInnerPadding(ssl, ech); - if (ret == 0) { - /* expand EchOuterExtensions if present. - * Also, if it exists, copy sessionID from outer hello */ - ret = TLSX_ECH_ExpandOuterExtensions(ssl, ech, ssl->heap); + ret = TLSX_ECH_CheckInnerPadding(ssl, ech); + if (ret == 0) { + /* expand EchOuterExtensions if present. + * Also, if it exists, copy sessionID from outer hello */ + ret = TLSX_ECH_ExpandOuterExtensions(ssl, ech, ssl->heap); + } } } if (ret != 0) { @@ -14725,10 +14949,14 @@ static void TLSX_ECH_Free(WOLFSSL_ECH* ech, void* heap) if (ech->ephemeralKey != NULL) wc_HpkeFreeKey(ech->hpke, ech->hpke->kem, ech->ephemeralKey, ech->hpke->heap); + /* wc_HpkeFreeEchSecret is intentionally not here, free it in + * TLSX_ExtractEch / TLSX_FinalizeEch */ XFREE(ech->hpke, heap, DYNAMIC_TYPE_TMP_BUFFER); } - if (ech->hpkeContext != NULL) + if (ech->hpkeContext != NULL) { + ForceZero(ech->hpkeContext, sizeof(HpkeBaseContext)); XFREE(ech->hpkeContext, heap, DYNAMIC_TYPE_TMP_BUFFER); + } if (ech->privateName != NULL) XFREE((char*)ech->privateName, heap, DYNAMIC_TYPE_TMP_BUFFER); @@ -14738,13 +14966,15 @@ static void TLSX_ECH_Free(WOLFSSL_ECH* ech, void* heap) /* encrypt the client hello and store it in ech->outerClientPayload, return * status */ -int TLSX_FinalizeEch(WOLFSSL_ECH* ech, byte* aad, word32 aadLen) +int TLSX_FinalizeEch(WOLFSSL* ssl, WOLFSSL_ECH* ech, byte* aad, word32 aadLen) { int ret = 0; void* receiverPubkey = NULL; byte* info = NULL; int infoLen = 0; byte* aadCopy = NULL; + if (ssl == NULL || ech == NULL || aad == NULL) + return BAD_FUNC_ARG; /* setup hpke context to seal, should be done at most once per connection */ if (ech->hpkeContext == NULL) { /* import the server public key */ @@ -14772,6 +15002,18 @@ int TLSX_FinalizeEch(WOLFSSL_ECH* ech, byte* aad, word32 aadLen) TLS_INFO_CONST_STRING_SZ + 1); XMEMCPY(info + TLS_INFO_CONST_STRING_SZ + 1, ech->echConfig->raw, ech->echConfig->rawLen); + } +#ifdef HAVE_SECRET_CALLBACK + /* allocate secret buffer for wc_HpkeInitSealContext to copy into */ + if (ret == 0 && (ssl->tls13SecretCb != NULL +#ifdef OPENSSL_EXTRA + || ssl->tls13KeyLogCb != NULL +#endif + )) { + ret = wc_HpkeInitEchSecret(ech->hpke); + } +#endif /* HAVE_SECRET_CALLBACK */ + if (ret == 0) { /* init the context for seal with info and keys */ ret = wc_HpkeInitSealContext(ech->hpke, ech->hpkeContext, ech->ephemeralKey, receiverPubkey, info, infoLen); @@ -14792,6 +15034,15 @@ int TLSX_FinalizeEch(WOLFSSL_ECH* ech, byte* aad, word32 aadLen) aadLen, ech->innerClientHello, ech->innerClientHelloLen - ech->hpke->Nt, ech->outerClientPayload); } + +#ifdef HAVE_SECRET_CALLBACK + if (ret == 0 && ech->hpke->echSecret != NULL) { + ret = EchWriteKeyLog(ssl, ech->hpke->echSecret, ech->hpke->Nsecret, + ech->echConfig->raw, ech->echConfig->rawLen); + } + wc_HpkeFreeEchSecret(ech->hpke); +#endif /* HAVE_SECRET_CALLBACK */ + if (info != NULL) XFREE(info, ech->hpke->heap, DYNAMIC_TYPE_TMP_BUFFER); if (aadCopy != NULL) @@ -14810,7 +15061,7 @@ int TLSX_FinalizeEch(WOLFSSL_ECH* ech, byte* aad, word32 aadLen) #define ECH_PARSE TLSX_ECH_Parse #define ECH_FREE TLSX_ECH_Free -#endif +#endif /* WOLFSSL_TLS13 && HAVE_ECH */ /** Releases all extensions in the provided list. */ void TLSX_FreeAll(TLSX* list, void* heap) @@ -15608,14 +15859,15 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) if (ssl->options.resuming && ssl->session->namedGroup != 0) { return TLSX_UseSupportedCurve(extensions, ssl->session->namedGroup, - ssl->heap); + ssl->heap, ssl->options.side); } #endif if (ssl->numGroups != 0) { int i; for (i = 0; i < ssl->numGroups; i++) { - ret = TLSX_UseSupportedCurve(extensions, ssl->group[i], ssl->heap); + ret = TLSX_UseSupportedCurve(extensions, ssl->group[i], ssl->heap, + ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; } @@ -15623,39 +15875,41 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) } #endif /* WOLFSSL_TLS13 */ -#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_HAVE_MLKEM) && \ +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_HAVE_MLKEM_CLIENT_SUPPORT) && \ !defined(WOLFSSL_NO_ML_KEM) && defined(WOLFSSL_PQC_HYBRIDS) /* Prefer non-experimental PQ/T hybrid groups (only for TLS 1.3) */ - if (IsAtLeastTLSv1_3(ssl->version)) { + if (IsAtLeastTLSv1_3(ssl->version) && + TLSX_IsMlKemGroupSupported(ssl->options.side)) { #if !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_CURVE25519) && \ ECC_MIN_KEY_SZ <= 256 ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_X25519MLKEM768, - ssl->heap); + ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; #endif #if !defined(WOLFSSL_NO_ML_KEM_1024) && defined(HAVE_ECC) && \ (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && \ ECC_MIN_KEY_SZ <= 384 ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_SECP384R1MLKEM1024, - ssl->heap); + ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; #endif #if !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_ECC) && \ (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && \ ECC_MIN_KEY_SZ <= 256 ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_SECP256R1MLKEM768, - ssl->heap); + ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; #endif } #endif -#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_HAVE_MLKEM) && \ +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_HAVE_MLKEM_CLIENT_SUPPORT) && \ !defined(WOLFSSL_NO_ML_KEM) && !defined(WOLFSSL_NO_ML_KEM_1024) && \ !defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE) - if (IsAtLeastTLSv1_3(ssl->version)) { + if (IsAtLeastTLSv1_3(ssl->version) && + TLSX_IsMlKemGroupSupported(ssl->options.side)) { ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_ML_KEM_1024, - ssl->heap); + ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; } #endif @@ -15664,8 +15918,8 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) /* list in order by strength, since not all servers choose by strength */ #if (defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 521 #ifndef NO_ECC_SECP - ret = TLSX_UseSupportedCurve(extensions, - WOLFSSL_ECC_SECP521R1, ssl->heap); + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_ECC_SECP521R1, + ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; #endif #endif @@ -15674,7 +15928,7 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) if (IsAtLeastTLSv1_3(ssl->version)) { /* TLS 1.3 BrainpoolP512 curve */ ret = TLSX_UseSupportedCurve(extensions, - WOLFSSL_ECC_BRAINPOOLP512R1TLS13, ssl->heap); + WOLFSSL_ECC_BRAINPOOLP512R1TLS13, ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; /* If TLS 1.2 is allowed, also add the TLS 1.2 curve */ @@ -15682,14 +15936,14 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) (ssl->options.minDowngrade <= TLSv1_2_MINOR || ssl->options.minDowngrade <= DTLSv1_2_MINOR)) { ret = TLSX_UseSupportedCurve(extensions, - WOLFSSL_ECC_BRAINPOOLP512R1, ssl->heap); + WOLFSSL_ECC_BRAINPOOLP512R1, ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; } } else { /* TLS 1.2 only */ ret = TLSX_UseSupportedCurve(extensions, - WOLFSSL_ECC_BRAINPOOLP512R1, ssl->heap); + WOLFSSL_ECC_BRAINPOOLP512R1, ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; } #endif @@ -15699,9 +15953,10 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_HAVE_MLKEM) && \ !defined(WOLFSSL_NO_ML_KEM) && !defined(WOLFSSL_NO_ML_KEM_768) && \ !defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE) - if (IsAtLeastTLSv1_3(ssl->version)) { + if (IsAtLeastTLSv1_3(ssl->version) && + TLSX_IsMlKemGroupSupported(ssl->options.side)) { ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_ML_KEM_768, - ssl->heap); + ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; } #endif @@ -15709,15 +15964,15 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) #if defined(HAVE_ECC) #if (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 384 #ifndef NO_ECC_SECP - ret = TLSX_UseSupportedCurve(extensions, - WOLFSSL_ECC_SECP384R1, ssl->heap); + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_ECC_SECP384R1, + ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; #endif #ifdef HAVE_ECC_BRAINPOOL if (IsAtLeastTLSv1_3(ssl->version)) { /* TLS 1.3 BrainpoolP384 curve */ ret = TLSX_UseSupportedCurve(extensions, - WOLFSSL_ECC_BRAINPOOLP384R1TLS13, ssl->heap); + WOLFSSL_ECC_BRAINPOOLP384R1TLS13, ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; /* If TLS 1.2 is allowed, also add the TLS 1.2 curve */ @@ -15725,14 +15980,14 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) (ssl->options.minDowngrade <= TLSv1_2_MINOR || ssl->options.minDowngrade <= DTLSv1_2_MINOR)) { ret = TLSX_UseSupportedCurve(extensions, - WOLFSSL_ECC_BRAINPOOLP384R1, ssl->heap); + WOLFSSL_ECC_BRAINPOOLP384R1, ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; } } else { /* TLS 1.2 only */ ret = TLSX_UseSupportedCurve(extensions, - WOLFSSL_ECC_BRAINPOOLP384R1, ssl->heap); + WOLFSSL_ECC_BRAINPOOLP384R1, ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; } #endif @@ -15741,8 +15996,8 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) #ifndef HAVE_FIPS #if defined(HAVE_CURVE448) && ECC_MIN_KEY_SZ <= 448 - ret = TLSX_UseSupportedCurve(extensions, - WOLFSSL_ECC_X448, ssl->heap); + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_ECC_X448, ssl->heap, + ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; #endif #endif /* HAVE_FIPS */ @@ -15750,9 +16005,10 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_HAVE_MLKEM) && \ !defined(WOLFSSL_NO_ML_KEM) && !defined(WOLFSSL_NO_ML_KEM_512) && \ !defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE) - if (IsAtLeastTLSv1_3(ssl->version)) { - ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_ML_KEM_512, - ssl->heap); + if (IsAtLeastTLSv1_3(ssl->version) && + TLSX_IsMlKemGroupSupported(ssl->options.side)) { + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_ML_KEM_512, ssl->heap, + ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; } #endif @@ -15760,20 +16016,20 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) #if defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES) #if (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 256 #ifndef NO_ECC_SECP - ret = TLSX_UseSupportedCurve(extensions, - WOLFSSL_ECC_SECP256R1, ssl->heap); + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_ECC_SECP256R1, + ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; #endif #ifdef HAVE_ECC_KOBLITZ - ret = TLSX_UseSupportedCurve(extensions, - WOLFSSL_ECC_SECP256K1, ssl->heap); + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_ECC_SECP256K1, + ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; #endif #ifdef HAVE_ECC_BRAINPOOL if (IsAtLeastTLSv1_3(ssl->version)) { /* TLS 1.3 BrainpoolP256 curve */ ret = TLSX_UseSupportedCurve(extensions, - WOLFSSL_ECC_BRAINPOOLP256R1TLS13, ssl->heap); + WOLFSSL_ECC_BRAINPOOLP256R1TLS13, ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; /* If TLS 1.2 is allowed, also add the TLS 1.2 curve */ @@ -15781,20 +16037,20 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) (ssl->options.minDowngrade <= TLSv1_2_MINOR || ssl->options.minDowngrade <= DTLSv1_2_MINOR)) { ret = TLSX_UseSupportedCurve(extensions, - WOLFSSL_ECC_BRAINPOOLP256R1, ssl->heap); + WOLFSSL_ECC_BRAINPOOLP256R1, ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; } } else { /* TLS 1.2 only */ ret = TLSX_UseSupportedCurve(extensions, - WOLFSSL_ECC_BRAINPOOLP256R1, ssl->heap); + WOLFSSL_ECC_BRAINPOOLP256R1, ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; } #endif #if !defined(HAVE_FIPS) && defined(WOLFSSL_SM2) - ret = TLSX_UseSupportedCurve(extensions, - WOLFSSL_ECC_SM2P256V1, ssl->heap); + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_ECC_SM2P256V1, + ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; #endif #endif @@ -15802,8 +16058,8 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) #ifndef HAVE_FIPS #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256 - ret = TLSX_UseSupportedCurve(extensions, - WOLFSSL_ECC_X25519, ssl->heap); + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_ECC_X25519, + ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; #endif #endif /* HAVE_FIPS */ @@ -15811,13 +16067,13 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) #if defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES) #if (defined(HAVE_ECC224) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 224 #ifndef NO_ECC_SECP - ret = TLSX_UseSupportedCurve(extensions, - WOLFSSL_ECC_SECP224R1, ssl->heap); + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_ECC_SECP224R1, + ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; #endif #ifdef HAVE_ECC_KOBLITZ - ret = TLSX_UseSupportedCurve(extensions, - WOLFSSL_ECC_SECP224K1, ssl->heap); + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_ECC_SECP224K1, + ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; #endif #endif @@ -15825,30 +16081,30 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) #ifndef HAVE_FIPS #if (defined(HAVE_ECC192) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 192 #ifndef NO_ECC_SECP - ret = TLSX_UseSupportedCurve(extensions, - WOLFSSL_ECC_SECP192R1, ssl->heap); + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_ECC_SECP192R1, + ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; #endif #ifdef HAVE_ECC_KOBLITZ - ret = TLSX_UseSupportedCurve(extensions, - WOLFSSL_ECC_SECP192K1, ssl->heap); + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_ECC_SECP192K1, + ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; #endif #endif #if (defined(HAVE_ECC160) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 160 #ifndef NO_ECC_SECP - ret = TLSX_UseSupportedCurve(extensions, - WOLFSSL_ECC_SECP160R1, ssl->heap); + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_ECC_SECP160R1, + ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; #endif #ifdef HAVE_ECC_SECPR2 - ret = TLSX_UseSupportedCurve(extensions, - WOLFSSL_ECC_SECP160R2, ssl->heap); + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_ECC_SECP160R2, + ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; #endif #ifdef HAVE_ECC_KOBLITZ - ret = TLSX_UseSupportedCurve(extensions, - WOLFSSL_ECC_SECP160K1, ssl->heap); + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_ECC_SECP160K1, + ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; #endif #endif @@ -15860,8 +16116,8 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) #ifdef HAVE_FFDHE_8192 if (8192/8 >= ssl->options.minDhKeySz && 8192/8 <= ssl->options.maxDhKeySz) { - ret = TLSX_UseSupportedCurve(extensions, - WOLFSSL_FFDHE_8192, ssl->heap); + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_FFDHE_8192, + ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; } @@ -15869,8 +16125,8 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) #ifdef HAVE_FFDHE_6144 if (6144/8 >= ssl->options.minDhKeySz && 6144/8 <= ssl->options.maxDhKeySz) { - ret = TLSX_UseSupportedCurve(extensions, - WOLFSSL_FFDHE_6144, ssl->heap); + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_FFDHE_6144, + ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; } @@ -15878,8 +16134,8 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) #ifdef HAVE_FFDHE_4096 if (4096/8 >= ssl->options.minDhKeySz && 4096/8 <= ssl->options.maxDhKeySz) { - ret = TLSX_UseSupportedCurve(extensions, - WOLFSSL_FFDHE_4096, ssl->heap); + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_FFDHE_4096, + ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; } @@ -15887,8 +16143,8 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) #ifdef HAVE_FFDHE_3072 if (3072/8 >= ssl->options.minDhKeySz && 3072/8 <= ssl->options.maxDhKeySz) { - ret = TLSX_UseSupportedCurve(extensions, - WOLFSSL_FFDHE_3072, ssl->heap); + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_FFDHE_3072, + ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; } @@ -15896,8 +16152,8 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) #ifdef HAVE_FFDHE_2048 if (2048/8 >= ssl->options.minDhKeySz && 2048/8 <= ssl->options.maxDhKeySz) { - ret = TLSX_UseSupportedCurve(extensions, - WOLFSSL_FFDHE_2048, ssl->heap); + ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_FFDHE_2048, + ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; } @@ -15906,35 +16162,36 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_HAVE_MLKEM) && \ !defined(WOLFSSL_NO_ML_KEM) && defined(WOLFSSL_EXTRA_PQC_HYBRIDS) - if (IsAtLeastTLSv1_3(ssl->version)) { + if (IsAtLeastTLSv1_3(ssl->version) && + TLSX_IsMlKemGroupSupported(ssl->options.side)) { #if !defined(WOLFSSL_NO_ML_KEM_1024) && defined(HAVE_ECC) && \ (defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 521 ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_SECP521R1MLKEM1024, - ssl->heap); + ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; #endif #if !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_ECC) && \ (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 384 ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_SECP384R1MLKEM768, - ssl->heap); + ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; #endif #if !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_CURVE448) && \ ECC_MIN_KEY_SZ <= 448 ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_X448MLKEM768, - ssl->heap); + ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; #endif #if !defined(WOLFSSL_NO_ML_KEM_512) && defined(HAVE_ECC) && \ (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 256 ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_SECP256R1MLKEM512, - ssl->heap); + ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; #endif #if !defined(WOLFSSL_NO_ML_KEM_512) && defined(HAVE_CURVE25519) && \ ECC_MIN_KEY_SZ <= 256 ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_X25519MLKEM512, - ssl->heap); + ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; #endif } @@ -15942,58 +16199,59 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions) #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_HAVE_MLKEM) && \ defined(WOLFSSL_MLKEM_KYBER) - if (IsAtLeastTLSv1_3(ssl->version)) { + if (IsAtLeastTLSv1_3(ssl->version) && + TLSX_IsMlKemGroupSupported(ssl->options.side)) { #ifdef WOLFSSL_KYBER1024 ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_KYBER_LEVEL5, - ssl->heap); + ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; #if defined(HAVE_ECC) && (defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)) && \ ECC_MIN_KEY_SZ <= 521 ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P521_KYBER_LEVEL5, - ssl->heap); + ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; #endif #endif #ifdef WOLFSSL_KYBER768 ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_KYBER_LEVEL3, - ssl->heap); + ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; #if defined(HAVE_ECC) && (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && \ ECC_MIN_KEY_SZ <= 384 ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P384_KYBER_LEVEL3, - ssl->heap); + ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; #endif #if defined(HAVE_ECC) && (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && \ ECC_MIN_KEY_SZ <= 256 ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P256_KYBER_LEVEL3, - ssl->heap); + ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; #endif #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256 ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_X25519_KYBER_LEVEL3, - ssl->heap); + ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; #endif #if defined(HAVE_CURVE448) && ECC_MIN_KEY_SZ <= 448 ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_X448_KYBER_LEVEL3, - ssl->heap); + ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; #endif #endif #ifdef WOLFSSL_KYBER512 ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_KYBER_LEVEL1, - ssl->heap); + ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; #if defined(HAVE_ECC) && (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && \ ECC_MIN_KEY_SZ <= 256 ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P256_KYBER_LEVEL1, - ssl->heap); + ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; #endif #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256 ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_X25519_KYBER_LEVEL1, - ssl->heap); + ssl->heap, ssl->options.side); if (ret != WOLFSSL_SUCCESS) return ret; #endif #endif @@ -16464,11 +16722,9 @@ static int TLSX_EchChangeSNI(WOLFSSL* ssl, TLSX** pEchX, /* if not NULL the semaphore will stop it from being counted */ echX = TLSX_Find(ssl->ctx->extensions, TLSX_ECH); - /* if type is outer change sni to public name */ - if (echX != NULL && - ((WOLFSSL_ECH*)echX->data)->type == ECH_TYPE_OUTER && - (ssl->options.echAccepted || - ((WOLFSSL_ECH*)echX->data)->innerCount == 0)) { + /* if type is outer and this is a real ECH then change sni to public name */ + if (echX != NULL && ssl->echConfigs != NULL && + ((WOLFSSL_ECH*)echX->data)->type == ECH_TYPE_OUTER) { if (ssl->extensions) { serverNameX = TLSX_Find(ssl->extensions, TLSX_SERVER_NAME); @@ -16663,12 +16919,6 @@ static int TLSX_GetSizeWithEch(WOLFSSL* ssl, byte* semaphore, byte msgType, if (echX != NULL) ech = (WOLFSSL_ECH*)echX->data; - /* If ECH won't be written exclude it from the size calculation */ - if (r == 0 && !ssl->options.echAccepted && ech != NULL && - ech->innerCount != 0) { - TURN_ON(semaphore, TLSX_ToSemaphore(echX->type)); - } - /* if encoding, then count encoded form of inner ClientHello. * `semaphore` is in/out so encodable extensions will later be ignored */ if (r == 0 && ech != NULL && ech->type == ECH_TYPE_INNER && @@ -16766,8 +17016,7 @@ int TLSX_GetRequestSize(WOLFSSL* ssl, byte msgType, word32* pLength) } #endif #if defined(HAVE_ECH) - if (ssl->echConfigs != NULL && !ssl->options.disableECH - && msgType == client_hello) { + if (!ssl->options.disableECH && msgType == client_hello) { ret = TLSX_GetSizeWithEch(ssl, semaphore, msgType, &length); if (ret != 0) return ret; @@ -16875,14 +17124,10 @@ static int TLSX_WriteWithEch(WOLFSSL* ssl, byte* output, byte* semaphore, msgType, pOffset); } - /* only write ECH if there is a shot at acceptance */ - if (ret == 0 && echX != NULL && - (ssl->options.echAccepted || - ((WOLFSSL_ECH*)echX->data)->innerCount == 0)) { - if (echX != NULL) { - /* turn off and write it last */ - TURN_OFF(semaphore, TLSX_ToSemaphore(echX->type)); - } + /* write ECH last */ + if (ret == 0 && echX != NULL) { + /* turn off and write it last */ + TURN_OFF(semaphore, TLSX_ToSemaphore(echX->type)); if (ret == 0 && ssl->extensions) { ret = TLSX_Write(ssl->extensions, output + *pOffset, semaphore, @@ -16993,10 +17238,8 @@ int TLSX_WriteRequest(WOLFSSL* ssl, byte* output, byte msgType, word32* pOffset) #endif #endif #if defined(WOLFSSL_TLS13) && defined(HAVE_ECH) - if (ssl->echConfigs != NULL && !ssl->options.disableECH - && msgType == client_hello) { - ret = TLSX_WriteWithEch(ssl, output, semaphore, - msgType, &offset); + if (!ssl->options.disableECH && msgType == client_hello) { + ret = TLSX_WriteWithEch(ssl, output, semaphore, msgType, &offset); if (ret != 0) return ret; } diff --git a/src/tls13.c b/src/tls13.c index 3925e67b8f..aadb2b30a0 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -57,7 +57,6 @@ * WOLFSSL_PSK_ONE_ID: Single PSK identity per connect default: off * WOLFSSL_PSK_MULTI_ID_PER_CS: Multiple PSK IDs per cipher suite default: off * WOLFSSL_PRIORITIZE_PSK: Prioritize PSK over ciphersuite order default: off - * WOLFSSL_PSK_ID_PROTECTION: Enable PSK identity protection default: off * * TLS 1.3 Session Tickets: * WOLFSSL_TICKET_HAVE_ID: Session tickets include ID default: off @@ -4781,7 +4780,7 @@ int SendTls13ClientHello(WOLFSSL* ssl) /* find length of outer and inner */ #if defined(HAVE_ECH) - if (ssl->echConfigs != NULL && !ssl->options.disableECH) { + if (!ssl->options.disableECH) { TLSX* echX = TLSX_Find(ssl->extensions, TLSX_ECH); if (echX == NULL) return WOLFSSL_FATAL_ERROR; @@ -4790,8 +4789,17 @@ int SendTls13ClientHello(WOLFSSL* ssl) if (args->ech == NULL) return WOLFSSL_FATAL_ERROR; - /* only prepare if we have a chance at acceptance */ - if (ssl->options.echAccepted || args->ech->innerCount == 0) { + /* if ECH was rejected by the HRR then the server MUST stop + * decrypting ECH, so send a GREASE ECH for the follow-up CH */ + if (ssl->echConfigs != NULL && !ssl->options.echAccepted && + ssl->options.serverState == + SERVER_HELLO_RETRY_REQUEST_COMPLETE) { + args->ech->state = ECH_WRITE_GREASE; + } + + /* only prepare if we have a chance at acceptance (real ECH only) */ + if (ssl->echConfigs != NULL && + (ssl->options.echAccepted || args->ech->innerCount == 0)) { word32 encodedLen; byte downgrade; @@ -4845,8 +4853,8 @@ int SendTls13ClientHello(WOLFSSL* ssl) /* innerClientHelloLen and padding are based on the * encoded (sealed) inner */ - args->ech->paddingLen += 31 - - ((encodedLen + args->ech->paddingLen - 1) % 32); + args->ech->paddingLen += + ECH_PADDING_TO_32(encodedLen + args->ech->paddingLen); args->ech->innerClientHelloLen = encodedLen + args->ech->paddingLen + args->ech->hpke->Nt; @@ -5097,16 +5105,16 @@ int SendTls13ClientHello(WOLFSSL* ssl) return ret; } #endif - ret = TLSX_FinalizeEch(args->ech, + ret = TLSX_FinalizeEch(ssl, args->ech, args->output + RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ, (word32)(args->sendSz - (RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ))); if (ret != 0) return ret; - - /* innerCount gates HRR re-prep and the server's copyRandom logic. */ - args->ech->innerCount = 1; } + /* Mark CH1 done for any ECH extension (real or GREASE) */ + if (args->ech != NULL) + args->ech->innerCount = 1; #endif #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) @@ -5854,7 +5862,7 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, if (args->extMsgType == hello_retry_request && ((WOLFSSL_ECH*)args->echX->data)->confBuf == NULL) { - /* server rejected ECH, fallback to outer */ + /* server rejected ECH, fall back to outer */ Free_HS_Hashes(ssl->hsHashesEch, ssl->heap); ssl->hsHashesEch = NULL; } @@ -5879,7 +5887,8 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, if (ret != 0) return ret; /* use the inner random for client random */ - if (args->extMsgType != hello_retry_request) { + if (args->extMsgType != hello_retry_request && + ssl->options.echAccepted) { XMEMCPY(ssl->arrays->clientRandom, ssl->arrays->clientRandomInner, RAN_LEN); } @@ -6100,11 +6109,24 @@ static int DoTls13CertificateRequest(WOLFSSL* ssl, const byte* input, return BUFFER_ERROR; /* INVALID_PARAMETER does not map to illegal_parameter in the central * alert path, so emit the alert explicitly before returning. */ - if (ssl->options.connectState < FINISHED_DONE && len > 0) { + if (ssl->options.connectState < FINISHED_DONE) { + /* RFC 8446 Section 4.3.2: in the handshake the context is zero + * length. */ + if (len > 0) { + SendAlert(ssl, alert_fatal, illegal_parameter); + WOLFSSL_ERROR_VERBOSE(INVALID_PARAMETER); + return INVALID_PARAMETER; + } + } +#ifdef WOLFSSL_POST_HANDSHAKE_AUTH + else if (len == 0) { + /* RFC 8446 Section 4.3.2: a post-handshake CertificateRequest context + * MUST be non-empty and unique for the connection. */ SendAlert(ssl, alert_fatal, illegal_parameter); WOLFSSL_ERROR_VERBOSE(INVALID_PARAMETER); return INVALID_PARAMETER; } +#endif #ifdef WOLFSSL_POST_HANDSHAKE_AUTH /* Remember the request context bytes; the CertReqCtx allocation and @@ -6113,6 +6135,18 @@ static int DoTls13CertificateRequest(WOLFSSL* ssl, const byte* input, */ reqCtxLen = len; reqCtxData = input + *inOutIdx; + /* Reject a context that duplicates one still pending on the connection. */ + if (ssl->options.connectState >= FINISHED_DONE) { + CertReqCtx* dup; + for (dup = ssl->certReqCtx; dup != NULL; dup = dup->next) { + if (dup->len == reqCtxLen && + XMEMCMP(&dup->ctx, reqCtxData, reqCtxLen) == 0) { + SendAlert(ssl, alert_fatal, illegal_parameter); + WOLFSSL_ERROR_VERBOSE(INVALID_PARAMETER); + return INVALID_PARAMETER; + } + } + } #endif *inOutIdx += len; @@ -6134,6 +6168,14 @@ static int DoTls13CertificateRequest(WOLFSSL* ssl, const byte* input, } *inOutIdx += len; + /* RFC 8446 Section 4.3.2: the signature_algorithms extension MUST be + * present in a CertificateRequest. */ + if (peerSuites.hashSigAlgoSz == 0) { + SendAlert(ssl, alert_fatal, missing_extension); + WOLFSSL_ERROR_VERBOSE(INVALID_PARAMETER); + return INVALID_PARAMETER; + } + #ifdef WOLFSSL_CERT_SETUP_CB if ((ret = CertSetupCbWrapper(ssl)) != 0) return ret; @@ -6446,6 +6488,37 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 inputSz, } #endif ret = DoClientTicketCheck(ssl, current, ssl->timeout, suite); + #if defined(HAVE_SNI) || defined(HAVE_ALPN) + if (ret == 0) { + /* Decline this PSK if the SNI/ALPN bound to the ticket + * does not match the current connection. RFC 6066 Sect. + * 3 mandates this for SNI; wolfSSL applies the same + * policy to ALPN as defense in depth. Skipping the PSK + * (rather than aborting) lets the server try the next + * candidate or fall back to a full handshake naturally + * without unwinding committed PSK state. ALPN_Select + * has already run earlier in DoTls13ClientHello so the + * negotiated ALPN is available to TicketAlpnHash. */ + byte curHash[TICKET_BINDING_HASH_SZ]; + #ifdef HAVE_SNI + if (TicketSniHash(ssl, curHash) != 0 || + XMEMCMP(curHash, current->it->sniHash, + TICKET_BINDING_HASH_SZ) != 0) { + WOLFSSL_MSG("Ticket SNI mismatch, skipping PSK"); + ret = WOLFSSL_FATAL_ERROR; + } + #endif + #ifdef HAVE_ALPN + if (ret == 0 && + (TicketAlpnHash(ssl, curHash) != 0 || + XMEMCMP(curHash, current->it->alpnHash, + TICKET_BINDING_HASH_SZ) != 0)) { + WOLFSSL_MSG("Ticket ALPN mismatch, skipping PSK"); + ret = WOLFSSL_FATAL_ERROR; + } + #endif + } + #endif if (ret == 0) DoClientTicketFinalize(ssl, current->it, current->sess); if (current->sess_free_cb != NULL) { @@ -6544,20 +6617,8 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 inputSz, } if (current == NULL) { -#ifdef WOLFSSL_PSK_ID_PROTECTION - #ifndef NO_CERTS - if (ssl->buffers.certChainCnt != 0) { - ret = 0; - goto cleanup; - } - #endif - WOLFSSL_ERROR_VERBOSE(BAD_BINDER); - ret = BAD_BINDER; - goto cleanup; -#else ret = 0; goto cleanup; -#endif } *first = (current == ext->data); @@ -6609,11 +6670,11 @@ static int CheckPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, return ret; } - /* Extensions pushed on stack/list and PSK must be last. */ - if (ssl->extensions != ext) { - WOLFSSL_ERROR_VERBOSE(PSK_KEY_ERROR); - return PSK_KEY_ERROR; - } + /* Wire-order check that PSK was the last extension in ClientHello is + * performed in DoTls13ClientHello immediately after TLSX_Parse, since + * post-parse code (e.g. ALPN_Select via TLSX_SetALPN) may legitimately + * prepend new entries to ssl->extensions before this point and would + * otherwise trip a head-of-list check here. */ /* Assume we are going to resume with a pre-shared key. */ ssl->options.resuming = 1; @@ -6664,6 +6725,20 @@ static int CheckPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, } #endif + if (!*usingPSK) { + #ifndef NO_CERTS + if (ssl->buffers.certificate == NULL + #ifdef WOLFSSL_CERT_SETUP_CB + && ssl->ctx->certSetupCb == NULL + #endif + ) + #endif + { + WOLFSSL_ERROR_VERBOSE(BAD_BINDER); + return BAD_BINDER; + } + } + if (*usingPSK) { /* While verifying the selected PSK, we updated the * handshake hash up to the binder bytes in the PSK extensions. @@ -6834,14 +6909,16 @@ static int CheckPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz, TLSX_Remove(&ssl->extensions, TLSX_CERT_WITH_EXTERN_PSK, ssl->heap); ssl->options.certWithExternPsk = 0; #endif -#ifdef WOLFSSL_PSK_ID_PROTECTION #ifndef NO_CERTS - if (ssl->buffers.certChainCnt != 0) + if (ssl->buffers.certificate != NULL + #ifdef WOLFSSL_CERT_SETUP_CB + || ssl->ctx->certSetupCb != NULL + #endif + ) return 0; #endif WOLFSSL_ERROR_VERBOSE(BAD_BINDER); return BAD_BINDER; -#endif } WOLFSSL_LEAVE("CheckPreSharedKeys", ret); @@ -7452,7 +7529,8 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, /* From here on we are a TLS 1.3 ClientHello. */ - /* Client random */ + /* Client random + * ECH Accepted -> This will fill with the innerClientRandom */ XMEMCPY(ssl->arrays->clientRandom, input + args->idx, RAN_LEN); args->idx += RAN_LEN; @@ -7579,6 +7657,25 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, goto exit_dch; } +#if (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)) && \ + defined(HAVE_TLS_EXTENSIONS) + /* RFC 8446 Section 4.2.11: the pre_shared_key extension MUST be the + * last extension in the ClientHello. wolfSSL stores extensions in + * reverse wire order (TLSX_Push prepends), so a well-formed + * ClientHello with PSK leaves PSK at the head of ssl->extensions + * here, before any post-parse code (e.g. ALPN_Select) modifies the + * list. */ + { + TLSX* pskExt = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY); + if (pskExt != NULL && ssl->extensions != pskExt) { + WOLFSSL_MSG("pre_shared_key extension was not last in " + "ClientHello"); + WOLFSSL_ERROR_VERBOSE(PSK_KEY_ERROR); + ERROR_OUT(PSK_KEY_ERROR, exit_dch); + } + } +#endif + #if defined(HAVE_ECH) if (!ssl->options.echProcessingInner && echX != NULL && ((WOLFSSL_ECH*)echX->data)->state == ECH_WRITE_NONE) { @@ -7688,6 +7785,15 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, } #endif +#ifdef HAVE_ALPN + /* Select the ALPN protocol before PSK selection so that the + * selected value is available to the per-PSK SNI/ALPN binding check + * inside CheckPreSharedKeys/DoPreSharedKeys. ALPN_Select itself + * only inspects ssl->extensions and the app callback; it does not + * depend on any state set during PSK validation. */ + if ((ret = ALPN_Select(ssl)) != 0) + goto exit_dch; +#endif #if (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)) && \ defined(HAVE_TLS_EXTENSIONS) ret = CheckPreSharedKeys(ssl, input + args->begin, helloSz, ssl->clSuites, @@ -7729,16 +7835,6 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #endif } -#ifdef HAVE_ALPN - /* With PSK and all other things validated, it's time to - * select the ALPN protocol, if so requested */ - if ((ret = ALPN_Select(ssl)) != 0) - goto exit_dch; -#endif -#if defined(HAVE_SESSION_TICKET) && (defined(HAVE_SNI) || defined(HAVE_ALPN)) - if ((ret = VerifyTicketBinding(ssl)) != 0) - goto exit_dch; -#endif } /* case TLS_ASYNC_BEGIN */ FALL_THROUGH; @@ -12176,8 +12272,16 @@ int SendTls13KeyUpdate(WOLFSSL* ssl) WOLFSSL_ENTER("SendTls13KeyUpdate"); #ifdef WOLFSSL_DTLS13 - if (ssl->options.dtls) + if (ssl->options.dtls) { + /* RFC 9147 Section 4.2.1: do not send a KeyUpdate that would advance + * the sending epoch beyond 2^48-1. */ + if (w64GTE(ssl->dtls13Epoch, + w64From32(DTLS13_EPOCH_MAX_HI32, DTLS13_EPOCH_MAX_LO32))) { + WOLFSSL_MSG("DTLS 1.3 sending epoch at maximum; refusing KeyUpdate"); + return BAD_STATE_E; + } i = Dtls13GetRlHeaderLength(ssl, 1) + DTLS_HANDSHAKE_HEADER_SZ; + } #endif /* WOLFSSL_DTLS13 */ outputSz = OPAQUE8_LEN + MAX_MSG_EXTRA; @@ -12311,7 +12415,17 @@ static int DoTls13KeyUpdate(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #ifdef WOLFSSL_DTLS13 if (ssl->options.dtls) { - w64Increment(&ssl->dtls13PeerEpoch); + /* Increment on a local copy so ssl->dtls13PeerEpoch is left + * untouched when the check fails. */ + w64wrapper newEpoch = ssl->dtls13PeerEpoch; + w64Increment(&newEpoch); + + /* RFC 9147 Section 8: the 2^48-1 cap is sender-only; receivers MUST + * NOT enforce it. Guard only the wrap-to-zero (Section 4.2.1). */ + if (w64IsZero(newEpoch)) + return BAD_STATE_E; + + ssl->dtls13PeerEpoch = newEpoch; ret = Dtls13SetEpochKeys(ssl, ssl->dtls13PeerEpoch, DECRYPT_SIDE_ONLY); if (ret != 0) @@ -13690,8 +13804,7 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, * Only on first inner ClientHello (before HRR), not CH2. */ if (copyRandom) { XMEMCPY(ssl->arrays->clientRandomInner, - ((WOLFSSL_ECH*)echX->data)->innerClientHello + - HANDSHAKE_HEADER_SZ + VERSION_SZ, RAN_LEN); + ssl->arrays->clientRandom, RAN_LEN); } *inOutIdx += size; } @@ -14667,7 +14780,7 @@ int wolfSSL_UseKeyShare(WOLFSSL* ssl, word16 group) (void)group; #else /* Check if the group is supported. */ - if (!TLSX_IsGroupSupported(group)) { + if (!TLSX_IsGroupSupported(group, ssl->options.side)) { WOLFSSL_MSG("Group not supported."); return BAD_FUNC_ARG; } @@ -16103,6 +16216,12 @@ int tls13ShowSecrets(WOLFSSL* ssl, int id, const unsigned char* secret, str = "SERVER_TRAFFIC_SECRET_0"; break; case EXPORTER_SECRET: str = "EXPORTER_SECRET"; break; +#ifdef HAVE_ECH + case ECH_SECRET: + str = "ECH_SECRET"; break; + case ECH_CONFIG: + str = "ECH_CONFIG"; break; +#endif default: #ifdef WOLFSSL_SSLKEYLOGFILE_OUTPUT XFCLOSE(fp); diff --git a/src/x509.c b/src/x509.c index 11b74af7fd..fd87b1da4a 100644 --- a/src/x509.c +++ b/src/x509.c @@ -4213,7 +4213,7 @@ static WOLFSSL_X509* d2i_X509orX509REQ(WOLFSSL_X509** x509, WOLFSSL_ENTER("wolfSSL_X509_d2i"); - if (in != NULL && len != 0 + if (in != NULL && len > 0 #ifndef WOLFSSL_CERT_REQ && req == 0 #else @@ -4523,6 +4523,10 @@ const byte* wolfSSL_X509_get_der(WOLFSSL_X509* x509, int* outSz) if (x509 == NULL || x509->derCert == NULL || outSz == NULL) return NULL; + if (x509->derCert->length > (word32)INT_MAX) { + return NULL; + } + *outSz = (int)x509->derCert->length; return x509->derCert->buffer; } @@ -6114,8 +6118,9 @@ WOLFSSL_X509* wolfSSL_X509_d2i_fp(WOLFSSL_X509** x509, XFILE file) #endif /* OPENSSL_EXTRA && !NO_FILESYSTEM && !NO_STDIO_FILESYSTEM */ -#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) || \ - defined(KEEP_PEER_CERT) || defined(SESSION_CERTS) +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) || \ + defined(WOLFSSL_WPAS_SMALL) || defined(KEEP_PEER_CERT) || \ + defined(SESSION_CERTS) #ifndef NO_FILESYSTEM WOLFSSL_ABI @@ -8835,7 +8840,7 @@ int wolfSSL_i2d_X509(WOLFSSL_X509* x509, unsigned char** out) } der = wolfSSL_X509_get_der(x509, &derSz); - if (der == NULL) { + if (der == NULL || derSz <= 0) { WOLFSSL_LEAVE("wolfSSL_i2d_X509", MEMORY_E); return MEMORY_E; } @@ -11368,7 +11373,7 @@ WOLFSSL_X509_ALGOR* wolfSSL_d2i_X509_ALGOR(WOLFSSL_X509_ALGOR** out, WOLFSSL_ENTER("wolfSSL_d2i_X509_ALGOR"); - if (src == NULL || *src == NULL || len == 0) + if (src == NULL || *src == NULL || len <= 0) return NULL; if (GetAlgoId(*src, &idx, &oid, oidIgnoreType, (word32)len) != 0) diff --git a/tests/api.c b/tests/api.c index 7757f53fc2..69d95d18ca 100644 --- a/tests/api.c +++ b/tests/api.c @@ -235,6 +235,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -2520,6 +2523,28 @@ static int test_wolfSSL_CTX_use_certificate_buffer(void) } /* END test_wolfSSL_CTX_use_certificate_buffer */ +static int test_ProcessBuffer_negative_size(void) +{ + EXPECT_DECLS; +#if !defined(NO_CERTS) && !defined(NO_TLS) && !defined(NO_WOLFSSL_SERVER) && \ + defined(USE_CERT_BUFFERS_2048) && !defined(NO_RSA) + WOLFSSL_CTX* ctx = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); + + ExpectIntEQ(wolfSSL_CTX_use_certificate_buffer(ctx, + server_cert_der_2048, -1, WOLFSSL_FILETYPE_ASN1), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectIntEQ(wolfSSL_CTX_use_certificate_buffer(ctx, + server_cert_der_2048, sizeof_server_cert_der_2048, + WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + static int test_wolfSSL_use_certificate_buffer(void) { EXPECT_DECLS; @@ -11057,6 +11082,12 @@ static int test_wc_PemToDer(void) XMEMSET(&info, 0, sizeof(info)); + { + const byte dummy = 'X'; + ExpectIntEQ(wc_PemToDer(&dummy, -1, CERT_TYPE, &pDer, NULL, + &info, &eccKey), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + } + ExpectIntEQ(ret = load_file(ca_cert, &cert_buf, &cert_sz), 0); ExpectIntEQ(ret = wc_PemToDer(cert_buf, (long int)cert_sz, CERT_TYPE, &pDer, NULL, &info, &eccKey), 0); @@ -11230,6 +11261,10 @@ static int test_wc_KeyPemToDer(void) ExpectIntEQ(wc_KeyPemToDer(cert_buf, 0, (byte*)&cert_der, cert_sz, ""), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + /* Bad arg: NULL der buffer with negative pemSz (NULL-deref guard). */ + ExpectIntEQ(wc_KeyPemToDer(cert_buf, -1, NULL, 0, ""), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + /* Test normal operation */ cert_dersz = cert_sz; /* DER will be smaller than PEM */ ExpectNotNull(cert_der = (byte*)malloc((size_t)cert_dersz)); @@ -13431,7 +13466,7 @@ static int test_wolfSSL_Tls12_Key_Logging_test(void) XMEMSET(buff, 0, sizeof(buff)); while (EXPECT_SUCCESS() && XFGETS(buff, (int)sizeof(buff), fp) != NULL) { - if (0 == strncmp(buff,"CLIENT_RANDOM ", sizeof("CLIENT_RANDOM ")-1)) { + if (0 == XSTRNCMP(buff,"CLIENT_RANDOM ", sizeof("CLIENT_RANDOM ")-1)) { found = 1; break; } @@ -13449,12 +13484,57 @@ static int test_wolfSSL_Tls12_Key_Logging_test(void) #if defined(WOLFSSL_TLS13) && defined(OPENSSL_EXTRA) && \ defined(HAVE_SECRET_CALLBACK) +#ifdef HAVE_ECH +static int test_ech_server_ctx_ready(WOLFSSL_CTX* ctx); +static int test_ech_server_ssl_ready(WOLFSSL* ssl); +static int test_ech_client_ssl_ready(WOLFSSL* ssl); +#endif + static int test_wolfSSL_Tls13_Key_Logging_client_ctx_ready(WOLFSSL_CTX* ctx) { /* set keylog callback */ wolfSSL_CTX_set_keylog_callback(ctx, keyLog_callback); return TEST_SUCCESS; } + +static int test_wolfSSL_Tls13_Key_Logging_server_ctx_ready(WOLFSSL_CTX* ctx) +{ +#ifdef HAVE_ECH + if (test_ech_server_ctx_ready(ctx) != TEST_SUCCESS) + return TEST_FAIL; +#endif + /* set keylog callback */ + wolfSSL_CTX_set_keylog_callback(ctx, keyLog_callback); + return TEST_SUCCESS; +} + +static int test_wolfSSL_Tls13_Key_Logging_client_ssl_ready(WOLFSSL* ssl) +{ +#ifdef HAVE_KEYING_MATERIAL + /* retain arrays so EXPORTER_SECRET is logged */ + wolfSSL_KeepArrays(ssl); +#endif +#ifdef HAVE_ECH + return test_ech_client_ssl_ready(ssl); +#else + (void)ssl; + return TEST_SUCCESS; +#endif +} + +static int test_wolfSSL_Tls13_Key_Logging_server_ssl_ready(WOLFSSL* ssl) +{ +#ifdef HAVE_KEYING_MATERIAL + /* retain arrays so EXPORTER_SECRET is logged */ + wolfSSL_KeepArrays(ssl); +#endif +#ifdef HAVE_ECH + return test_ech_server_ssl_ready(ssl); +#else + (void)ssl; + return TEST_SUCCESS; +#endif +} #endif static int test_wolfSSL_Tls13_Key_Logging_test(void) @@ -13463,7 +13543,7 @@ static int test_wolfSSL_Tls13_Key_Logging_test(void) #if defined(WOLFSSL_TLS13) && defined(OPENSSL_EXTRA) && \ defined(HAVE_SECRET_CALLBACK) /* This test is intended for checking whether keylog callback is called - * in client during TLS handshake between the client and a server. + * in the client/server during a TLS handshake. */ test_ssl_cbf server_cbf; test_ssl_cbf client_cbf; @@ -13473,6 +13553,9 @@ static int test_wolfSSL_Tls13_Key_Logging_test(void) XMEMSET(&client_cbf, 0, sizeof(test_ssl_cbf)); server_cbf.method = wolfTLSv1_3_server_method; /* TLS1.3 */ client_cbf.ctx_ready = &test_wolfSSL_Tls13_Key_Logging_client_ctx_ready; + client_cbf.ssl_ready = &test_wolfSSL_Tls13_Key_Logging_client_ssl_ready; + server_cbf.ctx_ready = &test_wolfSSL_Tls13_Key_Logging_server_ctx_ready; + server_cbf.ssl_ready = &test_wolfSSL_Tls13_Key_Logging_server_ssl_ready; /* clean up keylog file */ ExpectTrue((fp = XFOPEN("./MyKeyLog.txt", "w")) != XBADFILE); @@ -13487,44 +13570,181 @@ static int test_wolfSSL_Tls13_Key_Logging_test(void) /* check if the keylog file exists */ { char buff[300] = {0}; - int found[4] = {0}; - int numfnd = 0; - int i; + int found[7] = {0}; +#ifdef HAVE_ECH + char echRandom[RAN_LEN * 2] = {0}; + char chtsRandom[RAN_LEN * 2] = {0}; +#endif ExpectTrue((fp = XFOPEN("./MyKeyLog.txt", "rb")) != XBADFILE); while (EXPECT_SUCCESS() && XFGETS(buff, (int)sizeof(buff), fp) != NULL) { - if (0 == strncmp(buff, "CLIENT_HANDSHAKE_TRAFFIC_SECRET ", + if (0 == XSTRNCMP(buff, "CLIENT_HANDSHAKE_TRAFFIC_SECRET ", sizeof("CLIENT_HANDSHAKE_TRAFFIC_SECRET ")-1)) { - found[0] = 1; + found[0]++; +#ifdef HAVE_ECH + XMEMCPY(chtsRandom, + buff + sizeof("CLIENT_HANDSHAKE_TRAFFIC_SECRET ")-1, + RAN_LEN * 2); +#endif continue; } - else if (0 == strncmp(buff, "SERVER_HANDSHAKE_TRAFFIC_SECRET ", + else if (0 == XSTRNCMP(buff, "SERVER_HANDSHAKE_TRAFFIC_SECRET ", sizeof("SERVER_HANDSHAKE_TRAFFIC_SECRET ")-1)) { - found[1] = 1; + found[1]++; continue; } - else if (0 == strncmp(buff, "CLIENT_TRAFFIC_SECRET_0 ", + else if (0 == XSTRNCMP(buff, "CLIENT_TRAFFIC_SECRET_0 ", sizeof("CLIENT_TRAFFIC_SECRET_0 ")-1)) { - found[2] = 1; + found[2]++; continue; } - else if (0 == strncmp(buff, "SERVER_TRAFFIC_SECRET_0 ", + else if (0 == XSTRNCMP(buff, "SERVER_TRAFFIC_SECRET_0 ", sizeof("SERVER_TRAFFIC_SECRET_0 ")-1)) { - found[3] = 1; + found[3]++; continue; } +#ifdef HAVE_KEYING_MATERIAL + else if (0 == XSTRNCMP(buff, "EXPORTER_SECRET ", + sizeof("EXPORTER_SECRET ")-1)) { + found[4]++; + continue; + } +#endif +#ifdef HAVE_ECH + else if (0 == XSTRNCMP(buff, "ECH_SECRET ", + sizeof("ECH_SECRET ")-1)) { + found[5]++; + XMEMCPY(echRandom, buff + sizeof("ECH_SECRET ")-1, + RAN_LEN * 2); + continue; + } + else if (0 == XSTRNCMP(buff, "ECH_CONFIG ", + sizeof("ECH_CONFIG ")-1)) { + found[6]++; + continue; + } +#endif + } + if (fp != XBADFILE) + XFCLOSE(fp); + /* the four traffic secrets are derived by both client and server, so + * each label should appear twice with the callback set on both sides */ + ExpectIntEQ(found[0], 2); + ExpectIntEQ(found[1], 2); + ExpectIntEQ(found[2], 2); + ExpectIntEQ(found[3], 2); +#ifdef HAVE_KEYING_MATERIAL + /* both sides retain arrays via KeepArrays, so EXPORTER_SECRET fires + * on each */ + ExpectIntEQ(found[4], 2); +#endif +#ifdef HAVE_ECH + /* both sides also log ECH_SECRET and ECH_CONFIG (seal on client, + * open on server) */ + ExpectIntEQ(found[5], 2); + ExpectIntEQ(found[6], 2); + /* both lines must have been logged */ + ExpectIntNE(echRandom[0], 0); + ExpectIntNE(chtsRandom[0], 0); + /* ECH_SECRET MUST be logged against the outer random while + * CLIENT_HANDSHAKE_TRAFFIC_SECRET uses the inner random when ECH is + * accepted */ + ExpectIntNE(XSTRNCMP(echRandom, chtsRandom, RAN_LEN * 2), 0); +#endif + } +#endif /* OPENSSL_EXTRA && HAVE_SECRET_CALLBACK && WOLFSSL_TLS13 */ + return EXPECT_RESULT(); +} + +/* When ECH is rejected the inner random is never swapped in, so ECH_SECRET and + * CLIENT_HANDSHAKE_TRAFFIC_SECRET are both logged against the outer random. */ +static int test_wolfSSL_Tls13_Key_Logging_ech_rejected(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_TLS13) && defined(OPENSSL_EXTRA) && \ + defined(HAVE_SECRET_CALLBACK) && defined(HAVE_ECH) && \ + defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) + test_ssl_memio_ctx test_ctx; + WOLFSSL_CTX* tempCtx = NULL; + byte badConfig[128]; + word32 badConfigLen = sizeof(badConfig); + XFILE fp = XBADFILE; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + test_ctx.s_cb.method = wolfTLSv1_3_server_method; + test_ctx.c_cb.method = wolfTLSv1_3_client_method; + /* server generates its real ECH config and sets the keylog callback */ + test_ctx.s_cb.ctx_ready = test_wolfSSL_Tls13_Key_Logging_server_ctx_ready; + /* client sets the keylog callback */ + test_ctx.c_cb.ctx_ready = test_wolfSSL_Tls13_Key_Logging_client_ctx_ready; + + ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS); + + /* generate a throwaway ECH config the server cannot decrypt */ + ExpectNotNull(tempCtx = wolfSSL_CTX_new(wolfTLSv1_3_server_method())); + ExpectIntEQ(wolfSSL_CTX_GenerateEchConfig(tempCtx, "ech-public-name.com", + 0, 0, 0), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_GetEchConfigs(tempCtx, badConfig, &badConfigLen), + WOLFSSL_SUCCESS); + wolfSSL_CTX_free(tempCtx); + tempCtx = NULL; + + /* client uses the bad config so the server rejects ECH */ + ExpectIntEQ(wolfSSL_SetEchConfigs(test_ctx.c_ssl, badConfig, badConfigLen), + WOLFSSL_SUCCESS); + /* set inner SNI */ + ExpectIntEQ(wolfSSL_UseSNI(test_ctx.c_ssl, WOLFSSL_SNI_HOST_NAME, + "ech-private-name.com", (word16)XSTRLEN("ech-private-name.com")), + WOLFSSL_SUCCESS); + /* client sends empty cert on rejection, server should not ask for one */ + wolfSSL_set_verify(test_ctx.s_ssl, WOLFSSL_VERIFY_NONE, NULL); + + /* clean up keylog file */ + ExpectTrue((fp = XFOPEN("./MyKeyLog.txt", "w")) != XBADFILE); + if (fp != XBADFILE) { + XFCLOSE(fp); + fp = XBADFILE; + } + + /* handshake fails because ECH was rejected */ + ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS); + ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl), + WOLFSSL_ECH_STATUS_REJECTED); + ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl), + WOLFSSL_ECH_STATUS_REJECTED); + + test_ssl_memio_cleanup(&test_ctx); + + { + char buff[300] = {0}; + char echRandom[RAN_LEN * 2] = {0}; + char chtsRandom[RAN_LEN * 2] = {0}; + + ExpectTrue((fp = XFOPEN("./MyKeyLog.txt", "rb")) != XBADFILE); + while (EXPECT_SUCCESS() && + XFGETS(buff, (int)sizeof(buff), fp) != NULL) { + if (0 == XSTRNCMP(buff, "CLIENT_HANDSHAKE_TRAFFIC_SECRET ", + sizeof("CLIENT_HANDSHAKE_TRAFFIC_SECRET ")-1)) { + XMEMCPY(chtsRandom, + buff + sizeof("CLIENT_HANDSHAKE_TRAFFIC_SECRET ")-1, + RAN_LEN * 2); + } + else if (0 == XSTRNCMP(buff, "ECH_SECRET ", + sizeof("ECH_SECRET ")-1)) { + XMEMCPY(echRandom, buff + sizeof("ECH_SECRET ")-1, RAN_LEN * 2); + } } if (fp != XBADFILE) XFCLOSE(fp); - for (i = 0; i < 4; i++) { - if (found[i] != 0) - numfnd++; - } - ExpectIntEQ(numfnd, 4); + /* both lines must have been logged */ + ExpectIntNE(echRandom[0], 0); + ExpectIntNE(chtsRandom[0], 0); + /* ECH was rejected so both should be the outer random */ + ExpectIntEQ(XSTRNCMP(echRandom, chtsRandom, RAN_LEN * 2), 0); } -#endif /* OPENSSL_EXTRA && HAVE_SECRET_CALLBACK && WOLFSSL_TLS13 */ +#endif return EXPECT_RESULT(); } @@ -14978,7 +15198,8 @@ static int ech_find_extension(byte* buf, word16* idx_p, word16 extType) /* Test the HRR ECH rejection fallback path: * client offers ECH, HRR is triggered, server sends HRR without ECH extension, - * client falls back to the outer transcript, then aborts with ech_required. */ + * client falls back to the outer transcript, then aborts with ech_required. + * encrypted_client_hello should still be present in CH2 */ static int test_wolfSSL_Tls13_ECH_HRR_rejection(void) { EXPECT_DECLS; @@ -15012,7 +15233,25 @@ static int test_wolfSSL_Tls13_ECH_HRR_rejection(void) * outer transcript */ ExpectIntEQ(wolfSSL_NoKeyShares(test_ctx.c_ssl), WOLFSSL_SUCCESS); - /* Handshake must fail: client aborts with ech_required */ + if (EXPECT_SUCCESS()) { + word16 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + + /* One round: client sends CH1, server consumes it and writes HRR */ + (void)test_ssl_memio_do_handshake(&test_ctx, 1, NULL); + + /* Client reads HRR and writes CH2 into s_buff. + * CH2 carries encrypted_client_hello so the connection doesn't + * 'stick out' on the wire. */ + (void)wolfSSL_connect(test_ctx.c_ssl); + ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl), + WOLFSSL_ECH_STATUS_REJECTED); + /* hsHashesEch must have been freed by the HRR rejection code path */ + ExpectNull(test_ctx.c_ssl->hsHashesEch); + + ExpectIntEQ(ech_find_extension(test_ctx.s_buff, &idx, TLSXT_ECH), 0); + } + + /* Finish handshake: client aborts with ech_required */ ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS); ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl), WOLFSSL_ECH_STATUS_REJECTED); @@ -19340,7 +19579,10 @@ static int test_wolfSSL_verify_result(void) WOLFSSL_CTX* ctx = NULL; long result = 0xDEADBEEF; - ExpectIntEQ(WC_NO_ERR_TRACE(WOLFSSL_FAILURE), wolfSSL_get_verify_result(ssl)); + /* A NULL ssl returns a non-zero verify error (not X509_V_OK) so the + * OpenSSL-idiomatic "!= X509_V_OK" check is not fooled. See F-4594. */ + ExpectIntEQ(WOLFSSL_X509_V_ERR_APPLICATION_VERIFICATION, + wolfSSL_get_verify_result(ssl)); ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); ExpectNotNull(ssl = SSL_new(ctx)); @@ -21778,6 +22020,13 @@ static int test_wc_SetIssueBuffer(void) ExpectIntEQ(0, wc_SetIssuerBuffer(&forgedCert, peerCertBuf, peerCertSz)); + /* Negative-size rejection: pin both wc_SetIssuerBuffer and + * wc_SetSubjectBuffer (representatives for the seven wc_Set* siblings). */ + ExpectIntEQ(wc_SetIssuerBuffer(&forgedCert, peerCertBuf, -1), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_SetSubjectBuffer(&forgedCert, peerCertBuf, -1), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + wolfSSL_FreeX509(x509); #endif return EXPECT_RESULT(); @@ -23157,6 +23406,11 @@ static int test_wc_SignCert_cb(void) /* Invalid keyType for ECC signature */ ExpectIntEQ(wc_SignCert_cb(cert.bodySz, cert.sigType, der, FOURK_BUF, ED25519_TYPE, mockSignCb, &signCtx, &rng), BAD_FUNC_ARG); + /* sigType/key family mismatch: an RSA signature OID against an ECC + * key must be rejected with ALGO_ID_E before any signing happens. */ + ExpectIntEQ(wc_SignCert_cb(cert.bodySz, CTC_SHA256wRSA, der, + FOURK_BUF, ECC_TYPE, mockSignCb, &signCtx, &rng), + WC_NO_ERR_TRACE(ALGO_ID_E)); #endif ret = wc_ecc_free(&key); @@ -23243,6 +23497,11 @@ static int test_wc_SignCert_cb(void) /* Invalid keyType */ ExpectIntEQ(wc_SignCert_cb(cert.bodySz, cert.sigType, der, FOURK_BUF, ED448_TYPE, mockSignCb, &signCtx, &rng), BAD_FUNC_ARG); + /* sigType/key family mismatch: an ECDSA signature OID against an RSA + * key must be rejected with ALGO_ID_E before any signing happens. */ + ExpectIntEQ(wc_SignCert_cb(cert.bodySz, CTC_SHA256wECDSA, der, + FOURK_BUF, RSA_TYPE, mockSignCb, &signCtx, &rng), + WC_NO_ERR_TRACE(ALGO_ID_E)); #endif ret = wc_FreeRsaKey(&key); @@ -23607,7 +23866,7 @@ static int test_sk_X509_CRL_decode(void) } #if (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) && !defined(NO_CERTS) && \ - defined(HAVE_CRL) && defined(WOLFSSL_CERT_GEN) + defined(HAVE_CRL) && defined(WOLFSSL_CERT_GEN) && !defined(NO_ASN_TIME) /* Ensure oversized caller-provided revocationDate is rejected. */ static int test_wolfSSL_X509_CRL_add_revoked_oversized_revocation_date(void) { @@ -24182,6 +24441,15 @@ static int test_wc_MakeCRL_max_crlnum(void) ExpectIntGT(crlSz, 0); } + /* --- Negative: a sigType whose family does not match the signing key + * must be rejected before any signature is produced. The RSA key here + * paired with an ECDSA OID must return ALGO_ID_E. --- */ + if (EXPECT_SUCCESS()) { + ExpectIntEQ(wc_SignCRL_ex(tbsBuf, tbsSz, CTC_SHA256wECDSA, + crlBuf, (word32)bufSz, &rsaKey, NULL, &rng), + WC_NO_ERR_TRACE(ALGO_ID_E)); + } + /* --- Decode the CRL and verify CRL number --- */ if (EXPECT_SUCCESS()) { ExpectNotNull(decodedCrl = d2i_X509_CRL(NULL, crlBuf, crlSz)); @@ -25950,6 +26218,9 @@ static int test_wolfSSL_CTX_LoadCRL_largeCRLnum(void) WOLFSSL_SUCCESS); AssertIntEQ(XMEMCMP( crlInfo.crlNumber, exp_crlnum, XSTRLEN(exp_crlnum)), 0); + ExpectIntEQ(wolfSSL_CertManagerGetCRLInfo( + cm, &crlInfo, crlLrgCrlNumBuff, -1, WOLFSSL_FILETYPE_PEM), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); /* Expect to fail loading CRL because of >21 octets CRL number */ ExpectIntEQ(wolfSSL_CertManagerLoadCRLFile(cm, crl_lrgcrlnum2, WOLFSSL_FILETYPE_PEM), @@ -28069,7 +28340,8 @@ static int test_SSL_CIPHER_get_xxx(void) #if defined(WOLF_CRYPTO_CB) && defined(HAVE_IO_TESTS_DEPENDENCIES) && \ (!defined(WOLF_CRYPTO_CB_ONLY_SHA256) && !defined(WOLF_CRYPTO_CB_ONLY_AES) && \ - !defined(WOLF_CRYPTO_CB_ONLY_ECC) && !defined(WOLF_CRYPTO_CB_ONLY_RSA)) + !defined(WOLF_CRYPTO_CB_ONLY_ECC) && !defined(WOLF_CRYPTO_CB_ONLY_RSA) && \ + !defined(WOLF_CRYPTO_CB_ONLY_SHA512)) static int load_pem_key_file_as_der(const char* privKeyFile, DerBuffer** pDer, int* keyFormat) @@ -29073,7 +29345,8 @@ static int test_wc_CryptoCb(void) EXPECT_DECLS; #if defined(WOLF_CRYPTO_CB) && \ (!defined(WOLF_CRYPTO_CB_ONLY_SHA256) && !defined(WOLF_CRYPTO_CB_ONLY_AES) && \ - !defined(WOLF_CRYPTO_CB_ONLY_ECC) && !defined(WOLF_CRYPTO_CB_ONLY_RSA)) + !defined(WOLF_CRYPTO_CB_ONLY_ECC) && !defined(WOLF_CRYPTO_CB_ONLY_RSA) && \ + !defined(WOLF_CRYPTO_CB_ONLY_SHA512)) /* TODO: Add crypto callback API tests */ #ifdef HAVE_IO_TESTS_DEPENDENCIES @@ -31493,8 +31766,9 @@ static int test_session_ticket_hs_update(void) /** - * Make sure we don't send RSA Signature Hash Algorithms in the - * CertificateRequest when we don't have any such ciphers set. + * Make sure the CertificateRequest advertises ECDSA signature hash algorithms + * for an ECDHE-ECDSA server, and also includes RSA algorithms so that RSA + * clients can authenticate (the certificate_type advertised covers both). * @return EXPECT_RESULT() */ static int test_certreq_sighash_algos(void) @@ -31555,17 +31829,24 @@ static int test_certreq_sighash_algos(void) idx += OPAQUE16_LEN; maxIdx = idx + (int)len; for (; idx < maxIdx && EXPECT_SUCCESS(); idx += OPAQUE16_LEN) { - if (test_ctx.c_buff[idx+1] == ED25519_SA_MINOR || - test_ctx.c_buff[idx+1] == ED448_SA_MINOR || - test_ctx.c_buff[idx+1] == - ECDSA_BRAINPOOLP256R1TLS13_SHA256_MINOR || - test_ctx.c_buff[idx+1] == - ECDSA_BRAINPOOLP384R1TLS13_SHA384_MINOR || - test_ctx.c_buff[idx+1] == - ECDSA_BRAINPOOLP512R1TLS13_SHA512_MINOR) - ExpectIntEQ(test_ctx.c_buff[idx], NEW_SA_MAJOR); - else - ExpectIntEQ(test_ctx.c_buff[idx+1], ecc_dsa_sa_algo); + byte first = test_ctx.c_buff[idx]; + byte second = test_ctx.c_buff[idx+1]; + if (second == ED25519_SA_MINOR || + second == ED448_SA_MINOR || + second == ECDSA_BRAINPOOLP256R1TLS13_SHA256_MINOR || + second == ECDSA_BRAINPOOLP384R1TLS13_SHA384_MINOR || + second == ECDSA_BRAINPOOLP512R1TLS13_SHA512_MINOR) { + ExpectIntEQ(first, NEW_SA_MAJOR); + } + else { + /* ECDHE-ECDSA suites advertise ECDSA so the negotiated + * cipher can be used, and also RSA / RSA-PSS so RSA + * clients can authenticate via mutual auth. Note that + * RSA-PSS is encoded with sigAlgo first then mac. */ + ExpectTrue(second == ecc_dsa_sa_algo || + second == rsa_sa_algo || + first == rsa_pss_sa_algo); + } } break; } @@ -33378,7 +33659,8 @@ static int test_DhAgree_rejects_p_minus_1(void) static int test_ed448_rejects_identity_key(void) { EXPECT_DECLS; -#if defined(HAVE_ED448) && !defined(HAVE_SELFTEST) && \ +#if defined(HAVE_ED448) && defined(HAVE_ED448_VERIFY) && \ + defined(HAVE_ED448_KEY_IMPORT) && !defined(HAVE_SELFTEST) && \ (!defined(HAVE_FIPS) || FIPS_VERSION_GE(7,0)) ed448_key key; byte identity[ED448_PUB_KEY_SIZE]; @@ -34636,7 +34918,7 @@ TEST_CASE testCases[] = { /* OpenSSL sk_X509_CRL API test */ TEST_DECL(test_sk_X509_CRL_decode), #if (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) && !defined(NO_CERTS) && \ - defined(HAVE_CRL) && defined(WOLFSSL_CERT_GEN) + defined(HAVE_CRL) && defined(WOLFSSL_CERT_GEN) && !defined(NO_ASN_TIME) TEST_DECL(test_wolfSSL_X509_CRL_add_revoked_oversized_revocation_date), #endif #if (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) && !defined(NO_CERTS) && \ @@ -34859,6 +35141,7 @@ TEST_CASE testCases[] = { TEST_DECL(test_wolfSSL_CTX_use_certificate), TEST_DECL(test_wolfSSL_CTX_use_certificate_file), TEST_DECL(test_wolfSSL_CTX_use_certificate_buffer), + TEST_DECL(test_ProcessBuffer_negative_size), TEST_DECL(test_wolfSSL_use_certificate_buffer), TEST_DECL(test_wolfSSL_CTX_use_PrivateKey_file), TEST_DECL(test_wolfSSL_CTX_use_RSAPrivateKey_file), @@ -34935,6 +35218,7 @@ TEST_CASE testCases[] = { TEST_DECL(test_wolfSSL_Tls12_Key_Logging_test), /* Can't memory test as server hangs. */ TEST_DECL(test_wolfSSL_Tls13_Key_Logging_test), + TEST_DECL(test_wolfSSL_Tls13_Key_Logging_ech_rejected), TEST_DECL(test_wolfSSL_Tls13_postauth), TEST_DECL(test_wolfSSL_set_ecdh_auto), TEST_DECL(test_wolfSSL_CTX_set_ecdh_auto), @@ -34979,6 +35263,9 @@ TEST_CASE testCases[] = { TEST_DECL(test_TLSX_SNI_GetSize_overflow), TEST_DECL(test_TLSX_ECH_msg_type_validation), TEST_DECL(test_TLSX_SRTP_msg_type_validation), + TEST_DECL(test_TLSX_ALPN_server_response_count), + TEST_DECL(test_TLSX_SupportedCurve_empty_or_unsupported), + TEST_DECL(test_TLSX_PointFormat_uncompressed_required), TEST_DECL(test_wolfSSL_wolfSSL_UseSecureRenegotiation), TEST_DECL(test_wolfSSL_clear_secure_renegotiation), TEST_DECL(test_wolfSSL_SCR_Reconnect), @@ -35109,6 +35396,9 @@ TEST_CASE testCases[] = { TEST_DECL(test_revoked_loaded_int_cert), TEST_DTLS_DECLS, TEST_DTLS13_DECLS, + TEST_SSL_CERT_DECLS, + TEST_SSL_PK_DECLS, + TEST_SSL_EXT_DECLS, TEST_DECL(test_tls_multi_handshakes_one_record), TEST_DECL(test_write_dup), TEST_DECL(test_write_dup_want_write), @@ -35124,6 +35414,7 @@ TEST_CASE testCases[] = { TEST_DECL(test_wolfSSL_inject), TEST_DECL(test_ocsp_status_callback), TEST_DECL(test_ocsp_basic_verify), + TEST_DECL(test_ocsp_ancestor_responder_rejected), TEST_DECL(test_ocsp_responder_keyhash_binding), TEST_DECL(test_ocsp_response_parsing), TEST_DECL(test_ocsp_certid_enc_dec), diff --git a/tests/api/create_ocsp_test_blobs.py b/tests/api/create_ocsp_test_blobs.py index 92cd0cba87..6a55de9837 100644 --- a/tests/api/create_ocsp_test_blobs.py +++ b/tests/api/create_ocsp_test_blobs.py @@ -421,6 +421,23 @@ if __name__ == '__main__': 'name': 'resp_bad_embedded_cert' }, { + # intermediate1 signs OCSP for its subordinate server1 + 'response_status': 0, + 'signature_algorithm': signature_algorithm(), + 'responder_by_name': True, + 'responder_cert': WOLFSSL_OCSP_CERT_PATH + 'intermediate1-ca-cert.pem', + 'responses': [ + { + 'issuer_cert': WOLFSSL_OCSP_CERT_PATH + 'intermediate1-ca-cert.pem', + 'serial': 0x05, + 'status': CERT_GOOD + } + ], + 'responder_key': WOLFSSL_OCSP_CERT_PATH + 'intermediate1-ca-key.pem', + 'name': 'resp_server1_cert' + }, + { + # Ancestor-issued responder; rejected by RFC 6960 4.2.2.2 enforcement 'response_status': 0, 'signature_algorithm': signature_algorithm(), 'certs_path': [WOLFSSL_OCSP_CERT_PATH + 'ocsp-responder-cert.pem'], @@ -433,7 +450,7 @@ if __name__ == '__main__': } ], 'responder_key': WOLFSSL_OCSP_CERT_PATH + 'ocsp-responder-key.pem', - 'name': 'resp_server1_cert' + 'name': 'resp_server1_cert_ancestor_responder' }, { 'response_status': 0, @@ -557,6 +574,7 @@ if __name__ == '__main__': add_certificate(WOLFSSL_OCSP_CERT_PATH + '../server-cert.pem', f) add_certificate(WOLFSSL_OCSP_CERT_PATH + 'intermediate1-ca-cert.pem', f) add_certificate(WOLFSSL_OCSP_CERT_PATH + 'imposter-root-ca-cert.pem', f) + add_certificate(WOLFSSL_OCSP_CERT_PATH + 'server1-cert.pem', f) br = create_bad_response({ 'response_status': 0, 'responder_by_key': True, diff --git a/tests/api/include.am b/tests/api/include.am index 7ad64d3e63..3d204763c6 100644 --- a/tests/api/include.am +++ b/tests/api/include.am @@ -55,6 +55,9 @@ tests_unit_test_SOURCES += tests/api/test_lms_xmss.c # TLS Protocol tests_unit_test_SOURCES += tests/api/test_dtls.c tests_unit_test_SOURCES += tests/api/test_dtls13.c +tests_unit_test_SOURCES += tests/api/test_ssl_cert.c +tests_unit_test_SOURCES += tests/api/test_ssl_pk.c +tests_unit_test_SOURCES += tests/api/test_ssl_ext.c # TLS Feature tests_unit_test_SOURCES += tests/api/test_ocsp.c tests_unit_test_SOURCES += tests/api/test_evp.c @@ -163,6 +166,9 @@ EXTRA_DIST += tests/api/test_signature.h EXTRA_DIST += tests/api/test_lms_xmss.h EXTRA_DIST += tests/api/test_dtls.h EXTRA_DIST += tests/api/test_dtls13.h +EXTRA_DIST += tests/api/test_ssl_cert.h +EXTRA_DIST += tests/api/test_ssl_pk.h +EXTRA_DIST += tests/api/test_ssl_ext.h EXTRA_DIST += tests/api/test_ocsp.h EXTRA_DIST += tests/api/test_ocsp_test_blobs.h EXTRA_DIST += tests/api/create_ocsp_test_blobs.py diff --git a/tests/api/test_aes.c b/tests/api/test_aes.c index b5f90a89cc..65769d27db 100644 --- a/tests/api/test_aes.c +++ b/tests/api/test_aes.c @@ -7730,6 +7730,15 @@ int test_wc_AesEaxStream(void) ExpectIntEQ(wc_AesEaxEncryptFinal(NULL, tagBuf, WC_AES_BLOCK_SIZE), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + /* wc_AesEaxEncryptFinal authTagSz below WOLFSSL_MIN_AUTH_TAG_SZ must be + * rejected, even on an otherwise valid context */ + ExpectIntEQ(wc_AesEaxInit(&eax, key1, sizeof(key1), + nonce1, sizeof(nonce1), NULL, 0), 0); + ExpectIntEQ(wc_AesEaxEncryptFinal(&eax, tagBuf, + WOLFSSL_MIN_AUTH_TAG_SZ - 1), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_AesEaxFree(&eax), 0); + /* wc_AesEaxDecryptFinal NULL eax */ ExpectIntEQ(wc_AesEaxDecryptFinal(NULL, tag1, sizeof(tag1)), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); diff --git a/tests/api/test_arc4.c b/tests/api/test_arc4.c index 11bd20d671..3fe4d57eae 100644 --- a/tests/api/test_arc4.c +++ b/tests/api/test_arc4.c @@ -104,6 +104,43 @@ int test_wc_Arc4Process(void) } /* END test_wc_Arc4Process */ +/* + * Regression test for issue 5378: wc_Arc4Process must refuse to run unless a + * key has been configured with wc_Arc4SetKey(), both before SetKey and after + * Free. Otherwise the keystream is all-zero and ARC4 silently copies the + * plaintext into the ciphertext. + */ +int test_wc_Arc4Process_no_key(void) +{ + EXPECT_DECLS; +#ifndef NO_RC4 + Arc4 arc4; + const char* key = "\x01\x23\x45\x67\x89\xab\xcd\xef"; + int keyLen = 8; + const char* input = "\x01\x23\x45\x67\x89\xab\xcd\xef"; + byte cipher[8]; + + XMEMSET(&arc4, 0, sizeof(arc4)); + XMEMSET(cipher, 0, sizeof(cipher)); + + /* Processing without a key after init must fail, not silently copy. */ + ExpectIntEQ(wc_Arc4Init(&arc4, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_Arc4Process(&arc4, cipher, (byte*)input, (word32)keyLen), + WC_NO_ERR_TRACE(MISSING_KEY)); + + /* After a key is set, processing succeeds. */ + ExpectIntEQ(wc_Arc4SetKey(&arc4, (byte*)key, (word32)keyLen), 0); + ExpectIntEQ(wc_Arc4Process(&arc4, cipher, (byte*)input, (word32)keyLen), 0); + + /* After free, the keyed state is cleared and processing must fail again. */ + wc_Arc4Free(&arc4); + ExpectIntEQ(wc_Arc4Process(&arc4, cipher, (byte*)input, (word32)keyLen), + WC_NO_ERR_TRACE(MISSING_KEY)); +#endif + return EXPECT_RESULT(); + +} /* END test_wc_Arc4Process_no_key */ + #include diff --git a/tests/api/test_arc4.h b/tests/api/test_arc4.h index f79104d9c6..28075e3bc9 100644 --- a/tests/api/test_arc4.h +++ b/tests/api/test_arc4.h @@ -26,11 +26,13 @@ int test_wc_Arc4SetKey(void); int test_wc_Arc4Process(void); +int test_wc_Arc4Process_no_key(void); int test_wc_Arc4_MonteCarlo(void); #define TEST_ARC4_DECLS \ TEST_DECL_GROUP("arc4", test_wc_Arc4SetKey), \ TEST_DECL_GROUP("arc4", test_wc_Arc4Process), \ + TEST_DECL_GROUP("arc4", test_wc_Arc4Process_no_key), \ TEST_DECL_GROUP("arc4", test_wc_Arc4_MonteCarlo) #endif /* WOLFCRYPT_TEST_ARC4_H */ diff --git a/tests/api/test_asn.c b/tests/api/test_asn.c index ce4eea1487..19906ff02b 100644 --- a/tests/api/test_asn.c +++ b/tests/api/test_asn.c @@ -1318,6 +1318,61 @@ int test_wc_DecodeRsaPssParams(void) &hash, &mgf, &saltLen), WC_NO_ERR_TRACE(ASN_PARSE_E)); } + /* --- Test 9: trailerField = 1 (trailerFieldBC) => valid in all modes --- */ + /* SEQUENCE { [3] CONSTRUCTED { INTEGER 1 } } = 30 05 a3 03 02 01 01 */ + { + static const byte trailerValid[] = { + 0x30, 0x05, 0xa3, 0x03, 0x02, 0x01, 0x01 + }; + hash = WC_HASH_TYPE_NONE; + mgf = 0; + saltLen = 0; + ExpectIntEQ(wc_DecodeRsaPssParams(trailerValid, + (word32)sizeof(trailerValid), &hash, &mgf, &saltLen), 0); + ExpectIntEQ((int)hash, (int)WC_HASH_TYPE_SHA); + ExpectIntEQ(mgf, WC_MGF1SHA1); + ExpectIntEQ(saltLen, 20); + } + +#ifndef WOLFSSL_NO_ASN_STRICT + /* --- Test 10: trailerField = 2 => ASN_PARSE_E (strict mode) --- */ + /* RFC 8017 A.2.3: trailerField SHALL be trailerFieldBC(1). */ + /* SEQUENCE { [3] CONSTRUCTED { INTEGER 2 } } = 30 05 a3 03 02 01 02 */ + { + static const byte trailerTwo[] = { + 0x30, 0x05, 0xa3, 0x03, 0x02, 0x01, 0x02 + }; + ExpectIntEQ(wc_DecodeRsaPssParams(trailerTwo, + (word32)sizeof(trailerTwo), &hash, &mgf, &saltLen), + WC_NO_ERR_TRACE(ASN_PARSE_E)); + } + + /* --- Test 11: trailerField = 0 => ASN_PARSE_E (strict mode) --- */ + /* SEQUENCE { [3] CONSTRUCTED { INTEGER 0 } } = 30 05 a3 03 02 01 00 */ + { + static const byte trailerZero[] = { + 0x30, 0x05, 0xa3, 0x03, 0x02, 0x01, 0x00 + }; + ExpectIntEQ(wc_DecodeRsaPssParams(trailerZero, + (word32)sizeof(trailerZero), &hash, &mgf, &saltLen), + WC_NO_ERR_TRACE(ASN_PARSE_E)); + } + + /* --- Test 12: trailerField = 256 (multi-byte INTEGER) => ASN_PARSE_E --- + * Exercises the 2-byte integer branch in GetInteger16Bit (non-template) + * and the len==2 case of ASN_DATA_TYPE_WORD16 (template path). + * SEQUENCE { [3] CONSTRUCTED { INTEGER 256 } } = 30 06 a3 04 02 02 01 00 + */ + { + static const byte trailerMultiByte[] = { + 0x30, 0x06, 0xa3, 0x04, 0x02, 0x02, 0x01, 0x00 + }; + ExpectIntEQ(wc_DecodeRsaPssParams(trailerMultiByte, + (word32)sizeof(trailerMultiByte), &hash, &mgf, &saltLen), + WC_NO_ERR_TRACE(ASN_PARSE_E)); + } +#endif /* !WOLFSSL_NO_ASN_STRICT */ + #endif /* WC_RSA_PSS && !NO_RSA && !NO_ASN */ return EXPECT_RESULT(); } diff --git a/tests/api/test_certman.c b/tests/api/test_certman.c index 1c73e64a73..66ca862167 100644 --- a/tests/api/test_certman.c +++ b/tests/api/test_certman.c @@ -2933,253 +2933,178 @@ int test_wolfSSL_CertManagerCheckOCSPResponse(void) * - Run responder with * openssl ocsp -port 9999 -ndays 9999 * -index certs/ocsp/index-intermediate1-ca-issued-certs.txt - * -rsigner certs/ocsp/ocsp-responder-cert.pem - * -rkey certs/ocsp/ocsp-responder-key.pem + * -rsigner certs/ocsp/intermediate1-ca-cert.pem + * -rkey certs/ocsp/intermediate1-ca-key.pem * -CA certs/ocsp/intermediate1-ca-cert.pem * - Run client with * openssl ocsp -host 127.0.0.1:9999 -respout resp.out * -issuer certs/ocsp/intermediate1-ca-cert.pem * -cert certs/ocsp/server1-cert.pem * -CAfile certs/ocsp/root-ca-cert.pem -noverify - * - Select the response packet in Wireshark, and export it using - * "File->Export Packet Dissection->As "C" Arrays". Select "Selected - * packets only". After importing into the editor, remove the initial - * ~148 bytes of header, ending with the Content-Length and the \r\n\r\n. + * - Convert resp.out to a C array (e.g. xxd -i -c 12 resp.out) and paste + * the bytes below. */ static const byte response[] = { - 0x30, 0x82, 0x07, 0x40, /* ....0..@ */ - 0x0a, 0x01, 0x00, 0xa0, 0x82, 0x07, 0x39, 0x30, /* ......90 */ - 0x82, 0x07, 0x35, 0x06, 0x09, 0x2b, 0x06, 0x01, /* ..5..+.. */ - 0x05, 0x05, 0x07, 0x30, 0x01, 0x01, 0x04, 0x82, /* ...0.... */ - 0x07, 0x26, 0x30, 0x82, 0x07, 0x22, 0x30, 0x82, /* .&0.."0. */ - 0x01, 0x40, 0xa1, 0x81, 0xa1, 0x30, 0x81, 0x9e, /* .@...0.. */ - 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, /* 1.0...U. */ - 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, /* ...US1.0 */ - 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, /* ...U.... */ - 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, /* Washingt */ - 0x6f, 0x6e, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, /* on1.0... */ - 0x55, 0x04, 0x07, 0x0c, 0x07, 0x53, 0x65, 0x61, /* U....Sea */ - 0x74, 0x74, 0x6c, 0x65, 0x31, 0x10, 0x30, 0x0e, /* ttle1.0. */ - 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x07, 0x77, /* ..U....w */ - 0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, 0x31, 0x14, /* olfSSL1. */ - 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, /* 0...U... */ - 0x0b, 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x65, /* .Enginee */ - 0x72, 0x69, 0x6e, 0x67, 0x31, 0x1f, 0x30, 0x1d, /* ring1.0. */ - 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x77, /* ..U....w */ - 0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, 0x20, 0x4f, /* olfSSL O */ - 0x43, 0x53, 0x50, 0x20, 0x52, 0x65, 0x73, 0x70, /* CSP Resp */ - 0x6f, 0x6e, 0x64, 0x65, 0x72, 0x31, 0x1f, 0x30, /* onder1.0 */ - 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, /* ...*.H.. */ - 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6e, /* ......in */ - 0x66, 0x6f, 0x40, 0x77, 0x6f, 0x6c, 0x66, 0x73, /* fo@wolfs */ - 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x18, 0x0f, /* sl.com.. */ - 0x32, 0x30, 0x32, 0x34, 0x31, 0x32, 0x32, 0x30, /* 20241220 */ - 0x31, 0x37, 0x30, 0x37, 0x30, 0x34, 0x5a, 0x30, /* 170704Z0 */ - 0x64, 0x30, 0x62, 0x30, 0x3a, 0x30, 0x09, 0x06, /* d0b0:0.. */ - 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, /* .+...... */ - 0x04, 0x14, 0x71, 0x4d, 0x82, 0x23, 0x40, 0x59, /* ..qM.#@Y */ - 0xc0, 0x96, 0xa1, 0x37, 0x43, 0xfa, 0x31, 0xdb, /* ...7C.1. */ - 0xba, 0xb1, 0x43, 0x18, 0xda, 0x04, 0x04, 0x14, /* ..C..... */ - 0x83, 0xc6, 0x3a, 0x89, 0x2c, 0x81, 0xf4, 0x02, /* ..:.,... */ - 0xd7, 0x9d, 0x4c, 0xe2, 0x2a, 0xc0, 0x71, 0x82, /* ..L.*.q. */ - 0x64, 0x44, 0xda, 0x0e, 0x02, 0x01, 0x05, 0x80, /* dD...... */ - 0x00, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x34, 0x31, /* ...20241 */ - 0x32, 0x32, 0x30, 0x31, 0x37, 0x30, 0x37, 0x30, /* 22017070 */ - 0x34, 0x5a, 0xa0, 0x11, 0x18, 0x0f, 0x32, 0x30, /* 4Z....20 */ - 0x35, 0x32, 0x30, 0x35, 0x30, 0x36, 0x31, 0x37, /* 52050617 */ - 0x30, 0x37, 0x30, 0x34, 0x5a, 0xa1, 0x23, 0x30, /* 0704Z.#0 */ - 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2b, 0x06, 0x01, /* !0...+.. */ - 0x05, 0x05, 0x07, 0x30, 0x01, 0x02, 0x04, 0x12, /* ...0.... */ - 0x04, 0x10, 0x12, 0x7c, 0x27, 0xbd, 0x22, 0x28, /* ...|'."( */ - 0x5e, 0x62, 0x81, 0xed, 0x6d, 0x2c, 0x2d, 0x59, /* ^b..m,-Y */ - 0x42, 0xd7, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, /* B.0...*. */ - 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, /* H....... */ - 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x6c, 0xce, /* ......l. */ - 0xa8, 0xe8, 0xfe, 0xaf, 0x33, 0xe2, 0xce, 0x4e, /* ....3..N */ - 0x63, 0x8d, 0x61, 0x16, 0x0f, 0x70, 0xb2, 0x0c, /* c.a..p.. */ - 0x9a, 0xe3, 0x01, 0xd5, 0xca, 0xe5, 0x9b, 0x70, /* .......p */ - 0x81, 0x6f, 0x94, 0x09, 0xe8, 0x88, 0x98, 0x1a, /* .o...... */ - 0x67, 0xa0, 0xc2, 0xe7, 0x8f, 0x9b, 0x5f, 0x13, /* g....._. */ - 0x17, 0x8d, 0x93, 0x8c, 0x31, 0x61, 0x7d, 0x72, /* ....1a}r */ - 0x34, 0xbd, 0x21, 0x48, 0xca, 0xb2, 0xc9, 0xae, /* 4.!H.... */ - 0x28, 0x5f, 0x97, 0x19, 0xcb, 0xdf, 0xed, 0xd4, /* (_...... */ - 0x6e, 0x89, 0x30, 0x89, 0x11, 0xd1, 0x05, 0x08, /* n.0..... */ - 0x81, 0xe9, 0xa7, 0xba, 0xf7, 0x16, 0x0c, 0xbe, /* ........ */ - 0x48, 0x2e, 0xc0, 0x05, 0xac, 0x90, 0xc2, 0x35, /* H......5 */ - 0xce, 0x6c, 0x94, 0x5d, 0x2b, 0xad, 0x4f, 0x19, /* .l.]+.O. */ - 0xea, 0x7b, 0xd9, 0x4f, 0x49, 0x20, 0x8d, 0x98, /* .{.OI .. */ - 0xa9, 0xe4, 0x53, 0x6d, 0xca, 0x34, 0xdb, 0x4a, /* ..Sm.4.J */ - 0x28, 0xb3, 0x33, 0xfb, 0xfd, 0xcc, 0x4b, 0xfa, /* (.3...K. */ - 0xdb, 0x70, 0xe1, 0x96, 0xc8, 0xd4, 0xf1, 0x85, /* .p...... */ - 0x99, 0xaf, 0x06, 0xeb, 0xfd, 0x96, 0x21, 0x86, /* ......!. */ - 0x81, 0xee, 0xcf, 0xd2, 0xf4, 0x83, 0xc9, 0x1d, /* ........ */ - 0x8f, 0x42, 0xd1, 0xc1, 0xbc, 0x50, 0x0a, 0xfb, /* .B...P.. */ - 0x95, 0x39, 0x4c, 0x36, 0xa8, 0xfe, 0x2b, 0x8e, /* .9L6..+. */ - 0xc5, 0xb5, 0xe0, 0xab, 0xdb, 0xc0, 0xbf, 0x1d, /* ........ */ - 0x35, 0x4d, 0xc0, 0x52, 0xfb, 0x08, 0x04, 0x4c, /* 5M.R...L */ - 0x98, 0xf0, 0xb5, 0x5b, 0xff, 0x99, 0x74, 0xce, /* ...[..t. */ - 0xb7, 0xc9, 0xe3, 0xe5, 0x70, 0x2e, 0xd3, 0x1d, /* ....p... */ - 0x46, 0x38, 0xf9, 0x51, 0x17, 0x73, 0xd1, 0x08, /* F8.Q.s.. */ - 0x8d, 0x3d, 0x12, 0x47, 0xd0, 0x66, 0x77, 0xaf, /* .=.G.fw. */ - 0xfd, 0x4c, 0x75, 0x1f, 0xe9, 0x6c, 0xf4, 0x5a, /* .Lu..l.Z */ - 0xde, 0xec, 0x37, 0xc7, 0xc4, 0x0a, 0xbe, 0x91, /* ..7..... */ - 0xbc, 0x05, 0x08, 0x86, 0x47, 0x30, 0x2a, 0xc6, /* ....G0*. */ - 0x85, 0x4b, 0x55, 0x6c, 0xef, 0xdf, 0x2d, 0x5a, /* .KUl..-Z */ - 0xf7, 0x5b, 0xb5, 0xba, 0xed, 0x38, 0xb0, 0xcb, /* .[...8.. */ - 0xeb, 0x7e, 0x84, 0x3a, 0x69, 0x2c, 0xa0, 0x82, /* .~.:i,.. */ - 0x04, 0xc6, 0x30, 0x82, 0x04, 0xc2, 0x30, 0x82, /* ..0...0. */ - 0x04, 0xbe, 0x30, 0x82, 0x03, 0xa6, 0xa0, 0x03, /* ..0..... */ - 0x02, 0x01, 0x02, 0x02, 0x01, 0x04, 0x30, 0x0d, /* ......0. */ - 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, /* ..*.H... */ - 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0x97, /* .....0.. */ - 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, /* 1.0...U. */ - 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, /* ...US1.0 */ - 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, /* ...U.... */ - 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, /* Washingt */ - 0x6f, 0x6e, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, /* on1.0... */ - 0x55, 0x04, 0x07, 0x0c, 0x07, 0x53, 0x65, 0x61, /* U....Sea */ - 0x74, 0x74, 0x6c, 0x65, 0x31, 0x10, 0x30, 0x0e, /* ttle1.0. */ - 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x07, 0x77, /* ..U....w */ - 0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, 0x31, 0x14, /* olfSSL1. */ - 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, /* 0...U... */ - 0x0b, 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x65, /* .Enginee */ - 0x72, 0x69, 0x6e, 0x67, 0x31, 0x18, 0x30, 0x16, /* ring1.0. */ - 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0f, 0x77, /* ..U....w */ - 0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, 0x20, 0x72, /* olfSSL r */ - 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1f, /* oot CA1. */ - 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, /* 0...*.H. */ - 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, /* .......i */ - 0x6e, 0x66, 0x6f, 0x40, 0x77, 0x6f, 0x6c, 0x66, /* nfo@wolf */ - 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x30, /* ssl.com0 */ - 0x1e, 0x17, 0x0d, 0x32, 0x34, 0x31, 0x32, 0x31, /* ...24121 */ - 0x38, 0x32, 0x31, 0x32, 0x35, 0x33, 0x31, 0x5a, /* 8212531Z */ - 0x17, 0x0d, 0x32, 0x37, 0x30, 0x39, 0x31, 0x34, /* ..270914 */ - 0x32, 0x31, 0x32, 0x35, 0x33, 0x31, 0x5a, 0x30, /* 212531Z0 */ - 0x81, 0x9e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, /* ..1.0... */ - 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, /* U....US1 */ - 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, /* .0...U.. */ - 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, /* ..Washin */ - 0x67, 0x74, 0x6f, 0x6e, 0x31, 0x10, 0x30, 0x0e, /* gton1.0. */ - 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x07, 0x53, /* ..U....S */ - 0x65, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x31, 0x10, /* eattle1. */ - 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, /* 0...U... */ - 0x07, 0x77, 0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, /* .wolfSSL */ - 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, /* 1.0...U. */ - 0x0b, 0x0c, 0x0b, 0x45, 0x6e, 0x67, 0x69, 0x6e, /* ...Engin */ - 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x31, 0x1f, /* eering1. */ - 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, /* 0...U... */ - 0x16, 0x77, 0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, /* .wolfSSL */ - 0x20, 0x4f, 0x43, 0x53, 0x50, 0x20, 0x52, 0x65, /* OCSP Re */ - 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x65, 0x72, 0x31, /* sponder1 */ - 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, /* .0...*.H */ - 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, /* ........ */ - 0x69, 0x6e, 0x66, 0x6f, 0x40, 0x77, 0x6f, 0x6c, /* info@wol */ - 0x66, 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, /* fssl.com */ - 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, /* 0.."0... */ - 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, /* *.H..... */ - 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, /* ........ */ - 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, /* 0....... */ - 0x00, 0xb8, 0xba, 0x23, 0xb4, 0xf6, 0xc3, 0x7b, /* ...#...{ */ - 0x14, 0xc3, 0xa4, 0xf5, 0x1d, 0x61, 0xa1, 0xf5, /* .....a.. */ - 0x1e, 0x63, 0xb9, 0x85, 0x23, 0x34, 0x50, 0x6d, /* .c..#4Pm */ - 0xf8, 0x7c, 0xa2, 0x8a, 0x04, 0x8b, 0xd5, 0x75, /* .|.....u */ - 0x5c, 0x2d, 0xf7, 0x63, 0x88, 0xd1, 0x07, 0x7a, /* \-.c...z */ - 0xea, 0x0b, 0x45, 0x35, 0x2b, 0xeb, 0x1f, 0xb1, /* ..E5+... */ - 0x22, 0xb4, 0x94, 0x41, 0x38, 0xe2, 0x9d, 0x74, /* "..A8..t */ - 0xd6, 0x8b, 0x30, 0x22, 0x10, 0x51, 0xc5, 0xdb, /* ..0".Q.. */ - 0xca, 0x3f, 0x46, 0x2b, 0xfe, 0xe5, 0x5a, 0x3f, /* .?F+..Z? */ - 0x41, 0x74, 0x67, 0x75, 0x95, 0xa9, 0x94, 0xd5, /* Atgu.... */ - 0xc3, 0xee, 0x42, 0xf8, 0x8d, 0xeb, 0x92, 0x95, /* ..B..... */ - 0xe1, 0xd9, 0x65, 0xb7, 0x43, 0xc4, 0x18, 0xde, /* ..e.C... */ - 0x16, 0x80, 0x90, 0xce, 0x24, 0x35, 0x21, 0xc4, /* ....$5!. */ - 0x55, 0xac, 0x5a, 0x51, 0xe0, 0x2e, 0x2d, 0xb3, /* U.ZQ..-. */ - 0x0a, 0x5a, 0x4f, 0x4a, 0x73, 0x31, 0x50, 0xee, /* .ZOJs1P. */ - 0x4a, 0x16, 0xbd, 0x39, 0x8b, 0xad, 0x05, 0x48, /* J..9...H */ - 0x87, 0xb1, 0x99, 0xe2, 0x10, 0xa7, 0x06, 0x72, /* .......r */ - 0x67, 0xca, 0x5c, 0xd1, 0x97, 0xbd, 0xc8, 0xf1, /* g.\..... */ - 0x76, 0xf8, 0xe0, 0x4a, 0xec, 0xbc, 0x93, 0xf4, /* v..J.... */ - 0x66, 0x4c, 0x28, 0x71, 0xd1, 0xd8, 0x66, 0x03, /* fL(q..f. */ - 0xb4, 0x90, 0x30, 0xbb, 0x17, 0xb0, 0xfe, 0x97, /* ..0..... */ - 0xf5, 0x1e, 0xe8, 0xc7, 0x5d, 0x9b, 0x8b, 0x11, /* ....]... */ - 0x19, 0x12, 0x3c, 0xab, 0x82, 0x71, 0x78, 0xff, /* ..<..qx. */ - 0xae, 0x3f, 0x32, 0xb2, 0x08, 0x71, 0xb2, 0x1b, /* .?2..q.. */ - 0x8c, 0x27, 0xac, 0x11, 0xb8, 0xd8, 0x43, 0x49, /* .'....CI */ - 0xcf, 0xb0, 0x70, 0xb1, 0xf0, 0x8c, 0xae, 0xda, /* ..p..... */ - 0x24, 0x87, 0x17, 0x3b, 0xd8, 0x04, 0x65, 0x6c, /* $..;..el */ - 0x00, 0x76, 0x50, 0xef, 0x15, 0x08, 0xd7, 0xb4, /* .vP..... */ - 0x73, 0x68, 0x26, 0x14, 0x87, 0x95, 0xc3, 0x5f, /* sh&...._ */ - 0x6e, 0x61, 0xb8, 0x87, 0x84, 0xfa, 0x80, 0x1a, /* na...... */ - 0x0a, 0x8b, 0x98, 0xf3, 0xe3, 0xff, 0x4e, 0x44, /* ......ND */ - 0x1c, 0x65, 0x74, 0x7c, 0x71, 0x54, 0x65, 0xe5, /* .et|qTe. */ - 0x39, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, /* 9....... */ - 0x01, 0x0a, 0x30, 0x82, 0x01, 0x06, 0x30, 0x09, /* ..0...0. */ - 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, /* ..U....0 */ - 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, /* .0...U.. */ - 0x04, 0x16, 0x04, 0x14, 0x32, 0x67, 0xe1, 0xb1, /* ....2g.. */ - 0x79, 0xd2, 0x81, 0xfc, 0x9f, 0x23, 0x0c, 0x70, /* y....#.p */ - 0x40, 0x50, 0xb5, 0x46, 0x56, 0xb8, 0x30, 0x36, /* @P.FV.06 */ - 0x30, 0x81, 0xc4, 0x06, 0x03, 0x55, 0x1d, 0x23, /* 0....U.# */ - 0x04, 0x81, 0xbc, 0x30, 0x81, 0xb9, 0x80, 0x14, /* ...0.... */ - 0x73, 0xb0, 0x1c, 0xa4, 0x2f, 0x82, 0xcb, 0xcf, /* s.../... */ - 0x47, 0xa5, 0x38, 0xd7, 0xb0, 0x04, 0x82, 0x3a, /* G.8....: */ - 0x7e, 0x72, 0x15, 0x21, 0xa1, 0x81, 0x9d, 0xa4, /* ~r.!.... */ - 0x81, 0x9a, 0x30, 0x81, 0x97, 0x31, 0x0b, 0x30, /* ..0..1.0 */ - 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, /* ...U.... */ - 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, /* US1.0... */ - 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, /* U....Was */ - 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e, 0x31, /* hington1 */ - 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, /* .0...U.. */ - 0x0c, 0x07, 0x53, 0x65, 0x61, 0x74, 0x74, 0x6c, /* ..Seattl */ - 0x65, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, /* e1.0...U */ - 0x04, 0x0a, 0x0c, 0x07, 0x77, 0x6f, 0x6c, 0x66, /* ....wolf */ - 0x53, 0x53, 0x4c, 0x31, 0x14, 0x30, 0x12, 0x06, /* SSL1.0.. */ - 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x0b, 0x45, 0x6e, /* .U....En */ - 0x67, 0x69, 0x6e, 0x65, 0x65, 0x72, 0x69, 0x6e, /* gineerin */ - 0x67, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, /* g1.0...U */ - 0x04, 0x03, 0x0c, 0x0f, 0x77, 0x6f, 0x6c, 0x66, /* ....wolf */ - 0x53, 0x53, 0x4c, 0x20, 0x72, 0x6f, 0x6f, 0x74, /* SSL root */ - 0x20, 0x43, 0x41, 0x31, 0x1f, 0x30, 0x1d, 0x06, /* CA1.0.. */ - 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, /* .*.H.... */ - 0x09, 0x01, 0x16, 0x10, 0x69, 0x6e, 0x66, 0x6f, /* ....info */ - 0x40, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73, 0x6c, /* @wolfssl */ - 0x2e, 0x63, 0x6f, 0x6d, 0x82, 0x01, 0x63, 0x30, /* .com..c0 */ - 0x13, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x0c, /* ...U.%.. */ - 0x30, 0x0a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, /* 0...+... */ - 0x05, 0x07, 0x03, 0x09, 0x30, 0x0d, 0x06, 0x09, /* ....0... */ - 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, /* *.H..... */ - 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, /* ........ */ - 0x4d, 0xa2, 0xd8, 0x55, 0xe0, 0x2b, 0xf4, 0xad, /* M..U.+.. */ - 0x65, 0xe2, 0x92, 0x35, 0xcb, 0x60, 0xa0, 0xa2, /* e..5.`.. */ - 0x6b, 0xa6, 0x88, 0xc1, 0x86, 0x58, 0x57, 0x37, /* k....XW7 */ - 0xbd, 0x2e, 0x28, 0x6e, 0x1c, 0x56, 0x2a, 0x35, /* ..(n.V*5 */ - 0xde, 0xff, 0x3e, 0x8e, 0x3d, 0x47, 0x21, 0x1a, /* ..>.=G!. */ - 0xe9, 0xd3, 0xc6, 0xb4, 0xe2, 0xcb, 0x3e, 0xc6, /* ......>. */ - 0xaf, 0x9b, 0xef, 0x23, 0x88, 0x56, 0x95, 0x73, /* ...#.V.s */ - 0x2e, 0xb3, 0xed, 0xc5, 0x11, 0x4b, 0x69, 0xf7, /* .....Ki. */ - 0x13, 0x3a, 0x05, 0xe1, 0xaf, 0xba, 0xc9, 0x59, /* .:.....Y */ - 0xfd, 0xe2, 0xa0, 0x81, 0xa0, 0x4c, 0x0c, 0x2c, /* .....L., */ - 0xcb, 0x57, 0xad, 0x96, 0x3a, 0x8c, 0x32, 0xa6, /* .W..:.2. */ - 0x4a, 0xf8, 0x72, 0xb8, 0xec, 0xb3, 0x26, 0x69, /* J.r...&i */ - 0xd6, 0x6a, 0x4c, 0x4c, 0x78, 0x18, 0x3c, 0xca, /* .jLLx.<. */ - 0x19, 0xf1, 0xb5, 0x8e, 0x23, 0x81, 0x5b, 0x27, /* ....#.[' */ - 0x90, 0xe0, 0x5c, 0x2b, 0x17, 0x4d, 0x78, 0x99, /* ..\+.Mx. */ - 0x6b, 0x25, 0xbd, 0x2f, 0xae, 0x1b, 0xaa, 0xce, /* k%./.... */ - 0x84, 0xb9, 0x44, 0x21, 0x46, 0xc0, 0x34, 0x6b, /* ..D!F.4k */ - 0x5b, 0xb9, 0x1b, 0xca, 0x5c, 0x60, 0xf1, 0xef, /* [...\`.. */ - 0xe6, 0x66, 0xbc, 0x84, 0x63, 0x56, 0x50, 0x7d, /* .f..cVP} */ - 0xbb, 0x2c, 0x2f, 0x7b, 0x47, 0xb4, 0xfd, 0x58, /* .,/{G..X */ - 0x77, 0x87, 0xee, 0x27, 0x20, 0x96, 0x72, 0x8e, /* w..' .r. */ - 0x4c, 0x7e, 0x4f, 0x93, 0xeb, 0x5f, 0x8f, 0x9c, /* L~O.._.. */ - 0x1e, 0x59, 0x7a, 0x96, 0xaa, 0x53, 0x77, 0x22, /* .Yz..Sw" */ - 0x41, 0xd8, 0xd3, 0xf9, 0x89, 0x8f, 0xe8, 0x9d, /* A....... */ - 0x65, 0xbd, 0x0c, 0x71, 0x3c, 0xbb, 0xa3, 0x07, /* e..q<... */ - 0xbf, 0xfb, 0xa8, 0xd1, 0x18, 0x0a, 0xb4, 0xc4, /* ........ */ - 0xf7, 0x83, 0xb3, 0x86, 0x2b, 0xf0, 0x5b, 0x05, /* ....+.[. */ - 0x28, 0xc1, 0x01, 0x31, 0x73, 0x5c, 0x2b, 0xbd, /* (..1s\+. */ - 0x60, 0x97, 0xa3, 0x36, 0x82, 0x96, 0xd7, 0x83, /* `..6.... */ - 0xdf, 0x75, 0xee, 0x29, 0x42, 0x97, 0x86, 0x41, /* .u.)B..A */ - 0x55, 0xb9, 0x70, 0x87, 0xd5, 0x02, 0x85, 0x13, /* U.p..... */ - 0x41, 0xf8, 0x25, 0x05, 0xab, 0x6a, 0xaa, 0x57 /* A.%..j.W */ + 0x30, 0x82, 0x07, 0x75, 0x0a, 0x01, 0x00, 0xa0, 0x82, 0x07, 0x6e, 0x30, + 0x82, 0x07, 0x6a, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, + 0x01, 0x01, 0x04, 0x82, 0x07, 0x5b, 0x30, 0x82, 0x07, 0x57, 0x30, 0x82, + 0x01, 0x43, 0xa1, 0x81, 0xa4, 0x30, 0x81, 0xa1, 0x31, 0x0b, 0x30, 0x09, + 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, + 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, + 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, + 0x55, 0x04, 0x07, 0x0c, 0x07, 0x53, 0x65, 0x61, 0x74, 0x74, 0x6c, 0x65, + 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x07, 0x77, + 0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, + 0x55, 0x04, 0x0b, 0x0c, 0x0b, 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x65, + 0x72, 0x69, 0x6e, 0x67, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x0c, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, 0x20, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x20, + 0x43, 0x41, 0x20, 0x31, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6e, 0x66, + 0x6f, 0x40, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, + 0x6d, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x36, 0x30, 0x35, 0x32, 0x36, 0x31, + 0x35, 0x30, 0x35, 0x30, 0x31, 0x5a, 0x30, 0x64, 0x30, 0x62, 0x30, 0x3a, + 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, + 0x14, 0x71, 0x4d, 0x82, 0x23, 0x40, 0x59, 0xc0, 0x96, 0xa1, 0x37, 0x43, + 0xfa, 0x31, 0xdb, 0xba, 0xb1, 0x43, 0x18, 0xda, 0x04, 0x04, 0x14, 0x83, + 0xc6, 0x3a, 0x89, 0x2c, 0x81, 0xf4, 0x02, 0xd7, 0x9d, 0x4c, 0xe2, 0x2a, + 0xc0, 0x71, 0x82, 0x64, 0x44, 0xda, 0x0e, 0x02, 0x01, 0x05, 0x80, 0x00, + 0x18, 0x0f, 0x32, 0x30, 0x32, 0x36, 0x30, 0x35, 0x32, 0x36, 0x31, 0x35, + 0x30, 0x35, 0x30, 0x31, 0x5a, 0xa0, 0x11, 0x18, 0x0f, 0x32, 0x30, 0x35, + 0x33, 0x31, 0x30, 0x31, 0x30, 0x31, 0x35, 0x30, 0x35, 0x30, 0x31, 0x5a, + 0xa1, 0x23, 0x30, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x30, 0x01, 0x02, 0x04, 0x12, 0x04, 0x10, 0x8b, 0xb7, 0x65, + 0x51, 0xcf, 0x19, 0x82, 0x34, 0x51, 0x0a, 0xfb, 0x1a, 0x20, 0xad, 0x7c, + 0x9a, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x1a, 0x5d, 0xa2, + 0xf4, 0x02, 0x97, 0x5e, 0x0f, 0xf8, 0x6d, 0x9c, 0x81, 0xc1, 0x40, 0x5c, + 0xae, 0xe4, 0x4f, 0x06, 0x68, 0x5b, 0x9c, 0xc3, 0xb0, 0x48, 0x51, 0xd7, + 0x28, 0x59, 0x78, 0x97, 0x4b, 0x87, 0xca, 0x91, 0x78, 0x44, 0xaa, 0x63, + 0xfd, 0x2e, 0xb3, 0xd0, 0x38, 0x79, 0xc3, 0x89, 0xee, 0xa5, 0x98, 0xf9, + 0xb9, 0xfc, 0x5b, 0x40, 0x5d, 0x7b, 0x0b, 0xf0, 0xd9, 0xf0, 0x31, 0x00, + 0xe8, 0x31, 0x47, 0xb9, 0x58, 0x0b, 0x20, 0x0d, 0x07, 0x9e, 0x2f, 0x6e, + 0xba, 0xb2, 0x6d, 0x1e, 0x03, 0x9a, 0xa9, 0xd3, 0xac, 0x8e, 0xf0, 0x7f, + 0x27, 0x3f, 0xd3, 0x30, 0x11, 0x17, 0x72, 0x5c, 0x46, 0x94, 0xc8, 0xb3, + 0x23, 0xdc, 0x4a, 0x93, 0xe8, 0x8a, 0xdc, 0x9e, 0x55, 0x8f, 0x2b, 0xbf, + 0x9f, 0x75, 0x05, 0xfc, 0xc6, 0x6f, 0xcc, 0x90, 0x80, 0x78, 0xc3, 0x13, + 0x60, 0xe2, 0x53, 0xf2, 0xeb, 0xc0, 0x1b, 0xb8, 0x88, 0x1b, 0x01, 0xf7, + 0x71, 0x6e, 0x4b, 0xdc, 0xdc, 0x9b, 0x0f, 0x6d, 0x5e, 0xe3, 0x2c, 0x58, + 0x3d, 0xff, 0x74, 0xbc, 0xcd, 0x91, 0x0a, 0x80, 0x4a, 0xd9, 0xb4, 0xe2, + 0x88, 0x7a, 0x6d, 0x16, 0x5d, 0xbc, 0x33, 0x1e, 0xae, 0x0d, 0xa3, 0xd8, + 0xcb, 0xd6, 0x94, 0x31, 0xfa, 0x03, 0x80, 0xcd, 0x36, 0xa8, 0xbc, 0xce, + 0xa4, 0x0f, 0x36, 0xc5, 0x44, 0x71, 0x34, 0xab, 0xe0, 0xbd, 0x56, 0xbd, + 0x9b, 0x28, 0xde, 0x85, 0xf3, 0xe7, 0x66, 0x36, 0x0f, 0x80, 0x1c, 0x94, + 0x4d, 0xd0, 0xb3, 0x5d, 0xbd, 0x0b, 0x93, 0xff, 0x67, 0x35, 0x40, 0xff, + 0x85, 0xb8, 0xb9, 0xa8, 0xdc, 0xda, 0x90, 0xee, 0x18, 0x10, 0x6c, 0x2f, + 0x1d, 0xbd, 0x5e, 0x2a, 0x29, 0x00, 0x62, 0x82, 0x33, 0xe4, 0xac, 0x82, + 0x4f, 0x79, 0x53, 0x05, 0xf2, 0x38, 0x12, 0x9a, 0x3b, 0xe2, 0xce, 0xec, + 0xd3, 0xa0, 0x82, 0x04, 0xf8, 0x30, 0x82, 0x04, 0xf4, 0x30, 0x82, 0x04, + 0xf0, 0x30, 0x82, 0x03, 0xd8, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, + 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0x97, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, + 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, + 0x6e, 0x67, 0x74, 0x6f, 0x6e, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, + 0x04, 0x07, 0x0c, 0x07, 0x53, 0x65, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x31, + 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x07, 0x77, 0x6f, + 0x6c, 0x66, 0x53, 0x53, 0x4c, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x0c, 0x0b, 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x65, 0x72, + 0x69, 0x6e, 0x67, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x0c, 0x0f, 0x77, 0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, 0x20, 0x72, 0x6f, + 0x6f, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6e, + 0x66, 0x6f, 0x40, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73, 0x6c, 0x2e, 0x63, + 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x35, 0x31, 0x31, 0x31, 0x33, + 0x32, 0x30, 0x34, 0x31, 0x33, 0x34, 0x5a, 0x17, 0x0d, 0x32, 0x38, 0x30, + 0x38, 0x30, 0x39, 0x32, 0x30, 0x34, 0x31, 0x33, 0x34, 0x5a, 0x30, 0x81, + 0xa1, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, + 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e, 0x31, + 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x07, 0x53, 0x65, + 0x61, 0x74, 0x74, 0x6c, 0x65, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, + 0x04, 0x0a, 0x0c, 0x07, 0x77, 0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, 0x31, + 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x0b, 0x45, 0x6e, + 0x67, 0x69, 0x6e, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x31, 0x22, 0x30, + 0x20, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x19, 0x77, 0x6f, 0x6c, 0x66, + 0x53, 0x53, 0x4c, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6d, 0x65, 0x64, + 0x69, 0x61, 0x74, 0x65, 0x20, 0x43, 0x41, 0x20, 0x31, 0x31, 0x1f, 0x30, + 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, + 0x16, 0x10, 0x69, 0x6e, 0x66, 0x6f, 0x40, 0x77, 0x6f, 0x6c, 0x66, 0x73, + 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, + 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, + 0x01, 0x01, 0x00, 0xde, 0xb4, 0xc8, 0x5c, 0x77, 0xe0, 0x2d, 0xb1, 0xf5, + 0xb9, 0xad, 0x16, 0x47, 0x35, 0xa0, 0x35, 0x65, 0x65, 0xc6, 0xe1, 0x40, + 0xab, 0x1e, 0xb4, 0xb9, 0x13, 0xb7, 0xcb, 0x8c, 0xbb, 0x77, 0xa5, 0x76, + 0xda, 0x6d, 0x87, 0x87, 0xf6, 0x4a, 0x4d, 0x13, 0xe4, 0x26, 0x3e, 0x27, + 0x87, 0xee, 0x5b, 0xc7, 0x6a, 0x3f, 0x45, 0x30, 0x61, 0x55, 0x5c, 0xf6, + 0x35, 0xd1, 0x65, 0xfa, 0x98, 0x11, 0xa3, 0xa7, 0x55, 0xd5, 0xbe, 0x91, + 0x82, 0x4b, 0xfc, 0xbe, 0x90, 0xd6, 0x50, 0x53, 0x63, 0x9a, 0x2c, 0x22, + 0xe1, 0x35, 0x11, 0xdc, 0x78, 0x02, 0x97, 0x8a, 0xe4, 0x46, 0x92, 0x9c, + 0x53, 0x08, 0x76, 0xde, 0x1f, 0x53, 0xb6, 0xb8, 0xca, 0x77, 0x3e, 0x79, + 0x6e, 0xbc, 0xd0, 0xe3, 0x0d, 0x30, 0x5b, 0x4c, 0xf6, 0x94, 0x0d, 0x30, + 0x29, 0x64, 0x9f, 0x04, 0xe5, 0xdb, 0xfb, 0x89, 0x60, 0x67, 0xbb, 0xaf, + 0x26, 0x83, 0x51, 0x77, 0x24, 0x2f, 0x2b, 0x0b, 0xa1, 0x94, 0x81, 0x10, + 0x98, 0xe8, 0xeb, 0x26, 0xa8, 0x1e, 0x7c, 0xe4, 0xc4, 0x6c, 0x67, 0x06, + 0x95, 0x55, 0x4a, 0xdd, 0x52, 0xf4, 0xf2, 0x60, 0x6d, 0x01, 0x2b, 0x19, + 0x91, 0x35, 0x6d, 0xa4, 0x08, 0x47, 0x06, 0x71, 0x24, 0x00, 0xd9, 0xde, + 0xc6, 0x56, 0xf3, 0x8b, 0x53, 0x2c, 0xe2, 0x9a, 0x96, 0xa5, 0xf3, 0x62, + 0xe5, 0xc4, 0xe3, 0x23, 0xf2, 0xd2, 0xfc, 0x21, 0xea, 0x0f, 0x62, 0x76, + 0x8d, 0xd5, 0x99, 0x48, 0xce, 0xdc, 0x58, 0xc4, 0xbb, 0x7f, 0xda, 0x94, + 0x2c, 0x80, 0x74, 0x83, 0xc5, 0xe0, 0xb0, 0x15, 0x7e, 0x41, 0xfd, 0x0e, + 0xf2, 0xf4, 0xf0, 0x78, 0x76, 0x7b, 0xad, 0x26, 0x0d, 0xaa, 0x48, 0x96, + 0x17, 0x2f, 0x21, 0xe3, 0x95, 0x2b, 0x26, 0x37, 0xf9, 0xaa, 0x80, 0x2f, + 0xfe, 0xde, 0xf6, 0x5e, 0xbc, 0x97, 0x7f, 0x02, 0x03, 0x01, 0x00, 0x01, + 0xa3, 0x82, 0x01, 0x39, 0x30, 0x82, 0x01, 0x35, 0x30, 0x0c, 0x06, 0x03, + 0x55, 0x1d, 0x13, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1d, + 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x83, 0xc6, 0x3a, + 0x89, 0x2c, 0x81, 0xf4, 0x02, 0xd7, 0x9d, 0x4c, 0xe2, 0x2a, 0xc0, 0x71, + 0x82, 0x64, 0x44, 0xda, 0x0e, 0x30, 0x81, 0xc4, 0x06, 0x03, 0x55, 0x1d, + 0x23, 0x04, 0x81, 0xbc, 0x30, 0x81, 0xb9, 0x80, 0x14, 0x73, 0xb0, 0x1c, + 0xa4, 0x2f, 0x82, 0xcb, 0xcf, 0x47, 0xa5, 0x38, 0xd7, 0xb0, 0x04, 0x82, + 0x3a, 0x7e, 0x72, 0x15, 0x21, 0xa1, 0x81, 0x9d, 0xa4, 0x81, 0x9a, 0x30, + 0x81, 0x97, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, + 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e, + 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x07, 0x53, + 0x65, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, + 0x55, 0x04, 0x0a, 0x0c, 0x07, 0x77, 0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, + 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x0b, 0x45, + 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x31, 0x18, + 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0f, 0x77, 0x6f, 0x6c, + 0x66, 0x53, 0x53, 0x4c, 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, + 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6e, 0x66, 0x6f, 0x40, 0x77, 0x6f, + 0x6c, 0x66, 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x82, 0x01, 0x63, + 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x01, + 0x06, 0x30, 0x32, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, + 0x01, 0x04, 0x26, 0x30, 0x24, 0x30, 0x22, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x16, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x3a, + 0x32, 0x32, 0x32, 0x32, 0x30, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, + 0x00, 0x77, 0xec, 0x89, 0x37, 0xd4, 0x35, 0x2e, 0x24, 0xfd, 0xd2, 0xde, + 0xd9, 0x98, 0x87, 0xbe, 0x52, 0xae, 0xb5, 0xd4, 0xf6, 0x13, 0x34, 0x12, + 0x2c, 0xf0, 0x78, 0x98, 0x07, 0x9f, 0xf7, 0xe4, 0x76, 0xdf, 0x6e, 0xeb, + 0x97, 0xc7, 0x03, 0xa3, 0xe6, 0x15, 0x6e, 0xe2, 0x94, 0x16, 0x6b, 0xed, + 0x59, 0xa9, 0x4a, 0x10, 0xa0, 0xcc, 0xc2, 0x61, 0x78, 0xc7, 0xfb, 0x1c, + 0x04, 0x4a, 0x20, 0xc1, 0xfc, 0x94, 0xc6, 0x99, 0xb0, 0x3a, 0x8c, 0x2f, + 0x2b, 0x7d, 0x15, 0x30, 0x53, 0xc7, 0x9b, 0x73, 0x54, 0x6f, 0x4d, 0x16, + 0xa6, 0xab, 0x2d, 0x8a, 0x51, 0x70, 0x1f, 0x1b, 0x8e, 0x60, 0x0b, 0x56, + 0x8b, 0xf2, 0x94, 0x01, 0xfd, 0x81, 0x5f, 0x73, 0xcb, 0xed, 0x5e, 0xcc, + 0x4a, 0x71, 0xc1, 0xa9, 0x1a, 0xd7, 0xc7, 0x2b, 0x5a, 0x66, 0x02, 0x77, + 0xda, 0x10, 0xe8, 0x45, 0x42, 0xa0, 0x7c, 0xef, 0x78, 0xff, 0xdd, 0x08, + 0xf6, 0x84, 0x2f, 0x41, 0xf5, 0x18, 0xc9, 0xa2, 0x48, 0xd1, 0x5d, 0xb6, + 0xa4, 0x4d, 0x32, 0xaf, 0x83, 0x5d, 0xb9, 0x64, 0xec, 0x40, 0xe9, 0x62, + 0x38, 0xef, 0x1b, 0xd1, 0x8e, 0xc9, 0xe8, 0xfd, 0xb3, 0xe8, 0xe1, 0xa1, + 0xda, 0x16, 0x1e, 0x26, 0x3c, 0x82, 0x36, 0xcb, 0x8d, 0x80, 0x67, 0x33, + 0xca, 0x30, 0xbf, 0x93, 0x03, 0xc8, 0x9c, 0xbe, 0xa2, 0x6f, 0xaa, 0x7c, + 0x76, 0x24, 0x3d, 0x06, 0x99, 0xab, 0xa7, 0xfe, 0x12, 0xf3, 0xdb, 0xfd, + 0xa0, 0x8a, 0xb5, 0x0d, 0xc1, 0x9c, 0x90, 0xb7, 0xca, 0x7e, 0x6d, 0xfb, + 0xff, 0x2a, 0xc3, 0xfe, 0x7c, 0x9f, 0x41, 0xe8, 0xc2, 0x7f, 0x4f, 0xfa, + 0x4b, 0x49, 0xc4, 0xa0, 0xd0, 0xbc, 0xfd, 0x38, 0x34, 0x22, 0xff, 0xd5, + 0x83, 0x79, 0x70, 0x7f, 0x6c, 0x30, 0x8d, 0xad, 0x93, 0xfb, 0xb8, 0x77, + 0x01, 0x34, 0xaf, 0xcc, 0x0e }; OcspEntry entry[1]; CertStatus status[1]; @@ -3227,7 +3152,7 @@ int test_wolfSSL_CertManagerCheckOCSPResponse(void) /* Flip a byte in the request serial number, response should be invalid * now. */ if ((request != NULL) && (request->serial != NULL)) - request->serial[0] ^= request->serial[0]; + request->serial[0] ^= 0xFF; ExpectIntNE(wolfSSL_CertManagerCheckOCSPResponse(cm, (byte *)response, sizeof(response), NULL, status, entry, request), WOLFSSL_SUCCESS); @@ -3508,7 +3433,7 @@ int test_wolfSSL_CertManagerRejectMD5Cert(void) #if !defined(NO_CERTS) && !defined(NO_RSA) && !defined(NO_MD5) && \ !defined(WOLFSSL_ALLOW_MD5_CERT_SIGS) && defined(WOLFSSL_CERT_GEN) && \ !defined(NO_WOLFSSL_CM_VERIFY) && !defined(NO_ASN_CRYPT) && \ - !defined(USE_CERT_BUFFERS_1024) + !defined(USE_CERT_BUFFERS_1024) && !defined(NO_ASN_TIME) WOLFSSL_CERT_MANAGER* cm = NULL; RsaKey caKey; WC_RNG rng; diff --git a/tests/api/test_des3.c b/tests/api/test_des3.c index c52badb22f..ca8e0ba47c 100644 --- a/tests/api/test_des3.c +++ b/tests/api/test_des3.c @@ -181,6 +181,67 @@ int test_wc_Des3_CbcEncryptDecrypt(void) } /* END wc_Des3_CbcEncrypt */ +/* + * Regression test for issue 5379: wc_Des3_CbcEncrypt/Decrypt must refuse to + * run unless a key has been configured with wc_Des3_SetKey(), both before + * SetKey and after Free. Otherwise the operation would silently run with + * uninitialized or zeroed key material and return success. + * + * FIPS builds use the FIPS-certified DES3 implementation which does not track + * key state, so skip the test for FIPS. + */ +int test_wc_Des3_CbcEncryptDecrypt_no_key(void) +{ + EXPECT_DECLS; +#if !defined(NO_DES3) && !defined(HAVE_FIPS) + Des3 des; + byte cipher[24]; + byte plain[24]; + const byte key[] = { + 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef, + 0xfe,0xde,0xba,0x98,0x76,0x54,0x32,0x10, + 0x89,0xab,0xcd,0xef,0x01,0x23,0x45,0x67 + }; + const byte iv[] = { + 0x12,0x34,0x56,0x78,0x90,0xab,0xcd,0xef, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x11,0x21,0x31,0x41,0x51,0x61,0x71,0x81 + }; + const byte vector[] = { /* "Now is the time for all " w/o trailing 0 */ + 0x4e,0x6f,0x77,0x20,0x69,0x73,0x20,0x74, + 0x68,0x65,0x20,0x74,0x69,0x6d,0x65,0x20, + 0x66,0x6f,0x72,0x20,0x61,0x6c,0x6c,0x20 + }; + + XMEMSET(&des, 0, sizeof(Des3)); + XMEMSET(cipher, 0, sizeof(cipher)); + XMEMSET(plain, 0, sizeof(plain)); + + /* Encrypt/decrypt without a key after init must fail, not silently run. */ + ExpectIntEQ(wc_Des3Init(&des, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_Des3_CbcEncrypt(&des, cipher, vector, 24), + WC_NO_ERR_TRACE(MISSING_KEY)); + ExpectIntEQ(wc_Des3_CbcDecrypt(&des, plain, vector, 24), + WC_NO_ERR_TRACE(MISSING_KEY)); + + /* After a key is set, the operations succeed. */ + ExpectIntEQ(wc_Des3_SetKey(&des, key, iv, DES_ENCRYPTION), 0); + ExpectIntEQ(wc_Des3_CbcEncrypt(&des, cipher, vector, 24), 0); + ExpectIntEQ(wc_Des3_SetKey(&des, key, iv, DES_DECRYPTION), 0); + ExpectIntEQ(wc_Des3_CbcDecrypt(&des, plain, cipher, 24), 0); + ExpectIntEQ(XMEMCMP(plain, vector, 24), 0); + + /* After free, the keyed state is cleared and operations must fail again. */ + wc_Des3Free(&des); + ExpectIntEQ(wc_Des3_CbcEncrypt(&des, cipher, vector, 24), + WC_NO_ERR_TRACE(MISSING_KEY)); + ExpectIntEQ(wc_Des3_CbcDecrypt(&des, plain, vector, 24), + WC_NO_ERR_TRACE(MISSING_KEY)); +#endif + return EXPECT_RESULT(); + +} /* END test_wc_Des3_CbcEncryptDecrypt_no_key */ + /* * Unit test for wc_Des3_EcbEncrypt */ diff --git a/tests/api/test_des3.h b/tests/api/test_des3.h index 9f530f7e29..bd66779af8 100644 --- a/tests/api/test_des3.h +++ b/tests/api/test_des3.h @@ -27,14 +27,16 @@ int test_wc_Des3_SetIV(void); int test_wc_Des3_SetKey(void); int test_wc_Des3_CbcEncryptDecrypt(void); +int test_wc_Des3_CbcEncryptDecrypt_no_key(void); int test_wc_Des3_EcbEncrypt(void); int test_wc_Des3Cbc_MonteCarlo(void); -#define TEST_DES3_DECLS \ - TEST_DECL_GROUP("des3", test_wc_Des3_SetIV), \ - TEST_DECL_GROUP("des3", test_wc_Des3_SetKey), \ - TEST_DECL_GROUP("des3", test_wc_Des3_CbcEncryptDecrypt), \ - TEST_DECL_GROUP("des3", test_wc_Des3_EcbEncrypt), \ +#define TEST_DES3_DECLS \ + TEST_DECL_GROUP("des3", test_wc_Des3_SetIV), \ + TEST_DECL_GROUP("des3", test_wc_Des3_SetKey), \ + TEST_DECL_GROUP("des3", test_wc_Des3_CbcEncryptDecrypt), \ + TEST_DECL_GROUP("des3", test_wc_Des3_CbcEncryptDecrypt_no_key), \ + TEST_DECL_GROUP("des3", test_wc_Des3_EcbEncrypt), \ TEST_DECL_GROUP("des3", test_wc_Des3Cbc_MonteCarlo) #endif /* WOLFCRYPT_TEST_DES3_H */ diff --git a/tests/api/test_dh.c b/tests/api/test_dh.c index e90e4bba20..4b6c81c4a6 100644 --- a/tests/api/test_dh.c +++ b/tests/api/test_dh.c @@ -74,3 +74,146 @@ int test_wc_DhPublicKeyDecode(void) return EXPECT_RESULT(); } +/* + * Tests that wc_DhAgree rejects peer public keys that are not in the expected + * subgroup when the group order q is known (SP 800-56Ar3 section 5.6.2.3.1). + * This test not compatible with WOLFSSL_SP_MATH, because p vector is not 2048, + * 3072, or 4096 bits. + */ +int test_wc_DhAgree_subgroup_check(void) +{ + EXPECT_DECLS; +#if !defined(NO_DH) && !defined(WOLFSSL_SP_MATH) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION3_GT(7,0,0)) + DhKey key; + WC_RNG rng; + byte agree[64]; + + /* DSA-style 512-bit group where p - 1 == k * q, where q is + * a 161-bit prime, and g generates the order-q subgroup. + * + * y_bad has order 3 mod p (y^3 mod p == 1). It passes the bounds check + * (2 <= y <= p-2), but is not in the order-q subgroup (y^q mod p != 1). + * */ + const byte dsa_dh_p[] = { + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xab, 0x80, 0x00, 0x00, 0x47 + }; + const byte dsa_dh_q[] = { + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x07 + }; + const byte dsa_dh_g[] = { + 0x63, 0x23, 0x85, 0x16, 0x66, 0xc1, 0xf1, 0xf0, + 0xc3, 0xa0, 0x95, 0xd0, 0x4b, 0x68, 0x92, 0xf3, + 0x64, 0x09, 0xbd, 0x89, 0x57, 0x85, 0xfa, 0x44, + 0x86, 0xc1, 0x64, 0x86, 0x1e, 0xa1, 0x91, 0x33, + 0xd8, 0xaf, 0xb5, 0xa6, 0x28, 0xed, 0xc2, 0x7c, + 0x37, 0xa1, 0x5b, 0x0b, 0xf7, 0x6a, 0xa4, 0x61, + 0x75, 0x08, 0x16, 0x12, 0xe5, 0x62, 0xc4, 0x89, + 0x5a, 0x9c, 0x1b, 0x76, 0xe1, 0x5f, 0x63, 0x21 + }; + /* Order-3 element: y^3 = 1 mod p, y^q mod p != 1 */ + const byte dsa_dh_y_bad[] = { + 0x41, 0x61, 0x8f, 0xcd, 0xb7, 0x76, 0xb7, 0xd2, + 0x38, 0x46, 0x98, 0x16, 0xa3, 0xfd, 0xd2, 0xa2, + 0x71, 0x6a, 0x0b, 0x66, 0x87, 0x3f, 0x6c, 0x15, + 0x28, 0x46, 0x79, 0xfb, 0x64, 0x4c, 0x2a, 0x28, + 0xe6, 0x65, 0x44, 0x8e, 0xf8, 0x30, 0x4e, 0x73, + 0xec, 0x8b, 0x4b, 0xd2, 0x82, 0xd1, 0x87, 0x20, + 0x35, 0x47, 0x42, 0xe6, 0x94, 0x49, 0x7c, 0x73, + 0xbc, 0x47, 0xcd, 0xcb, 0x88, 0xb8, 0xed, 0x62 + }; + /* A {priv, pub} keypair generated from these parameters. + * This pair would pass a partial subgroup test. The pub key + * is not actually needed for this test. */ + const byte priv[] = { + 0xc7, 0x82, 0xd1, 0xc4, 0x13, 0xa8, 0x3f, 0xe0, + 0xef, 0xdc, 0xf4, 0x10, 0xf9, 0xf4, 0xc7, 0x0e, + 0x30, 0xbc, 0x65, 0x14 + }; + /* + byte pub[] = { + 0x28, 0x2e, 0x2b, 0xf4, 0x4d, 0x83, 0xf5, 0xd8, + 0x77, 0x5a, 0xea, 0x7c, 0x4d, 0x89, 0x98, 0x1b, + 0xe9, 0x61, 0x69, 0x35, 0x39, 0xdd, 0x1b, 0x2d, + 0x5f, 0x35, 0x29, 0x25, 0xd9, 0xec, 0xcc, 0x46, + 0x39, 0xfe, 0x3e, 0xe4, 0x67, 0xc9, 0x47, 0xe1, + 0xc4, 0x5b, 0x02, 0x95, 0x61, 0x4a, 0x23, 0xdc, + 0x3a, 0xf6, 0xce, 0x18, 0x99, 0x1e, 0xe0, 0x72, + 0xeb, 0x53, 0x1f, 0xf0, 0xc9, 0x50, 0x9a, 0xc7 + }; + */ + word32 privSz = sizeof(priv); + word32 agreeSz; + + #if defined(WOLFSSL_PUBLIC_MP) && !defined(WOLFSSL_SMALL_STACK) + /* optional sanity checks for the mp used in this dh test. */ + const byte expt[1] = {0x03}; + mp_int p[1], e[1], q[1]; + mp_int g[1], y[1], r[1]; + int isPrime = 0; + /* init mp */ + ExpectIntEQ(mp_init_multi(p, q, g, y, r, e), MP_OKAY); + /* load mp values */ + ExpectIntEQ(mp_read_unsigned_bin(p, dsa_dh_p, sizeof(dsa_dh_p)), MP_OKAY); + ExpectIntEQ(mp_read_unsigned_bin(e, expt, sizeof(expt)), MP_OKAY); + ExpectIntEQ(mp_read_unsigned_bin(q, dsa_dh_q, sizeof(dsa_dh_q)), MP_OKAY); + ExpectIntEQ(mp_read_unsigned_bin(g, dsa_dh_g, sizeof(dsa_dh_g)), MP_OKAY); + ExpectIntEQ(mp_read_unsigned_bin(y, dsa_dh_y_bad, sizeof(dsa_dh_y_bad)), + MP_OKAY); + /* p, q are prime */ + ExpectIntEQ(mp_prime_is_prime(p, 8, &isPrime), MP_OKAY); + ExpectIntEQ(isPrime, 1); + ExpectIntEQ(mp_prime_is_prime(q, 8, &isPrime), MP_OKAY); + ExpectIntEQ(isPrime, 1); + /* (y ^ 3) mod p == 1*/ + ExpectIntEQ(mp_exptmod(y, e, p, r), MP_OKAY); + ExpectIntEQ(mp_cmp_d(r, 1), MP_EQ); + /* (g ^ q) mod p == 1*/ + ExpectIntEQ(mp_exptmod(g, q, p, r), MP_OKAY); + ExpectIntEQ(mp_cmp_d(r, 1), MP_EQ); + /* (y ^ q) mod p != 1*/ + ExpectIntEQ(mp_exptmod(y, q, p, r), MP_OKAY); + ExpectIntNE(mp_cmp_d(r, 1), MP_EQ); + /* clear them */ + mp_clear(p); mp_clear(e); mp_clear(q); + mp_clear(g); mp_clear(y); mp_clear(r); + #endif /* WOLFSSL_PUBLIC_MP && !WOLFSSL_SMALL_STACK */ + + XMEMSET(&key, 0, sizeof(DhKey)); + XMEMSET(&rng, 0, sizeof(WC_RNG)); + + ExpectIntEQ(wc_InitRng(&rng), 0); + ExpectIntEQ(wc_InitDhKey(&key), 0); + + /* Set DH parameters. */ + ExpectIntEQ(wc_DhSetCheckKey(&key, dsa_dh_p, sizeof(dsa_dh_p), + dsa_dh_g, sizeof(dsa_dh_g), dsa_dh_q, sizeof(dsa_dh_q), + 0, &rng), 0); + + /* sanity: agree with g (valid subgroup element). This should succeed */ + agreeSz = sizeof(agree); + ExpectIntEQ(wc_DhAgree(&key, agree, &agreeSz, priv, privSz, + dsa_dh_g, sizeof(dsa_dh_g)), 0); + + /* y_bad is not in the order-q subgroup. This should be rejected with + * error DH_CHECK_PUB_E.*/ + agreeSz = sizeof(agree); + ExpectIntEQ(wc_DhAgree(&key, agree, &agreeSz, priv, privSz, + dsa_dh_y_bad, sizeof(dsa_dh_y_bad)), + DH_CHECK_PUB_E); + + wc_FreeDhKey(&key); + wc_FreeRng(&rng); +#endif /* !NO_DH && !defined(WOLFSSL_SP_MATH) && !HAVE_SELFTEST && etc... */ + return EXPECT_RESULT(); +} + diff --git a/tests/api/test_dh.h b/tests/api/test_dh.h index a81d98b01f..e5d32bce3c 100644 --- a/tests/api/test_dh.h +++ b/tests/api/test_dh.h @@ -25,8 +25,10 @@ #include int test_wc_DhPublicKeyDecode(void); +int test_wc_DhAgree_subgroup_check(void); -#define TEST_DH_DECLS \ - TEST_DECL_GROUP("dh", test_wc_DhPublicKeyDecode) +#define TEST_DH_DECLS \ + TEST_DECL_GROUP("dh", test_wc_DhPublicKeyDecode), \ + TEST_DECL_GROUP("dh", test_wc_DhAgree_subgroup_check) #endif /* WOLFCRYPT_TEST_DH_H */ diff --git a/tests/api/test_dtls.c b/tests/api/test_dtls.c index 572dda6c94..f160cdc594 100644 --- a/tests/api/test_dtls.c +++ b/tests/api/test_dtls.c @@ -515,13 +515,54 @@ int test_wolfSSL_dtls_set_pending_peer(void) wolfSSL_CTX_free(ctx_s); wolfSSL_CTX_free(ctx_c); #endif + +#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_DTLS_CID) && \ + !defined(WOLFSSL_NO_SOCK) && defined(XINET_PTON) && \ + defined(HAVE_SOCKADDR) && !defined(WOLFSSL_NO_TLS12) && \ + !defined(NO_WOLFSSL_CLIENT) + { + /* Exercise the "already the current peer" branch, which needs real + * AF_INET addresses (sockAddrEqual() validates the sockaddr). */ + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + void* cur = NULL; + void* other = NULL; + unsigned int addrSz = (unsigned int)sizeof(SOCKADDR_IN); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectNotNull(cur = + wolfSSL_dtls_create_peer(11111, (char*)"127.0.0.1")); + ExpectNotNull(other = + wolfSSL_dtls_create_peer(22222, (char*)"127.0.0.1")); + + /* NULL object fails. */ + ExpectIntEQ(wolfSSL_dtls_set_pending_peer(NULL, cur, addrSz), + WOLFSSL_FAILURE); + + /* Make 'cur' the current peer. */ + ExpectIntEQ(wolfSSL_dtls_set_peer(ssl, cur, addrSz), WOLFSSL_SUCCESS); + + /* A different address goes to the pending slot (SockAddrSet path). */ + ExpectIntEQ(wolfSSL_dtls_set_pending_peer(ssl, other, addrSz), + WOLFSSL_SUCCESS); + /* The current address matches: the staged pending peer is cleared. */ + ExpectIntEQ(wolfSSL_dtls_set_pending_peer(ssl, cur, addrSz), + WOLFSSL_SUCCESS); + /* Matches again with no pending peer left to clear. */ + ExpectIntEQ(wolfSSL_dtls_set_pending_peer(ssl, cur, addrSz), + WOLFSSL_SUCCESS); + + wolfSSL_dtls_free_peer(cur); + wolfSSL_dtls_free_peer(other); + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); + } +#endif return EXPECT_RESULT(); } - - - int test_dtls_version_checking(void) { EXPECT_DECLS; @@ -5438,3 +5479,798 @@ int test_dtls12_export_import_etm(void) #endif return EXPECT_RESULT(); } + + +/* ---------------------------------------------------------------------------- + * Coverage tests for DTLS APIs in src/ssl_api_dtls.c + * ------------------------------------------------------------------------- */ + +int test_wolfSSL_dtls_create_free_peer(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && defined(XINET_PTON) && \ + !defined(WOLFSSL_NO_SOCK) && defined(HAVE_SOCKADDR) + void* peer = NULL; + + /* Valid IPv4 address and port. */ + ExpectNotNull(peer = wolfSSL_dtls_create_peer(11111, (char*)"127.0.0.1")); + ExpectIntEQ(wolfSSL_dtls_free_peer(peer), WOLFSSL_SUCCESS); + + /* Invalid address string returns NULL. */ + ExpectNull(wolfSSL_dtls_create_peer(11111, (char*)"not-an-ip-address")); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_dtls_get0_peer(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && !defined(NO_WOLFSSL_CLIENT) && \ + !defined(WOLFSSL_NO_TLS12) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + const void* peer = NULL; + unsigned int peerSz = 0; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + ExpectIntEQ(wolfSSL_dtls_set_peer(ssl, (void*)"1234", 5), WOLFSSL_SUCCESS); +#ifndef WOLFSSL_RW_THREADED + /* NULL arguments fail. */ + ExpectIntEQ(wolfSSL_dtls_get0_peer(NULL, &peer, &peerSz), WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_dtls_get0_peer(ssl, NULL, &peerSz), WOLFSSL_FAILURE); + /* Returns a pointer to the stored peer address and its size. */ + ExpectIntEQ(wolfSSL_dtls_get0_peer(ssl, &peer, &peerSz), WOLFSSL_SUCCESS); + ExpectIntEQ(peerSz, 5); + ExpectNotNull(peer); +#else + ExpectIntEQ(wolfSSL_dtls_get0_peer(ssl, &peer, &peerSz), + WOLFSSL_NOT_IMPLEMENTED); +#endif + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_dtls_set_timeout_init(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_LEANPSK) && \ + !defined(NO_WOLFSSL_CLIENT) && !defined(WOLFSSL_NO_TLS12) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + ExpectIntEQ(wolfSSL_dtls_set_timeout_init(NULL, 1), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_dtls_set_timeout_init(ssl, -1), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_dtls_set_timeout_max(ssl, 5), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_dtls_set_timeout_init(ssl, 3), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_dtls_get_current_timeout(ssl), 3); + /* Initial timeout greater than maximum fails. */ + ExpectIntEQ(wolfSSL_dtls_set_timeout_init(ssl, 10), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_dtls_retransmit(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) && \ + !defined(WOLFSSL_NO_TLS12) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), 0); + + /* NULL fails. */ + ExpectIntEQ(wolfSSL_dtls_retransmit(NULL), WOLFSSL_FATAL_ERROR); + /* Send the ClientHello flight, then retransmit it (DTLS 1.2 path). */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(wolfSSL_dtls_retransmit(ssl_c), WOLFSSL_SUCCESS); + + /* Resending fails when the transport reports want-write, exercising the + * error path (sets ssl->error and returns WOLFSSL_FATAL_ERROR). */ + test_memio_simulate_want_write(&test_ctx, 1, 1); + ExpectIntEQ(wolfSSL_dtls_retransmit(ssl_c), WOLFSSL_FATAL_ERROR); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_WRITE); + test_memio_simulate_want_write(&test_ctx, 1, 0); + + /* After the handshake completes, retransmit is a no-op success. */ + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(wolfSSL_dtls_retransmit(ssl_c), WOLFSSL_SUCCESS); + + wolfSSL_free(ssl_s); + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_s); + wolfSSL_CTX_free(ctx_c); +#endif +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \ + defined(WOLFSSL_DTLS13) && defined(WOLFSSL_TLS13) + { + /* DTLS 1.3 exercises the Dtls13DoScheduledWork() branch. */ + WOLFSSL_CTX *ctx_c13 = NULL, *ctx_s13 = NULL; + WOLFSSL *ssl_c13 = NULL, *ssl_s13 = NULL; + struct test_memio_ctx test_ctx13; + + XMEMSET(&test_ctx13, 0, sizeof(test_ctx13)); + ExpectIntEQ(test_memio_setup(&test_ctx13, &ctx_c13, &ctx_s13, &ssl_c13, + &ssl_s13, wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), + 0); + ExpectIntEQ(wolfSSL_negotiate(ssl_c13), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c13, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(wolfSSL_dtls_retransmit(ssl_c13), WOLFSSL_SUCCESS); + + wolfSSL_free(ssl_s13); + wolfSSL_free(ssl_c13); + wolfSSL_CTX_free(ctx_s13); + wolfSSL_CTX_free(ctx_c13); + } +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_DTLSv1_compat_timeouts(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && !defined(NO_WOLFSSL_CLIENT) && \ + !defined(WOLFSSL_NO_TLS12) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + WOLFSSL_TIMEVAL tv; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + XMEMSET(&tv, 0, sizeof(tv)); + ExpectIntEQ(wolfSSL_DTLSv1_get_timeout(ssl, &tv), 0); + /* NULL arguments are tolerated. */ + ExpectIntEQ(wolfSSL_DTLSv1_get_timeout(NULL, NULL), 0); +#ifndef NO_WOLFSSL_STUB + ExpectIntEQ(wolfSSL_DTLSv1_handle_timeout(ssl), 0); + wolfSSL_DTLSv1_set_initial_timeout_duration(ssl, 1000); +#endif + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_dtls13_set_send_more_acks(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_TLS13) && \ + !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_3_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* Toggle the send-more-acks option (void return). */ + wolfSSL_dtls13_set_send_more_acks(ssl, 1); + wolfSSL_dtls13_set_send_more_acks(ssl, 0); + /* NULL is tolerated. */ + wolfSSL_dtls13_set_send_more_acks(NULL, 1); + /* Quick-timeout flag defaults to off. */ + ExpectIntEQ(wolfSSL_dtls13_use_quick_timeout(ssl), 0); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_dtls_srtp_keying_material(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) && \ + defined(WOLFSSL_SRTP) && defined(HAVE_KEYING_MATERIAL) && \ + !defined(WOLFSSL_NO_TLS12) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + const WOLFSSL_SRTP_PROTECTION_PROFILE* profile = NULL; + unsigned char keyMaterial[64]; + size_t olen = 0; + const char* profileStr = "SRTP_AES128_CM_SHA1_80"; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), 0); + + /* No profile selected before the handshake. */ + ExpectNull(wolfSSL_get_selected_srtp_profile(NULL)); + + /* NULL arguments fail. */ + olen = sizeof(keyMaterial); + ExpectIntEQ(wolfSSL_export_dtls_srtp_keying_material(NULL, keyMaterial, + &olen), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + /* Exporting before SRTP is negotiated reports a missing extension. */ + ExpectIntEQ(wolfSSL_export_dtls_srtp_keying_material(ssl_c, keyMaterial, + &olen), WC_NO_ERR_TRACE(EXT_MISSING)); + + /* Request SRTP on both ends (0 == success, OpenSSL convention). */ + ExpectIntEQ(wolfSSL_set_tlsext_use_srtp(ssl_c, profileStr), 0); + ExpectIntEQ(wolfSSL_set_tlsext_use_srtp(ssl_s, profileStr), 0); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + /* A profile is now selected. */ + ExpectNotNull(profile = wolfSSL_get_selected_srtp_profile(ssl_c)); + + /* Length-only query (out == NULL). */ + olen = 0; + ExpectIntEQ(wolfSSL_export_dtls_srtp_keying_material(ssl_c, NULL, &olen), + WC_NO_ERR_TRACE(LENGTH_ONLY_E)); + ExpectIntGT((int)olen, 0); + ExpectIntLE((int)olen, (int)sizeof(keyMaterial)); + /* A buffer smaller than the keying material reports BUFFER_E. */ + olen = 1; + ExpectIntEQ(wolfSSL_export_dtls_srtp_keying_material(ssl_c, keyMaterial, + &olen), WC_NO_ERR_TRACE(BUFFER_E)); + /* Export the keying material into a large enough buffer. */ + olen = sizeof(keyMaterial); +#ifdef WOLFSSL_OPENVPN + ExpectIntEQ(wolfSSL_export_dtls_srtp_keying_material(ssl_c, keyMaterial, + &olen), WOLFSSL_SUCCESS); +#else + /* Arrays aren't saved without WOLFSSL_OPENVPN. */ + ExpectIntEQ(wolfSSL_export_dtls_srtp_keying_material(ssl_c, keyMaterial, + &olen), WOLFSSL_FAILURE); +#endif + +#ifndef NO_WOLFSSL_STUB + /* Stub returns NULL. */ + ExpectNull(wolfSSL_get_srtp_profiles(ssl_c)); +#endif + + wolfSSL_free(ssl_s); + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_s); + wolfSSL_CTX_free(ctx_c); +#endif + return EXPECT_RESULT(); +} + +#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_MULTICAST) && \ + (defined(WOLFSSL_TLS13) || defined(WOLFSSL_SNIFFER)) && \ + !defined(NO_WOLFSSL_CLIENT) +static int test_dtls_mcast_highwater_cb(unsigned short peerId, + unsigned int maxSeq, unsigned int curSeq, void* ctx) +{ + (void)peerId; + (void)maxSeq; + (void)curSeq; + (void)ctx; + return 0; +} +#endif + +int test_wolfSSL_mcast_peers(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_MULTICAST) && \ + (defined(WOLFSSL_TLS13) || defined(WOLFSSL_SNIFFER)) && \ + !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + int hwCtx = 0; + + ExpectIntGT(wolfSSL_mcast_get_max_peers(), 0); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method())); + ExpectIntEQ(wolfSSL_CTX_mcast_set_member_id(ctx, 0), WOLFSSL_SUCCESS); + + /* Highwater callback argument validation. */ + ExpectIntEQ(wolfSSL_CTX_mcast_set_highwater_cb(NULL, 320, 100, 200, + test_dtls_mcast_highwater_cb), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_CTX_mcast_set_highwater_cb(ctx, 320, 100, 200, NULL), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_CTX_mcast_set_highwater_cb(ctx, 320, 100, 200, + test_dtls_mcast_highwater_cb), WOLFSSL_SUCCESS); + + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + ExpectIntEQ(wolfSSL_mcast_set_highwater_ctx(NULL, &hwCtx), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_mcast_set_highwater_ctx(ssl, &hwCtx), WOLFSSL_SUCCESS); + + /* Add, query and remove a multicast peer. */ + ExpectIntEQ(wolfSSL_mcast_peer_add(NULL, 1, 0), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_mcast_peer_add(ssl, 1, 0), WOLFSSL_SUCCESS); + /* Known peer that has not sent data yet -> 0. */ + ExpectIntEQ(wolfSSL_mcast_peer_known(ssl, 1), 0); + /* Unknown peer -> 0. */ + ExpectIntEQ(wolfSSL_mcast_peer_known(ssl, 2), 0); + ExpectIntEQ(wolfSSL_mcast_peer_known(NULL, 1), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + /* Once the peer has received data (non-zero sequence number) it is + * reported as known. */ + if (ssl != NULL) { + int j; + for (j = 0; j < WOLFSSL_DTLS_PEERSEQ_SZ; j++) { + if (ssl->keys.peerSeq[j].peerId == 1) { + ssl->keys.peerSeq[j].nextSeq_lo = 1; + break; + } + } + } + ExpectIntEQ(wolfSSL_mcast_peer_known(ssl, 1), 1); + /* Remove the peer (sub = 1). */ + ExpectIntEQ(wolfSSL_mcast_peer_add(ssl, 1, 1), WOLFSSL_SUCCESS); + + /* Re-adding a peer that is already present reports an error. */ + ExpectIntEQ(wolfSSL_mcast_peer_add(ssl, 5, 0), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_mcast_peer_add(ssl, 5, 0), WOLFSSL_FATAL_ERROR); + ExpectIntEQ(wolfSSL_mcast_peer_add(ssl, 5, 1), WOLFSSL_SUCCESS); + + /* Filling every peer slot then adding another peer overflows the list. */ +#if WOLFSSL_DTLS_PEERSEQ_SZ <= 255 + { + int idx; + for (idx = 0; idx < WOLFSSL_DTLS_PEERSEQ_SZ && !EXPECT_FAIL(); idx++) { + ExpectIntEQ(wolfSSL_mcast_peer_add(ssl, (word16)idx, 0), + WOLFSSL_SUCCESS); + } + ExpectIntEQ(wolfSSL_mcast_peer_add(ssl, + (word16)WOLFSSL_DTLS_PEERSEQ_SZ, 0), WOLFSSL_FATAL_ERROR); + } +#endif + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_set_dtls_fd_connected(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && !defined(NO_WOLFSSL_CLIENT) && \ + !defined(WOLFSSL_NO_TLS12) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectIntEQ(wolfSSL_set_dtls_fd_connected(NULL, 0), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntEQ(wolfSSL_set_dtls_fd_connected(ssl, 1), WOLFSSL_SUCCESS); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_dtls_get_peer(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && !defined(NO_WOLFSSL_CLIENT) && \ + !defined(WOLFSSL_NO_TLS12) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + unsigned char peer[16]; + unsigned int peerSz = (unsigned int)sizeof(peer); + + ExpectIntEQ(wolfSSL_dtls_get_peer(NULL, peer, &peerSz), WOLFSSL_FAILURE); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* No peer set yet. */ + peerSz = (unsigned int)sizeof(peer); + ExpectIntEQ(wolfSSL_dtls_get_peer(ssl, peer, &peerSz), WOLFSSL_FAILURE); + + /* Set then retrieve the peer. */ + ExpectIntEQ(wolfSSL_dtls_set_peer(ssl, (void*)"1234", 5), WOLFSSL_SUCCESS); + peerSz = (unsigned int)sizeof(peer); + ExpectIntEQ(wolfSSL_dtls_get_peer(ssl, peer, &peerSz), WOLFSSL_SUCCESS); + ExpectIntEQ(peerSz, 5); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_dtls_set_peer(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && !defined(NO_WOLFSSL_CLIENT) && \ + !defined(WOLFSSL_NO_TLS12) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + unsigned char peer[16]; + unsigned int peerSz = (unsigned int)sizeof(peer); + + ExpectIntEQ(wolfSSL_dtls_set_peer(NULL, (void*)"1234", 5), WOLFSSL_FAILURE); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* Set a peer then read it back. */ + ExpectIntEQ(wolfSSL_dtls_set_peer(ssl, (void*)"1234", 5), WOLFSSL_SUCCESS); + peerSz = (unsigned int)sizeof(peer); + ExpectIntEQ(wolfSSL_dtls_get_peer(ssl, peer, &peerSz), WOLFSSL_SUCCESS); + ExpectIntEQ(peerSz, 5); + + /* A larger peer grows the buffer, freeing the previous one. */ + ExpectIntEQ(wolfSSL_dtls_set_peer(ssl, (void*)"123456789012", 12), + WOLFSSL_SUCCESS); + peerSz = (unsigned int)sizeof(peer); + ExpectIntEQ(wolfSSL_dtls_get_peer(ssl, peer, &peerSz), WOLFSSL_SUCCESS); + ExpectIntEQ(peerSz, 12); + + /* Clearing the peer with NULL/0 frees the stored address. */ + ExpectIntEQ(wolfSSL_dtls_set_peer(ssl, NULL, 0), WOLFSSL_SUCCESS); + peerSz = (unsigned int)sizeof(peer); + ExpectIntEQ(wolfSSL_dtls_get_peer(ssl, peer, &peerSz), WOLFSSL_FAILURE); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_GetDtlsMacSecret(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_AEAD_ONLY) + /* NULL ssl returns NULL. */ + ExpectNull(wolfSSL_GetDtlsMacSecret(NULL, 0, 0)); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_dtls_get_using_nonblock(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && !defined(NO_WOLFSSL_CLIENT) && \ + !defined(WOLFSSL_NO_TLS12) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectIntEQ(wolfSSL_dtls_get_using_nonblock(NULL), WOLFSSL_FAILURE); + + /* DTLS object: default is off. */ + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntEQ(wolfSSL_dtls_get_using_nonblock(ssl), 0); + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); + ssl = NULL; + ctx = NULL; + +#ifndef WOLFSSL_NO_TLS12 + /* Non-DTLS object takes the deprecated-use branch and returns 0. */ + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntEQ(wolfSSL_dtls_get_using_nonblock(ssl), 0); + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_dtls_set_using_nonblock(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_LEANPSK) && \ + !defined(NO_WOLFSSL_CLIENT) && !defined(WOLFSSL_NO_TLS12) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + /* NULL is a no-op (must not crash). */ + wolfSSL_dtls_set_using_nonblock(NULL, 1); + + /* DTLS object: value is stored and read back. */ + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + wolfSSL_dtls_set_using_nonblock(ssl, 1); + ExpectIntEQ(wolfSSL_dtls_get_using_nonblock(ssl), 1); + wolfSSL_dtls_set_using_nonblock(ssl, 0); + ExpectIntEQ(wolfSSL_dtls_get_using_nonblock(ssl), 0); + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); + ssl = NULL; + ctx = NULL; + +#ifndef WOLFSSL_NO_TLS12 + /* Non-DTLS object takes the deprecated-use branch. */ + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + wolfSSL_dtls_set_using_nonblock(ssl, 1); + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_set_mtu_compat(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && defined(OPENSSL_EXTRA) && \ + (defined(WOLFSSL_SCTP) || defined(WOLFSSL_DTLS_MTU)) && \ + !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* A reasonable MTU succeeds. */ + ExpectIntEQ(wolfSSL_set_mtu_compat(ssl, 1500), WOLFSSL_SUCCESS); + /* An MTU larger than a record fails. */ + ExpectIntEQ(wolfSSL_set_mtu_compat(ssl, 0xFFFF), WOLFSSL_FAILURE); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_dtls_set_timeout_max(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_LEANPSK) && \ + !defined(NO_WOLFSSL_CLIENT) && !defined(WOLFSSL_NO_TLS12) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectIntEQ(wolfSSL_dtls_set_timeout_max(NULL, 5), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* Negative timeout fails. */ + ExpectIntEQ(wolfSSL_dtls_set_timeout_max(ssl, -1), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + /* Valid maximum succeeds. */ + ExpectIntEQ(wolfSSL_dtls_set_timeout_max(ssl, 5), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_dtls_set_timeout_init(ssl, 3), WOLFSSL_SUCCESS); + /* Maximum less than the initial timeout fails. */ + ExpectIntEQ(wolfSSL_dtls_set_timeout_max(ssl, 2), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_CTX_mcast_set_member_id(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_MULTICAST) && \ + (defined(WOLFSSL_TLS13) || defined(WOLFSSL_SNIFFER)) && \ + !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + + ExpectIntEQ(wolfSSL_CTX_mcast_set_member_id(NULL, 0), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method())); + /* Member id out of range (> 8-bit) fails. */ + ExpectIntEQ(wolfSSL_CTX_mcast_set_member_id(ctx, 256), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + /* Valid member id succeeds. */ + ExpectIntEQ(wolfSSL_CTX_mcast_set_member_id(ctx, 0), WOLFSSL_SUCCESS); + + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_mcast_read(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_MULTICAST) && \ + (defined(WOLFSSL_TLS13) || defined(WOLFSSL_SNIFFER)) && \ + !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + word16 id = 0; + byte buf[16]; + + ExpectIntEQ(wolfSSL_mcast_read(NULL, &id, buf, (int)sizeof(buf)), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method())); + ExpectIntEQ(wolfSSL_CTX_mcast_set_member_id(ctx, 0), WOLFSSL_SUCCESS); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* Negative size fails. */ + ExpectIntEQ(wolfSSL_mcast_read(ssl, &id, buf, -1), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_dtls_got_timeout(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_LEANPSK) && \ + !defined(NO_WOLFSSL_CLIENT) + /* NULL object fails. */ + ExpectIntEQ(wolfSSL_dtls_got_timeout(NULL), WOLFSSL_FATAL_ERROR); +#ifndef WOLFSSL_NO_TLS12 + { + /* A non-DTLS object also fails. */ + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl), WOLFSSL_FATAL_ERROR); + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); + } +#endif +#endif + +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) && \ + !defined(WOLFSSL_LEANPSK) && !defined(WOLFSSL_NO_TLS12) + { + /* With a DTLS 1.2 flight buffered, a transport that reports want-write + * makes the timeout handler take the pool-send error path. */ + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), 0); + + /* Buffer the ClientHello flight. */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + + /* Resending the flight fails -> error path, returns FATAL_ERROR. */ + test_memio_simulate_want_write(&test_ctx, 1, 1); + ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), WOLFSSL_FATAL_ERROR); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_WRITE); + + /* With the transport unblocked the resend succeeds. */ + test_memio_simulate_want_write(&test_ctx, 1, 0); + ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), WOLFSSL_SUCCESS); + + wolfSSL_free(ssl_s); + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_s); + wolfSSL_CTX_free(ctx_c); + } +#endif + +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \ + defined(WOLFSSL_DTLS13) && defined(WOLFSSL_TLS13) + { + /* DTLS 1.3: a want-write while retransmitting takes the + * Dtls13RtxTimeout() error branch. */ + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0); + + /* Buffer the ClientHello flight. */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + + /* Retransmit under want-write fails. */ + test_memio_simulate_want_write(&test_ctx, 1, 1); + ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), WOLFSSL_FATAL_ERROR); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_WRITE); + test_memio_simulate_want_write(&test_ctx, 1, 0); + + wolfSSL_free(ssl_s); + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_s); + wolfSSL_CTX_free(ctx_c); + } +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_DTLS_SetCookieSecret(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && !defined(NO_WOLFSSL_SERVER) && \ + (defined(NO_CERTS) || !defined(NO_RSA)) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + byte secret1[32]; + byte secret2[16]; + + XMEMSET(secret1, 0xA5, sizeof(secret1)); + XMEMSET(secret2, 0x5A, sizeof(secret2)); + + /* NULL object fails. */ + ExpectIntEQ(wolfSSL_DTLS_SetCookieSecret(NULL, secret1, sizeof(secret1)), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_server_method())); +#ifndef NO_CERTS + /* A server WOLFSSL needs a key and certificate set on the context. */ + ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, CERT_FILETYPE), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile, + CERT_FILETYPE), WOLFSSL_SUCCESS); +#endif + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* A non-NULL secret with zero size fails. */ + ExpectIntEQ(wolfSSL_DTLS_SetCookieSecret(ssl, secret1, 0), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* Set an explicit secret (copy path). */ + ExpectIntEQ(wolfSSL_DTLS_SetCookieSecret(ssl, secret1, sizeof(secret1)), 0); + /* A different size frees the old buffer and reallocates. */ + ExpectIntEQ(wolfSSL_DTLS_SetCookieSecret(ssl, secret2, sizeof(secret2)), 0); + /* The same size keeps the existing buffer (no reallocation). */ + ExpectIntEQ(wolfSSL_DTLS_SetCookieSecret(ssl, secret2, sizeof(secret2)), 0); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_set_secret(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_MULTICAST) && \ + (defined(WOLFSSL_TLS13) || defined(WOLFSSL_SNIFFER)) && \ + !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + byte preMasterSecret[16]; + byte clientRandom[32]; + byte serverRandom[32]; + byte suite[2] = { 0, 0xfe }; /* WDM_WITH_NULL_SHA256 */ + + XMEMSET(preMasterSecret, 0x23, sizeof(preMasterSecret)); + XMEMSET(clientRandom, 0xA5, sizeof(clientRandom)); + XMEMSET(serverRandom, 0x5A, sizeof(serverRandom)); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method())); + ExpectIntEQ(wolfSSL_CTX_mcast_set_member_id(ctx, 0), WOLFSSL_SUCCESS); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* Invalid arguments take the error path and return WOLFSSL_FATAL_ERROR. */ + ExpectIntEQ(wolfSSL_set_secret(ssl, 23, NULL, sizeof(preMasterSecret), + clientRandom, serverRandom, suite), WOLFSSL_FATAL_ERROR); + ExpectIntEQ(wolfSSL_set_secret(ssl, 23, preMasterSecret, 0, + clientRandom, serverRandom, suite), WOLFSSL_FATAL_ERROR); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + diff --git a/tests/api/test_dtls.h b/tests/api/test_dtls.h index fd22d125bf..4523cdef1e 100644 --- a/tests/api/test_dtls.h +++ b/tests/api/test_dtls.h @@ -45,6 +45,27 @@ int test_dtls_mtu_fragment_headroom(void); int test_dtls_mtu_split_messages(void); int test_dtls_set_session_min_downgrade(void); int test_dtls12_export_import_etm(void); +int test_wolfSSL_dtls_create_free_peer(void); +int test_wolfSSL_dtls_get0_peer(void); +int test_wolfSSL_dtls_set_timeout_init(void); +int test_wolfSSL_dtls_retransmit(void); +int test_wolfSSL_DTLSv1_compat_timeouts(void); +int test_wolfSSL_dtls13_set_send_more_acks(void); +int test_wolfSSL_dtls_srtp_keying_material(void); +int test_wolfSSL_mcast_peers(void); +int test_wolfSSL_set_dtls_fd_connected(void); +int test_wolfSSL_dtls_get_peer(void); +int test_wolfSSL_dtls_set_peer(void); +int test_wolfSSL_GetDtlsMacSecret(void); +int test_wolfSSL_dtls_get_using_nonblock(void); +int test_wolfSSL_dtls_set_using_nonblock(void); +int test_wolfSSL_set_mtu_compat(void); +int test_wolfSSL_dtls_set_timeout_max(void); +int test_wolfSSL_CTX_mcast_set_member_id(void); +int test_wolfSSL_mcast_read(void); +int test_wolfSSL_dtls_got_timeout(void); +int test_wolfSSL_DTLS_SetCookieSecret(void); +int test_wolfSSL_set_secret(void); /* DTLS tests moved out of tests/api.c. */ int test_dtls_msg_from_other_peer(void); @@ -105,7 +126,8 @@ int test_WOLFSSL_dtls_version_alert(void); TEST_DECL_GROUP("dtls", test_dtls_set_session_min_downgrade), \ TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_export), \ TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_export_peers), \ - TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_import_state_extra_window_words), \ + TEST_DECL_GROUP("dtls", \ + test_wolfSSL_dtls_import_state_extra_window_words), \ TEST_DECL_GROUP("dtls", test_wolfSSL_DTLS_either_side), \ TEST_DECL_GROUP("dtls", test_generate_cookie), \ TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_set_mtu), \ @@ -135,5 +157,30 @@ int test_WOLFSSL_dtls_version_alert(void); TEST_DECL_GROUP("dtls", test_dtls_seq_num_downgrade), \ TEST_DECL_GROUP("dtls", test_dtls_old_seq_number), \ TEST_DECL_GROUP("dtls", test_dtls12_missing_finished), \ - TEST_DECL_GROUP("dtls", test_dtls12_export_import_etm) + TEST_DECL_GROUP("dtls", test_dtls12_export_import_etm), \ + TEST_DECL_GROUP("dtls", test_dtls13_min_rtx_interval), \ + TEST_DECL_GROUP("dtls", test_dtls13_no_session_id_echo), \ + TEST_DECL_GROUP("dtls", test_dtls13_oversized_cert_chain), \ + TEST_DECL_GROUP("dtls", test_dtls_set_session_min_downgrade), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_create_free_peer), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_get0_peer), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_set_timeout_init), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_retransmit), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_DTLSv1_compat_timeouts), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_dtls13_set_send_more_acks), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_srtp_keying_material), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_mcast_peers), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_set_dtls_fd_connected), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_get_peer), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_set_peer), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_GetDtlsMacSecret), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_get_using_nonblock), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_set_using_nonblock), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_set_mtu_compat), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_set_timeout_max), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_CTX_mcast_set_member_id), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_mcast_read), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_got_timeout), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_DTLS_SetCookieSecret), \ + TEST_DECL_GROUP("dtls", test_wolfSSL_set_secret) #endif /* TESTS_API_DTLS_H */ diff --git a/tests/api/test_ed25519.c b/tests/api/test_ed25519.c index e68505b862..1858f4d71a 100644 --- a/tests/api/test_ed25519.c +++ b/tests/api/test_ed25519.c @@ -811,6 +811,7 @@ int test_wc_ed25519_reject_small_order_keys(void) 0x2a,0x20,0x53,0xfa,0x2c,0x39,0xcc,0xc6, 0x4e,0xc7,0xfd,0x77,0x92,0xac,0x03,0xfa}, }; +#ifndef NO_ED25519_VERIFY /* Forged signature: R = B (base point), S = 1. * With public key A = identity, S*B - h*A = B = R for any message. */ static const byte forged_sig[ED25519_SIG_SIZE] = { @@ -823,6 +824,7 @@ int test_wc_ed25519_reject_small_order_keys(void) 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; +#endif ed25519_key key; word32 i; word32 num_keys = (word32)(sizeof(small_order_keys) / ED25519_PUB_KEY_SIZE); @@ -864,6 +866,7 @@ int test_wc_ed25519_reject_small_order_keys(void) wc_ed25519_free(&key); } +#ifndef NO_ED25519_VERIFY /* (3) Even a "trusted" import (which bypasses wc_ed25519_check_key) * must not let wc_ed25519_verify_msg accept a forged signature against * an identity public key. Test both the canonical encoding (y = 1, @@ -902,6 +905,7 @@ int test_wc_ed25519_reject_small_order_keys(void) wc_ed25519_free(&key); } } +#endif #endif return EXPECT_RESULT(); } diff --git a/tests/api/test_ed448.c b/tests/api/test_ed448.c index 6bb7934615..4d98b02f93 100644 --- a/tests/api/test_ed448.c +++ b/tests/api/test_ed448.c @@ -760,6 +760,7 @@ int test_wc_ed448_reject_small_order_keys(void) 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x80}, }; +#ifndef NO_ED448_VERIFY /* Arbitrary signature bytes: S = 1 (must be below the Ed448 group * order or wc_ed448_verify_msg() returns BAD_FUNC_ARG before the * small-order check has a chance to fire). The R bytes do not need @@ -788,6 +789,7 @@ int test_wc_ed448_reject_small_order_keys(void) 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00 }; +#endif ed448_key key; word32 i; word32 num_keys = (word32)(sizeof(small_order_keys) / ED448_PUB_KEY_SIZE); @@ -829,6 +831,7 @@ int test_wc_ed448_reject_small_order_keys(void) wc_ed448_free(&key); } +#ifndef NO_ED448_VERIFY /* (3) Even a "trusted" import (which bypasses wc_ed448_check_key) * must not let wc_ed448_verify_msg accept a forged signature against * an identity public key. Test both the canonical encoding (y = 1, @@ -866,6 +869,7 @@ int test_wc_ed448_reject_small_order_keys(void) wc_ed448_free(&key); } } +#endif #endif return EXPECT_RESULT(); } diff --git a/tests/api/test_evp_cipher.c b/tests/api/test_evp_cipher.c index 492e6b9a62..a6643e9ad1 100644 --- a/tests/api/test_evp_cipher.c +++ b/tests/api/test_evp_cipher.c @@ -501,6 +501,28 @@ int test_wolfSSL_EVP_CIPHER_iv_length(void) #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) NID_chacha20_poly1305, #endif + #ifdef WOLFSSL_AES_CFB + #ifdef WOLFSSL_AES_128 + NID_aes_128_cfb128, + #endif + #ifdef WOLFSSL_AES_192 + NID_aes_192_cfb128, + #endif + #ifdef WOLFSSL_AES_256 + NID_aes_256_cfb128, + #endif + #endif /* WOLFSSL_AES_CFB */ + #ifdef WOLFSSL_AES_OFB + #ifdef WOLFSSL_AES_128 + NID_aes_128_ofb, + #endif + #ifdef WOLFSSL_AES_192 + NID_aes_192_ofb, + #endif + #ifdef WOLFSSL_AES_256 + NID_aes_256_ofb, + #endif + #endif /* WOLFSSL_AES_OFB */ }; int iv_lengths[] = { #if defined(HAVE_AES_CBC) || defined(WOLFSSL_AES_DIRECT) @@ -546,6 +568,28 @@ int test_wolfSSL_EVP_CIPHER_iv_length(void) #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) CHACHA20_POLY1305_AEAD_IV_SIZE, #endif + #ifdef WOLFSSL_AES_CFB + #ifdef WOLFSSL_AES_128 + AES_BLOCK_SIZE, + #endif + #ifdef WOLFSSL_AES_192 + AES_BLOCK_SIZE, + #endif + #ifdef WOLFSSL_AES_256 + AES_BLOCK_SIZE, + #endif + #endif /* WOLFSSL_AES_CFB */ + #ifdef WOLFSSL_AES_OFB + #ifdef WOLFSSL_AES_128 + AES_BLOCK_SIZE, + #endif + #ifdef WOLFSSL_AES_192 + AES_BLOCK_SIZE, + #endif + #ifdef WOLFSSL_AES_256 + AES_BLOCK_SIZE, + #endif + #endif /* WOLFSSL_AES_OFB */ }; int i; int nidsLen = (sizeof(nids)/sizeof(int)); diff --git a/tests/api/test_evp_pkey.c b/tests/api/test_evp_pkey.c index 6b15f38d96..9bdd5b9339 100644 --- a/tests/api/test_evp_pkey.c +++ b/tests/api/test_evp_pkey.c @@ -2563,7 +2563,8 @@ int test_wolfSSL_EVP_PKEY_print_public(void) int test_wolfSSL_EVP_PKEY_ed25519(void) { EXPECT_DECLS; -#if defined(OPENSSL_EXTRA) && defined(HAVE_ED25519) +#if defined(OPENSSL_EXTRA) && defined(HAVE_ED25519) && \ + defined(HAVE_ED25519_KEY_IMPORT) WOLFSSL_EVP_PKEY* pkey = NULL; const unsigned char* p; @@ -2623,7 +2624,8 @@ int test_wolfSSL_CTX_use_PrivateKey_ed25519(void) { EXPECT_DECLS; #if defined(OPENSSL_EXTRA) && defined(HAVE_ED25519) && \ - !defined(NO_WOLFSSL_SERVER) && !defined(NO_TLS) + defined(HAVE_ED25519_KEY_IMPORT) && !defined(NO_WOLFSSL_SERVER) && \ + !defined(NO_TLS) WOLFSSL_CTX* ctx = NULL; WOLFSSL_EVP_PKEY* pkey = NULL; const unsigned char* p; @@ -2653,7 +2655,8 @@ int test_wolfSSL_CTX_use_PrivateKey_ed25519(void) int test_wolfSSL_EVP_PKEY_ed448(void) { EXPECT_DECLS; -#if defined(OPENSSL_EXTRA) && defined(HAVE_ED448) +#if defined(OPENSSL_EXTRA) && defined(HAVE_ED448) && \ + defined(HAVE_ED448_KEY_IMPORT) WOLFSSL_EVP_PKEY* pkey = NULL; const unsigned char* p; diff --git a/tests/api/test_lms_xmss.c b/tests/api/test_lms_xmss.c index 2dc3ff2158..63a0c4ba9a 100644 --- a/tests/api/test_lms_xmss.c +++ b/tests/api/test_lms_xmss.c @@ -30,6 +30,9 @@ #include #include +#ifdef HAVE_ECC +#include +#endif #include #include #include @@ -230,11 +233,14 @@ int test_wc_LmsKey_reload_cache(void) * standard ISARA OIDs and wraps the raw RFC 8391 pub key in an OCTET * STRING, so the fixtures were produced with a small generator that * overrides the AlgorithmIdentifier and SPKI to match RFC 9802. */ -#if (defined(WOLFSSL_HAVE_LMS) || defined(WOLFSSL_HAVE_XMSS)) && \ - !defined(NO_FILESYSTEM) && !defined(NO_CERTS) -/* Sanity bound on a test fixture cert. The largest BC-generated - * fixture we ship (XMSS^MT 40/8) is ~19 KiB; 1 MiB is well above - * any realistic RFC 9802 cert and catches a wild XFTELL. Typed as +/* Only the LMS interop-anchor verification still loads a committed fixture + * (bc_lms_native_bc_root.der); everything else is generated in-process. Gate + * these file helpers on exactly that call site to avoid an unused-function + * warning in XMSS-only or truncated-hash builds. */ +#if defined(WOLFSSL_HAVE_LMS) && !defined(NO_FILESYSTEM) && \ + !defined(NO_CERTS) && !defined(WOLFSSL_NO_LMS_SHA256_256) +/* Sanity bound on a test fixture cert. 1 MiB is well above any realistic + * RFC 9802 cert and catches a wild XFTELL. Typed as * long to match XFTELL's return so the size comparison below isn't * a mixed long-vs-int compare. */ #define RFC9802_TEST_MAX_CERT_SIZE ((long)(1L << 20)) @@ -288,8 +294,8 @@ static int rfc9802_load_file(const char* path, byte** out, int* outLen) return EXPECT_RESULT(); } -static int rfc9802_verify_one_cert(const char* path, word32 expectedKeyOID, - word32 expectedSigOID) +static WC_MAYBE_UNUSED int rfc9802_verify_one_cert(const char* path, + word32 expectedKeyOID, word32 expectedSigOID) { EXPECT_DECLS; byte* buf = NULL; @@ -512,6 +518,7 @@ static int rfc9802_xmss_import_negative(void) wc_XmssKey_Free(&key); } +#if !defined(WOLFSSL_XMSS_MIN_HEIGHT) || (WOLFSSL_XMSS_MIN_HEIGHT <= 10) /* Once params have been configured (state != INITED), the OID * prefix in the raw key MUST match key->oid and is_xmssmt MUST * match key->is_xmssmt. Set XMSS-SHA2_10_256 and feed a valid- @@ -561,10 +568,12 @@ static int rfc9802_xmss_import_negative(void) ExpectIntEQ((int)key.is_xmssmt, 0); wc_XmssKey_Free(&key); + #if WOLFSSL_XMSS_MAX_HEIGHT >= 20 ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0); ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, buf, sizeof(buf), 1), 0); ExpectIntEQ((int)key.is_xmssmt, 1); wc_XmssKey_Free(&key); + #endif } /* Lenient state: re-importing the same pub key into a VERIFYONLY @@ -635,222 +644,38 @@ static int rfc9802_xmss_import_negative(void) WC_NO_ERR_TRACE(BAD_STATE_E)); wc_XmssKey_Free(&key); } +#endif return EXPECT_RESULT(); } #endif -/* Walk the AlgorithmIdentifier SEQUENCE that begins at sigIndex and - * locate the byte offset of the last byte of its OID content. Handles - * both short-form (length < 128) and long-form DER length encodings, - * so a future fixture-regenerator that emits longer OIDs / SEQUENCEs - * still drives this test rather than tripping the loud-fail branch. - * - * Returns 0 on success with *oidLastByte set; returns -1 on any DER - * shape mismatch. */ -#if defined(WOLFSSL_HAVE_XMSS) && !defined(NO_FILESYSTEM) && !defined(NO_CERTS) -static int rfc9802_find_sig_alg_oid_last_byte(const byte* buf, word32 bufLen, - word32 sigIndex, word32* oidLastByte) +/* Collect the byte offset of the final sub-identifier of every + * 1.3.6.1.5.5.7.6. OID in a DER cert (XMSS ends 0x22, XMSS^MT ends + * 0x23). RFC 9802 reuses the same OID for the SubjectPublicKeyInfo algorithm, + * the TBS signatureAlgorithm and the outer signatureAlgorithm, so a conformant + * XMSS/XMSS^MT cert contains exactly three, in TBS-signature / SPKI-key / + * outer-signature order. Returns the number of occurrences found. */ +#if defined(WOLFSSL_ASN_TEMPLATE) && defined(WOLFSSL_HAVE_XMSS) && \ + !defined(WOLFSSL_XMSS_VERIFY_ONLY) && defined(WOLFSSL_CERT_GEN) && \ + !defined(NO_FILESYSTEM) && !defined(NO_CERTS) +static int rfc9802_collect_hbs_oid_offsets(const byte* der, word32 derSz, + byte lastByte, word32* offsets, int maxOff) { - word32 idx = sigIndex; - word32 oidContentLen = 0; + /* OID body for 1.3.6.1.5.5.7.6: 2B 06 01 05 05 07 06, then . */ + static const byte pfx[] = { 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x06 }; + int n = 0; + word32 i; - /* AlgorithmIdentifier ::= SEQUENCE { algorithm OID, ... } */ - if (idx >= bufLen || buf[idx] != 0x30) - return -1; - idx++; - /* Skip SEQUENCE length (short or long form). */ - if (idx >= bufLen) - return -1; - if (buf[idx] < 0x80) { - idx++; - } - else { - word32 nbytes = (word32)(buf[idx] & 0x7F); - if (nbytes == 0 || nbytes > 4 || idx + 1 + nbytes > bufLen) - return -1; - idx += 1 + nbytes; - } - /* algorithm OID tag. */ - if (idx >= bufLen || buf[idx] != 0x06) - return -1; - idx++; - /* OID length (short or long form). */ - if (idx >= bufLen) - return -1; - if (buf[idx] < 0x80) { - oidContentLen = buf[idx]; - idx++; - } - else { - word32 nbytes = (word32)(buf[idx] & 0x7F); - word32 i; - if (nbytes == 0 || nbytes > 4 || idx + 1 + nbytes > bufLen) - return -1; - for (i = 0; i < nbytes; i++) - oidContentLen = (oidContentLen << 8) | buf[idx + 1 + i]; - idx += 1 + nbytes; - } - if (oidContentLen == 0 || idx + oidContentLen > bufLen) - return -1; - *oidLastByte = idx + oidContentLen - 1; - return 0; -} - -/* Helper: load fixture, locate last byte of outer signatureAlgorithm - * OID, patch it from `expected` to `swap`, and assert that verifying - * the patched cert against itself as a trust anchor fails. */ -static int rfc9802_assert_oid_patch_breaks_verify(const char* path, - byte expectedLastByte, byte patchedLastByte) -{ - EXPECT_DECLS; - byte* buf = NULL; - int bytes = 0; - DecodedCert cert; - WOLFSSL_CERT_MANAGER* cm = NULL; - word32 sigIndex = 0; - word32 lastOidByte = 0; - - ExpectIntEQ(rfc9802_load_file(path, &buf, &bytes), TEST_SUCCESS); - if (buf == NULL) - return TEST_FAIL; - - wc_InitDecodedCert(&cert, buf, (word32)bytes, NULL); - ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL), 0); - sigIndex = cert.sigIndex; - wc_FreeDecodedCert(&cert); - - ExpectIntEQ(rfc9802_find_sig_alg_oid_last_byte(buf, (word32)bytes, - sigIndex, &lastOidByte), 0); - /* Sanity-check the fixture matches the family the caller asserted, - * so a future regenerator swapping fixtures fails loudly here - * rather than silently testing the wrong direction. */ - ExpectIntEQ((int)buf[lastOidByte], (int)expectedLastByte); - - if (lastOidByte < (word32)bytes && - buf[lastOidByte] == expectedLastByte) { - buf[lastOidByte] = patchedLastByte; - ExpectNotNull(cm = wolfSSL_CertManagerNew()); - /* After the patch the cert's outer signatureAlgorithm and SPKI - * disagree. Verification must fail somewhere (at parse, at - * load, or at ConfirmSignature). The load is best-effort - - * some shape changes get caught there, others only at verify. */ - (void)wolfSSL_CertManagerLoadCABuffer(cm, buf, (long)bytes, - WOLFSSL_FILETYPE_ASN1); - ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, buf, - (long)bytes, WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); - if (cm != NULL) { - wolfSSL_CertManagerFree(cm); - cm = NULL; + for (i = 0; (word32)(i + sizeof(pfx)) < derSz; i++) { + if (XMEMCMP(der + i, pfx, sizeof(pfx)) == 0 && + der[i + sizeof(pfx)] == lastByte) { + if (n < maxOff) + offsets[n] = i + (word32)sizeof(pfx); + n++; } } - - XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return EXPECT_RESULT(); -} - -/* X.509-level negative: swap the outer signatureAlgorithm OID byte so - * the cert declares XMSS where the SPKI is XMSS^MT, and vice versa. - * SigOidMatchesKeyOid must reject both directions before any crypto. */ -static int rfc9802_xmss_sig_oid_mismatch(void) -{ - EXPECT_DECLS; - /* XMSS sigOID ends 0x22; XMSS^MT sigOID ends 0x23. Patch each - * direction so the asymmetric-key path is exercised both ways - - * a regression that only stripped the check from one branch of - * SigOidMatchesKeyOid would otherwise be missed. */ - ExpectIntEQ(rfc9802_assert_oid_patch_breaks_verify( - "./certs/xmss/bc_xmss_sha2_10_256_root.der", - /* expected XMSS */ 0x22, /* patched to XMSS^MT */ 0x23), - TEST_SUCCESS); - ExpectIntEQ(rfc9802_assert_oid_patch_breaks_verify( - "./certs/xmss/bc_xmssmt_sha2_20_2_256_root.der", - /* expected XMSS^MT */ 0x23, /* patched to XMSS */ 0x22), - TEST_SUCCESS); - return EXPECT_RESULT(); -} -#endif - -/* Exercise a real CA -> leaf certificate chain, not just self-signed. - * Loads the CA as a trust anchor and verifies the leaf against it. */ -#if defined(WOLFSSL_HAVE_LMS) && !defined(NO_FILESYSTEM) && !defined(NO_CERTS) -static int rfc9802_lms_chain_verify(void) -{ - EXPECT_DECLS; - byte* caBuf = NULL; - byte* leafBuf = NULL; - int caLen = 0; - int leafLen = 0; - WOLFSSL_CERT_MANAGER* cm = NULL; - - ExpectIntEQ(rfc9802_load_file("./certs/lms/bc_lms_chain_ca.der", - &caBuf, &caLen), TEST_SUCCESS); - ExpectIntEQ(rfc9802_load_file("./certs/lms/bc_lms_chain_leaf.der", - &leafBuf, &leafLen), TEST_SUCCESS); - - ExpectNotNull(cm = wolfSSL_CertManagerNew()); - /* Only the CA is a trust anchor; the leaf is verified against it. */ - ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, caBuf, (long)caLen, - WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); - ExpectIntEQ(wolfSSL_CertManagerVerifyBuffer(cm, leafBuf, (long)leafLen, - WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); - - /* Without loading the CA the leaf must NOT verify. */ - if (cm != NULL) { - wolfSSL_CertManagerFree(cm); - cm = NULL; - } - ExpectNotNull(cm = wolfSSL_CertManagerNew()); - ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, leafBuf, (long)leafLen, - WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); - if (cm != NULL) { - wolfSSL_CertManagerFree(cm); - cm = NULL; - } - - XFREE(leafBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(caBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return EXPECT_RESULT(); -} -#endif - -/* Mirror of rfc9802_lms_chain_verify but for an XMSS CA -> leaf pair. */ -#if defined(WOLFSSL_HAVE_XMSS) && !defined(NO_FILESYSTEM) && !defined(NO_CERTS) -static int rfc9802_xmss_chain_verify(void) -{ - EXPECT_DECLS; - byte* caBuf = NULL; - byte* leafBuf = NULL; - int caLen = 0; - int leafLen = 0; - WOLFSSL_CERT_MANAGER* cm = NULL; - - ExpectIntEQ(rfc9802_load_file("./certs/xmss/bc_xmss_chain_ca.der", - &caBuf, &caLen), TEST_SUCCESS); - ExpectIntEQ(rfc9802_load_file("./certs/xmss/bc_xmss_chain_leaf.der", - &leafBuf, &leafLen), TEST_SUCCESS); - - ExpectNotNull(cm = wolfSSL_CertManagerNew()); - ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, caBuf, (long)caLen, - WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); - ExpectIntEQ(wolfSSL_CertManagerVerifyBuffer(cm, leafBuf, (long)leafLen, - WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); - - if (cm != NULL) { - wolfSSL_CertManagerFree(cm); - cm = NULL; - } - ExpectNotNull(cm = wolfSSL_CertManagerNew()); - ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, leafBuf, (long)leafLen, - WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); - if (cm != NULL) { - wolfSSL_CertManagerFree(cm); - cm = NULL; - } - - XFREE(leafBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(caBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return EXPECT_RESULT(); + return n; } #endif @@ -860,38 +685,15 @@ int test_rfc9802_lms_x509_verify(void) #if defined(WOLFSSL_HAVE_LMS) #if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && \ !defined(WOLFSSL_NO_LMS_SHA256_256) - /* Mixed single-level LMS and multi-level HSS fixtures. The HSS - * public key carries only the top-level LMS/LM-OTS types, so - * wc_LmsKey_ImportPubRaw's auto-derive path searches the map - * by (levels, lmsType, lmOtsType). The bc_lms_native_bc_root - * fixture is generated through Bouncy Castle's stock - * JcaContentSignerBuilder("LMS") + JcaX509v3CertificateBuilder - * with no overrides; including it here is the cross-impl interop - * gate (BC's native LMS X.509 path is RFC 9802-compliant for HSS/ - * LMS, so wolfSSL must accept it end-to-end). - * - * All fixtures use the SHA-256/M32 family, so the whole block - * is gated on that family being compiled in. Truncated SHA-256/192 - * or SHAKE-only builds skip this block. */ - static const char* const lmsFiles[] = { - "./certs/lms/bc_lms_sha256_h5_w4_root.der", -#if !defined(WOLFSSL_LMS_MAX_HEIGHT) || (WOLFSSL_LMS_MAX_HEIGHT >= 10) - "./certs/lms/bc_lms_sha256_h10_w8_root.der", -#endif -#if !defined(WOLFSSL_LMS_MAX_LEVELS) || (WOLFSSL_LMS_MAX_LEVELS >= 2) - "./certs/lms/bc_hss_L2_H5_W8_root.der", -#endif -#if !defined(WOLFSSL_LMS_MAX_LEVELS) || (WOLFSSL_LMS_MAX_LEVELS >= 3) - "./certs/lms/bc_hss_L3_H5_W4_root.der", -#endif - "./certs/lms/bc_lms_native_bc_root.der", - }; - size_t i; - for (i = 0; i < sizeof(lmsFiles) / sizeof(lmsFiles[0]); i++) { - ExpectIntEQ(rfc9802_verify_one_cert(lmsFiles[i], - HSS_LMSk, CTC_HSS_LMS), TEST_SUCCESS); - } - ExpectIntEQ(rfc9802_lms_chain_verify(), TEST_SUCCESS); + /* Cross-implementation interop gate. bc_lms_native_bc_root.der is + * generated through Bouncy Castle's stock JcaContentSignerBuilder("LMS") + * + JcaX509v3CertificateBuilder with no overrides; BC's native LMS X.509 + * path is RFC 9802-compliant for HSS/LMS, so wolfSSL must accept it + * end-to-end. This is the one fixture from an independent implementation + * that we keep; wolfSSL's own generation is exercised by + * test_rfc9802_lms_x509_gen instead of committed wolfSSL fixtures. */ + ExpectIntEQ(rfc9802_verify_one_cert("./certs/lms/bc_lms_native_bc_root.der", + HSS_LMSk, CTC_HSS_LMS), TEST_SUCCESS); #endif /* !NO_FILESYSTEM && !NO_CERTS && !WOLFSSL_NO_LMS_SHA256_256 */ /* Pure wolfCrypt-level negative tests don't need filesystem or cert * support, so they run for any LMS-enabled build. */ @@ -904,31 +706,551 @@ int test_rfc9802_xmss_x509_verify(void) { EXPECT_DECLS; #if defined(WOLFSSL_HAVE_XMSS) -#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) - static const char* const xmssFiles[] = { - "./certs/xmss/bc_xmss_sha2_10_256_root.der", - "./certs/xmss/bc_xmss_sha2_16_256_root.der", - }; - static const char* const xmssmtFiles[] = { - "./certs/xmss/bc_xmssmt_sha2_20_2_256_root.der", - "./certs/xmss/bc_xmssmt_sha2_20_4_256_root.der", - "./certs/xmss/bc_xmssmt_sha2_40_8_256_root.der", - }; - size_t i; - for (i = 0; i < sizeof(xmssFiles) / sizeof(xmssFiles[0]); i++) { - ExpectIntEQ(rfc9802_verify_one_cert(xmssFiles[i], - XMSSk, CTC_XMSS), TEST_SUCCESS); - } - for (i = 0; i < sizeof(xmssmtFiles) / sizeof(xmssmtFiles[0]); i++) { - ExpectIntEQ(rfc9802_verify_one_cert(xmssmtFiles[i], - XMSSMTk, CTC_XMSSMT), TEST_SUCCESS); - } - ExpectIntEQ(rfc9802_xmss_sig_oid_mismatch(), TEST_SUCCESS); - ExpectIntEQ(rfc9802_xmss_chain_verify(), TEST_SUCCESS); -#endif /* !NO_FILESYSTEM && !NO_CERTS */ - /* Pure wolfCrypt-level negative tests don't need filesystem or cert - * support, so they run for any XMSS-enabled build. */ + /* No independent (RFC 9802-aligned) third-party XMSS X.509 implementation + * exists to interop against - OpenSSL has no XMSS cert signing and Bouncy + * Castle's XMSS encoding is not yet aligned with the final RFC - so there + * is no committed interop fixture here. wolfSSL's own XMSS/XMSS^MT cert + * generation, chain signing and the X.509-level signatureAlgorithm/SPKI + * mismatch rejection are exercised in test_rfc9802_xmss_x509_gen. + * + * Pure wolfCrypt-level negative tests run for any XMSS-enabled build. */ ExpectIntEQ(rfc9802_xmss_import_negative(), TEST_SUCCESS); #endif return EXPECT_RESULT(); } + +/* RFC 9802 certificate/CSR GENERATION tests. + * + * These exercise the cert-gen path (wc_MakeCert_ex / wc_SignCert_ex and + * wc_MakeCertReq_ex) with a freshly generated LMS or XMSS key, then feed + * the result back through the existing verification path to prove the + * generated SubjectPublicKeyInfo, signatureAlgorithm and signature are + * RFC 9802-compliant and self-consistent. */ +/* RFC 9802 cert/CSR generation is only wired into the ASN.1 template + * implementation (the original/non-template path has no LMS/XMSS support), + * so all of these tests require WOLFSSL_ASN_TEMPLATE. */ +#if defined(WOLFSSL_ASN_TEMPLATE) && defined(WOLFSSL_CERT_GEN) && \ + !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && \ + ((defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY)) || \ + (defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY))) +/* Populate a minimal self-consistent subject/issuer name. */ +static void rfc9802_gen_set_names(Cert* cert) +{ + XSTRNCPY(cert->subject.country, "US", CTC_NAME_SIZE); + XSTRNCPY(cert->subject.state, "OR", CTC_NAME_SIZE); + XSTRNCPY(cert->subject.locality, "Portland", CTC_NAME_SIZE); + XSTRNCPY(cert->subject.org, "wolfSSL", CTC_NAME_SIZE); + XSTRNCPY(cert->subject.unit, "Testing", CTC_NAME_SIZE); + XSTRNCPY(cert->subject.commonName, "RFC9802 Gen Root CA", CTC_NAME_SIZE); +} + +/* Verify a self-signed DER cert by loading it as its own CA. */ +static int rfc9802_gen_verify_selfsigned(const byte* der, int derSz) +{ + EXPECT_DECLS; + WOLFSSL_CERT_MANAGER* cm = NULL; + + ExpectNotNull(cm = wolfSSL_CertManagerNew()); + ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, der, (long)derSz, + WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CertManagerVerifyBuffer(cm, der, (long)derSz, + WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + if (cm != NULL) + wolfSSL_CertManagerFree(cm); + return EXPECT_RESULT(); +} + +#ifdef WOLFSSL_CERT_REQ +/* Parse a generated CSR and confirm its proof-of-possession signature. */ +static int rfc9802_gen_verify_csr(const byte* der, int derSz) +{ + EXPECT_DECLS; + DecodedCert dc; + + wc_InitDecodedCert(&dc, der, (word32)derSz, NULL); + ExpectIntEQ(wc_ParseCert(&dc, CERTREQ_TYPE, VERIFY, NULL), 0); + wc_FreeDecodedCert(&dc); + return EXPECT_RESULT(); +} +#endif /* WOLFSSL_CERT_REQ */ + +/* Generate a self-signed root CA (and, when CSRs are enabled, a PKCS#10 + * request) for an already-made key, then feed each back through the + * verification path. keyType is the wc_MakeCert_ex/wc_SignCert_ex selector + * (LMS_TYPE / XMSS_TYPE / XMSSMT_TYPE) and sigType the matching CTC_ OID. + * key is void* to mirror the public wc_MakeCert_ex API; callers must pass a + * key object whose type matches keyType. */ +static int rfc9802_gen_roundtrip(void* key, int keyType, int sigType, + WC_RNG* rng, word32 derCap) +{ + EXPECT_DECLS; + byte* der = NULL; + int derSz = 0; + + ExpectNotNull(der = (byte*)XMALLOC(derCap, NULL, DYNAMIC_TYPE_TMP_BUFFER)); + + /* Self-signed root CA: generate -> sign -> verify round trip. */ + if (EXPECT_SUCCESS() && der != NULL) { + Cert cert; + ExpectIntEQ(wc_InitCert(&cert), 0); + rfc9802_gen_set_names(&cert); + cert.sigType = sigType; + cert.isCA = 1; + cert.selfSigned = 1; + cert.daysValid = 365; + ExpectIntGT(wc_MakeCert_ex(&cert, der, derCap, keyType, key, rng), 0); + ExpectIntGT(derSz = wc_SignCert_ex(cert.bodySz, cert.sigType, der, + derCap, keyType, key, rng), 0); + ExpectIntEQ(rfc9802_gen_verify_selfsigned(der, derSz), TEST_SUCCESS); + } + +#ifdef WOLFSSL_CERT_REQ + /* PKCS#10 CSR: generate -> self-sign proof-of-possession -> parse. */ + if (EXPECT_SUCCESS() && der != NULL) { + Cert cert; + ExpectIntEQ(wc_InitCert(&cert), 0); + rfc9802_gen_set_names(&cert); + cert.sigType = sigType; + ExpectIntGT(wc_MakeCertReq_ex(&cert, der, derCap, keyType, key), 0); + ExpectIntGT(derSz = wc_SignCert_ex(cert.bodySz, cert.sigType, der, + derCap, keyType, key, rng), 0); + ExpectIntEQ(rfc9802_gen_verify_csr(der, derSz), TEST_SUCCESS); + } +#endif /* WOLFSSL_CERT_REQ */ + + XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return EXPECT_RESULT(); +} + +/* wc_ecc_make_key is available with HAVE_ECC; HAVE_ECC_KEY_EXPORT is needed + * for the leaf SPKI and !WC_NO_RNG for key generation. */ +#if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_EXPORT) && !defined(WC_NO_RNG) +/* Subject name for the generated leaf (distinct from the CA subject). */ +static void rfc9802_gen_set_leaf_names(Cert* cert) +{ + XSTRNCPY(cert->subject.country, "US", CTC_NAME_SIZE); + XSTRNCPY(cert->subject.state, "OR", CTC_NAME_SIZE); + XSTRNCPY(cert->subject.locality, "Portland", CTC_NAME_SIZE); + XSTRNCPY(cert->subject.org, "wolfSSL", CTC_NAME_SIZE); + XSTRNCPY(cert->subject.unit, "Testing", CTC_NAME_SIZE); + XSTRNCPY(cert->subject.commonName, "RFC9802 Gen Leaf", CTC_NAME_SIZE); +} + +/* Generate a self-signed LMS/XMSS CA, then an ECC leaf issued and signed by + * that CA, and confirm the leaf chains to the CA (and fails without it). This + * is the real RFC 9802 use case - a hash-based CA signing another cert - that + * self-signed roots and CSRs don't cover. caKey is the already-made CA key; + * caKeyType/caSigType select its algorithm. */ +static int rfc9802_gen_chain(void* caKey, int caKeyType, int caSigType, + WC_RNG* rng, word32 derCap) +{ + EXPECT_DECLS; + ecc_key leafKey; + int leafKeyInit = 0; + byte* caDer = NULL; + byte* leafDer = NULL; + int caSz = 0; + int leafSz = 0; + WOLFSSL_CERT_MANAGER* cm = NULL; + + ExpectNotNull(caDer = (byte*)XMALLOC(derCap, NULL, DYNAMIC_TYPE_TMP_BUFFER)); + ExpectNotNull(leafDer = (byte*)XMALLOC(derCap, NULL, + DYNAMIC_TYPE_TMP_BUFFER)); + ExpectIntEQ(wc_ecc_init(&leafKey), 0); + leafKeyInit = 1; + ExpectIntEQ(wc_ecc_make_key(rng, 32, &leafKey), 0); + + /* Self-signed CA root. */ + if (EXPECT_SUCCESS() && caDer != NULL) { + Cert ca; + ExpectIntEQ(wc_InitCert(&ca), 0); + rfc9802_gen_set_names(&ca); + ca.sigType = caSigType; + ca.isCA = 1; + ca.selfSigned = 1; + ca.daysValid = 365; + ExpectIntGT(wc_MakeCert_ex(&ca, caDer, derCap, caKeyType, caKey, rng), + 0); + ExpectIntGT(caSz = wc_SignCert_ex(ca.bodySz, caSigType, caDer, derCap, + caKeyType, caKey, rng), 0); + } + + /* ECC leaf, issued by the CA's subject and signed with the CA key. */ + if (EXPECT_SUCCESS() && leafDer != NULL && caSz > 0) { + Cert leaf; + ExpectIntEQ(wc_InitCert(&leaf), 0); + rfc9802_gen_set_leaf_names(&leaf); + leaf.sigType = caSigType; + leaf.daysValid = 365; + ExpectIntEQ(wc_SetIssuerBuffer(&leaf, caDer, caSz), 0); + ExpectIntGT(wc_MakeCert_ex(&leaf, leafDer, derCap, ECC_TYPE, &leafKey, + rng), 0); + ExpectIntGT(leafSz = wc_SignCert_ex(leaf.bodySz, caSigType, leafDer, + derCap, caKeyType, caKey, rng), 0); + } + + /* Leaf verifies only when the CA is the trust anchor. */ + if (EXPECT_SUCCESS() && leafSz > 0) { + ExpectNotNull(cm = wolfSSL_CertManagerNew()); + ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, caDer, (long)caSz, + WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CertManagerVerifyBuffer(cm, leafDer, (long)leafSz, + WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + if (cm != NULL) { + wolfSSL_CertManagerFree(cm); + cm = NULL; + } + ExpectNotNull(cm = wolfSSL_CertManagerNew()); + ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, leafDer, (long)leafSz, + WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + if (cm != NULL) { + wolfSSL_CertManagerFree(cm); + cm = NULL; + } + } + + /* Negative: corrupt the leaf's signature (last byte of the DER, in the + * signatureValue) and confirm verification fails even with the CA loaded. + * This proves the CA's hash-based signature is cryptographically checked, + * not accepted on issuer-name chaining alone. */ + if (EXPECT_SUCCESS() && leafSz > 0) { + byte saved = leafDer[leafSz - 1]; + leafDer[leafSz - 1] ^= 0xFF; + ExpectNotNull(cm = wolfSSL_CertManagerNew()); + ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, caDer, (long)caSz, + WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, leafDer, (long)leafSz, + WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + if (cm != NULL) { + wolfSSL_CertManagerFree(cm); + cm = NULL; + } + leafDer[leafSz - 1] = saved; + } + + if (leafKeyInit) + wc_ecc_free(&leafKey); + XFREE(leafDer, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(caDer, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return EXPECT_RESULT(); +} +#endif /* HAVE_ECC && HAVE_ECC_KEY_EXPORT */ +#endif /* gen test support */ + +#if defined(WOLFSSL_ASN_TEMPLATE) && defined(WOLFSSL_HAVE_LMS) && \ + !defined(WOLFSSL_LMS_VERIFY_ONLY) && \ + defined(WOLFSSL_CERT_GEN) && !defined(NO_FILESYSTEM) && \ + !defined(NO_CERTS) && !defined(WOLFSSL_NO_LMS_SHA256_256) +/* Init an LMS key with the shared persistence callbacks and given params. */ +static int rfc9802_gen_lms_init(LmsKey* key, int levels, int height, int win) +{ + int ret = wc_LmsKey_Init(key, NULL, INVALID_DEVID); + if (ret == 0) + ret = wc_LmsKey_SetParameters(key, levels, height, win); + if (ret == 0) + ret = wc_LmsKey_SetWriteCb(key, test_lms_write_key); + if (ret == 0) + ret = wc_LmsKey_SetReadCb(key, test_lms_read_key); + if (ret == 0) + ret = wc_LmsKey_SetContext(key, (void*)LMS_TEST_PRIV_KEY_FILE); + return ret; +} +#endif + +int test_rfc9802_lms_x509_gen(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_ASN_TEMPLATE) && defined(WOLFSSL_HAVE_LMS) && \ + !defined(WOLFSSL_LMS_VERIFY_ONLY) && \ + defined(WOLFSSL_CERT_GEN) && !defined(NO_FILESYSTEM) && \ + !defined(NO_CERTS) && !defined(WOLFSSL_NO_LMS_SHA256_256) + LmsKey key; + WC_RNG rng; + + ExpectIntEQ(wc_InitRng(&rng), 0); + + /* Single-level LMS (L1-H5-W8). */ + remove(LMS_TEST_PRIV_KEY_FILE); + ExpectIntEQ(rfc9802_gen_lms_init(&key, 1, 5, 8), 0); + ExpectIntEQ(wc_LmsKey_MakeKey(&key, &rng), 0); + ExpectIntEQ(rfc9802_gen_roundtrip(&key, LMS_TYPE, CTC_HSS_LMS, &rng, 8192), + TEST_SUCCESS); + + /* Negative: signing an LMS key with a non-LMS signature OID must be + * rejected rather than emit a cert whose signatureAlgorithm contradicts + * its public key. The check fires before any signature is produced, so + * the key's one-time signatures are not consumed. */ + if (EXPECT_SUCCESS()) { + Cert cert; + byte* tmp = NULL; + ExpectNotNull(tmp = (byte*)XMALLOC(8192, NULL, DYNAMIC_TYPE_TMP_BUFFER)); + ExpectIntEQ(wc_InitCert(&cert), 0); + rfc9802_gen_set_names(&cert); + cert.sigType = CTC_HSS_LMS; + cert.isCA = 1; + cert.selfSigned = 1; + cert.daysValid = 365; + if (tmp != NULL) { + ExpectIntGT(wc_MakeCert_ex(&cert, tmp, 8192, LMS_TYPE, &key, + &rng), 0); + ExpectIntEQ(wc_SignCert_ex(cert.bodySz, CTC_XMSS, tmp, 8192, + LMS_TYPE, &key, &rng), WC_NO_ERR_TRACE(ALGO_ID_E)); + } + XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER); + } + +#if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_EXPORT) && !defined(WC_NO_RNG) + /* Real CA use case: the LMS CA signs an ECC leaf; the leaf must chain to + * the CA. Reuses the L1 key (plenty of one-time signatures remain). */ + ExpectIntEQ(rfc9802_gen_chain(&key, LMS_TYPE, CTC_HSS_LMS, &rng, 8192), + TEST_SUCCESS); +#endif + + wc_LmsKey_Free(&key); + remove(LMS_TEST_PRIV_KEY_FILE); + +#if !defined(WOLFSSL_LMS_MAX_LEVELS) || (WOLFSSL_LMS_MAX_LEVELS >= 2) + /* Multi-level HSS (L2-H5-W8): the signature embeds a lower-level LMS + * public key + signature, exercising the larger, multi-level encoding. */ + remove(LMS_TEST_PRIV_KEY_FILE); + ExpectIntEQ(rfc9802_gen_lms_init(&key, 2, 5, 8), 0); + ExpectIntEQ(wc_LmsKey_MakeKey(&key, &rng), 0); + ExpectIntEQ(rfc9802_gen_roundtrip(&key, LMS_TYPE, CTC_HSS_LMS, &rng, 8192), + TEST_SUCCESS); + wc_LmsKey_Free(&key); + remove(LMS_TEST_PRIV_KEY_FILE); +#endif + +#if !defined(WOLFSSL_LMS_MAX_LEVELS) || (WOLFSSL_LMS_MAX_LEVELS >= 3) + /* Three-level HSS with Winternitz 4 (L3-H5-W4): exercises the deepest + * multi-level encoding and a different Winternitz parameter than the + * W8 cases above. */ + remove(LMS_TEST_PRIV_KEY_FILE); + ExpectIntEQ(rfc9802_gen_lms_init(&key, 3, 5, 4), 0); + ExpectIntEQ(wc_LmsKey_MakeKey(&key, &rng), 0); + ExpectIntEQ(rfc9802_gen_roundtrip(&key, LMS_TYPE, CTC_HSS_LMS, &rng, 8192), + TEST_SUCCESS); + wc_LmsKey_Free(&key); + remove(LMS_TEST_PRIV_KEY_FILE); +#endif + + wc_FreeRng(&rng); +#endif + return EXPECT_RESULT(); +} + +#if defined(WOLFSSL_ASN_TEMPLATE) && defined(WOLFSSL_HAVE_XMSS) && \ + !defined(WOLFSSL_XMSS_VERIFY_ONLY) && \ + defined(WOLFSSL_CERT_GEN) && !defined(NO_FILESYSTEM) && !defined(NO_CERTS) +#define XMSS_GEN_TEST_PRIV_KEY_FILE "/tmp/wolfssl_test_xmss_gen.key" +static enum wc_XmssRc xmss_gen_write_key(const byte* priv, word32 privSz, + void* context) +{ + XFILE f = XFOPEN((const char*)context, "wb"); + enum wc_XmssRc ret = WC_XMSS_RC_SAVED_TO_NV_MEMORY; + if (f == XBADFILE) + return WC_XMSS_RC_WRITE_FAIL; + if (XFWRITE(priv, 1, privSz, f) != privSz) + ret = WC_XMSS_RC_WRITE_FAIL; + XFCLOSE(f); + return ret; +} +static enum wc_XmssRc xmss_gen_read_key(byte* priv, word32 privSz, + void* context) +{ + XFILE f = XFOPEN((const char*)context, "rb"); + enum wc_XmssRc ret = WC_XMSS_RC_READ_TO_MEMORY; + if (f == XBADFILE) + return WC_XMSS_RC_READ_FAIL; + if (XFREAD(priv, 1, privSz, f) != privSz) + ret = WC_XMSS_RC_READ_FAIL; + XFCLOSE(f); + return ret; +} + +/* Init an XMSS/XMSS^MT key with the shared persistence callbacks. */ +static int rfc9802_gen_xmss_init(XmssKey* key, const char* paramStr) +{ + int ret = wc_XmssKey_Init(key, NULL, INVALID_DEVID); + if (ret == 0) + ret = wc_XmssKey_SetParamStr(key, paramStr); + if (ret == 0) + ret = wc_XmssKey_SetWriteCb(key, xmss_gen_write_key); + if (ret == 0) + ret = wc_XmssKey_SetReadCb(key, xmss_gen_read_key); + if (ret == 0) + ret = wc_XmssKey_SetContext(key, (void*)XMSS_GEN_TEST_PRIV_KEY_FILE); + return ret; +} + +/* X.509-level negative tests on a wolfSSL-generated XMSS/XMSS^MT cert, run + * against the already-made key (no extra keygen). oidLast is the cert's true + * final OID byte (XMSS 0x22, XMSS^MT 0x23) and oidSwap the other family's: + * + * (a) flip only the outer signatureAlgorithm OID -> it no longer equals the + * TBS signatureAlgorithm, which the generic X.509 algId-consistency check + * rejects (ASN_SIG_OID_E at parse); + * (b) flip both signatureAlgorithm copies (TBS + outer) but leave the SPKI + * key OID -> outer == TBS (that check passes), yet the signature + * algorithm now disagrees with the public-key algorithm, which RFC 9802 + * requires verification to reject (SigOidMatchesKeyOid, before the - now + * also invalid - signature is even checked). + * + * Either way verification must fail. */ +static int rfc9802_gen_xmss_oid_tamper(void* key, int keyType, int sigType, + WC_RNG* rng, byte oidLast, byte oidSwap) +{ + EXPECT_DECLS; + byte* der = NULL; + int derSz = 0; + word32 off[8]; + int n = 0; + WOLFSSL_CERT_MANAGER* cm = NULL; + + ExpectNotNull(der = (byte*)XMALLOC(16384, NULL, DYNAMIC_TYPE_TMP_BUFFER)); + + if (EXPECT_SUCCESS() && der != NULL) { + Cert cert; + ExpectIntEQ(wc_InitCert(&cert), 0); + rfc9802_gen_set_names(&cert); + cert.sigType = sigType; + cert.isCA = 1; + cert.selfSigned = 1; + cert.daysValid = 365; + ExpectIntGT(wc_MakeCert_ex(&cert, der, 16384, keyType, key, rng), 0); + ExpectIntGT(derSz = wc_SignCert_ex(cert.bodySz, sigType, der, 16384, + keyType, key, rng), 0); + } + + if (EXPECT_SUCCESS() && derSz > 0) { + n = rfc9802_collect_hbs_oid_offsets(der, (word32)derSz, oidLast, off, 8); + /* TBS-signature, SPKI-key, outer-signature - in that order. */ + ExpectIntEQ(n, 3); + } + + /* (a) Outer signatureAlgorithm != TBS signatureAlgorithm. */ + if (EXPECT_SUCCESS() && n == 3) { + der[off[2]] = oidSwap; + ExpectNotNull(cm = wolfSSL_CertManagerNew()); + (void)wolfSSL_CertManagerLoadCABuffer(cm, der, (long)derSz, + WOLFSSL_FILETYPE_ASN1); + ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, der, (long)derSz, + WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + if (cm != NULL) { + wolfSSL_CertManagerFree(cm); + cm = NULL; + } + der[off[2]] = oidLast; /* restore */ + } + + /* (b) signatureAlgorithm (both copies) disagrees with the SPKI key OID. */ + if (EXPECT_SUCCESS() && n == 3) { + der[off[0]] = oidSwap; + der[off[2]] = oidSwap; + ExpectNotNull(cm = wolfSSL_CertManagerNew()); + (void)wolfSSL_CertManagerLoadCABuffer(cm, der, (long)derSz, + WOLFSSL_FILETYPE_ASN1); + ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, der, (long)derSz, + WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); + if (cm != NULL) { + wolfSSL_CertManagerFree(cm); + cm = NULL; + } + } + + XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return EXPECT_RESULT(); +} +#endif /* XMSS gen support */ + +int test_rfc9802_xmss_x509_gen(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_ASN_TEMPLATE) && defined(WOLFSSL_HAVE_XMSS) && \ + !defined(WOLFSSL_XMSS_VERIFY_ONLY) && \ + defined(WOLFSSL_CERT_GEN) && !defined(NO_FILESYSTEM) && !defined(NO_CERTS) + XmssKey key; + WC_RNG rng; + + ExpectIntEQ(wc_InitRng(&rng), 0); + + /* Single-tree XMSS. */ + remove(XMSS_GEN_TEST_PRIV_KEY_FILE); + ExpectIntEQ(rfc9802_gen_xmss_init(&key, "XMSS-SHA2_10_256"), 0); + ExpectIntEQ(wc_XmssKey_MakeKey(&key, &rng), 0); + ExpectIntEQ((int)key.is_xmssmt, 0); + ExpectIntEQ(rfc9802_gen_roundtrip(&key, XMSS_TYPE, CTC_XMSS, &rng, 16384), + TEST_SUCCESS); + + /* Negative: the XMSSMT_TYPE selector must not be accepted for a + * single-tree XMSS key, and signing a single-tree key as XMSS^MT must be + * rejected. Both checks fire before signing, so no signature is used. */ + if (EXPECT_SUCCESS()) { + Cert cert; + byte* tmp = NULL; + ExpectNotNull(tmp = (byte*)XMALLOC(16384, NULL, + DYNAMIC_TYPE_TMP_BUFFER)); + ExpectIntEQ(wc_InitCert(&cert), 0); + rfc9802_gen_set_names(&cert); + cert.sigType = CTC_XMSS; + cert.isCA = 1; + cert.selfSigned = 1; + cert.daysValid = 365; + /* Wrong selector for the key's tree variant. */ + if (tmp != NULL) { + ExpectIntEQ(wc_MakeCert_ex(&cert, tmp, 16384, XMSSMT_TYPE, &key, + &rng), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + /* Correct selector, but signed with the XMSS^MT OID. */ + ExpectIntGT(wc_MakeCert_ex(&cert, tmp, 16384, XMSS_TYPE, &key, + &rng), 0); + ExpectIntEQ(wc_SignCert_ex(cert.bodySz, CTC_XMSSMT, tmp, 16384, + XMSS_TYPE, &key, &rng), WC_NO_ERR_TRACE(ALGO_ID_E)); + } + XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER); + } + +#if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_EXPORT) && !defined(WC_NO_RNG) + /* Real CA use case: the XMSS CA signs an ECC leaf; the leaf must chain. */ + ExpectIntEQ(rfc9802_gen_chain(&key, XMSS_TYPE, CTC_XMSS, &rng, 16384), + TEST_SUCCESS); +#endif + /* X.509-level signatureAlgorithm/SPKI OID consistency, reusing this key. */ + ExpectIntEQ(rfc9802_gen_xmss_oid_tamper(&key, XMSS_TYPE, CTC_XMSS, &rng, + /* XMSS */ 0x22, /* swap */ 0x23), TEST_SUCCESS); + + wc_XmssKey_Free(&key); + remove(XMSS_GEN_TEST_PRIV_KEY_FILE); + + /* Multi-tree XMSS^MT: exercises the XMSSMT_TYPE selector, the + * XMSSMTk public-key OID branch and the CTC_XMSSMT signature OID. */ + remove(XMSS_GEN_TEST_PRIV_KEY_FILE); + ExpectIntEQ(rfc9802_gen_xmss_init(&key, "XMSSMT-SHA2_20/2_256"), 0); + ExpectIntEQ(wc_XmssKey_MakeKey(&key, &rng), 0); + ExpectIntEQ((int)key.is_xmssmt, 1); + ExpectIntEQ(rfc9802_gen_roundtrip(&key, XMSSMT_TYPE, CTC_XMSSMT, &rng, + 16384), TEST_SUCCESS); +#if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_EXPORT) && !defined(WC_NO_RNG) + ExpectIntEQ(rfc9802_gen_chain(&key, XMSSMT_TYPE, CTC_XMSSMT, &rng, 16384), + TEST_SUCCESS); +#endif + ExpectIntEQ(rfc9802_gen_xmss_oid_tamper(&key, XMSSMT_TYPE, CTC_XMSSMT, &rng, + /* XMSS^MT */ 0x23, /* swap */ 0x22), TEST_SUCCESS); + wc_XmssKey_Free(&key); + remove(XMSS_GEN_TEST_PRIV_KEY_FILE); + + /* A second XMSS^MT parameter set (different embedded param-set OID and a + * larger signature) to keep the encoder/auto-derive decoder exercised + * across sizes now that the committed multi-size fixtures are gone. */ + remove(XMSS_GEN_TEST_PRIV_KEY_FILE); + ExpectIntEQ(rfc9802_gen_xmss_init(&key, "XMSSMT-SHA2_20/4_256"), 0); + ExpectIntEQ(wc_XmssKey_MakeKey(&key, &rng), 0); + ExpectIntEQ((int)key.is_xmssmt, 1); + ExpectIntEQ(rfc9802_gen_roundtrip(&key, XMSSMT_TYPE, CTC_XMSSMT, &rng, + 16384), TEST_SUCCESS); + wc_XmssKey_Free(&key); + remove(XMSS_GEN_TEST_PRIV_KEY_FILE); + + wc_FreeRng(&rng); +#endif + return EXPECT_RESULT(); +} diff --git a/tests/api/test_lms_xmss.h b/tests/api/test_lms_xmss.h index b2ff579987..78c66e53e9 100644 --- a/tests/api/test_lms_xmss.h +++ b/tests/api/test_lms_xmss.h @@ -28,12 +28,16 @@ int test_wc_LmsKey_sign_verify(void); int test_wc_LmsKey_reload_cache(void); int test_rfc9802_lms_x509_verify(void); int test_rfc9802_xmss_x509_verify(void); +int test_rfc9802_lms_x509_gen(void); +int test_rfc9802_xmss_x509_gen(void); /* LMS, and RFC 9802 (HSS/LMS and XMSS/XMSS^MT in X.509). */ #define TEST_LMS_XMSS_DECLS \ TEST_DECL_GROUP("lms", test_wc_LmsKey_sign_verify), \ TEST_DECL_GROUP("lms", test_wc_LmsKey_reload_cache), \ TEST_DECL_GROUP("lms", test_rfc9802_lms_x509_verify), \ - TEST_DECL_GROUP("xmss", test_rfc9802_xmss_x509_verify) + TEST_DECL_GROUP("xmss", test_rfc9802_xmss_x509_verify), \ + TEST_DECL_GROUP("lms", test_rfc9802_lms_x509_gen), \ + TEST_DECL_GROUP("xmss", test_rfc9802_xmss_x509_gen) #endif /* WOLFCRYPT_TEST_LMS_XMSS_H */ diff --git a/tests/api/test_mldsa_legacy.c b/tests/api/test_mldsa_legacy.c index 03d3ce0728..a8f1c131f4 100644 --- a/tests/api/test_mldsa_legacy.c +++ b/tests/api/test_mldsa_legacy.c @@ -207,23 +207,10 @@ wc_static_assert(WC_NO_ERR_TRACE(DILITHIUM_KEY_SIZE_E) == * signature mismatches and defeat the purpose. */ static void mldsa_legacy_shim_symbol_aliases_compile_check(void) { - typedef int (*init_fn)(wc_MlDsaKey*, void*, int); - typedef void (*free_fn)(wc_MlDsaKey*); - typedef int (*set_level_fn)(wc_MlDsaKey*, byte); - typedef int (*get_level_fn)(wc_MlDsaKey*, byte*); typedef int (*size_fn)(wc_MlDsaKey*); typedef int (*check_fn)(wc_MlDsaKey*); typedef int (*export_fn)(wc_MlDsaKey*, byte*, word32*); - init_fn f_init_ex = &wc_dilithium_init_ex; - free_fn f_free = &wc_dilithium_free; - set_level_fn f_set_level = &wc_dilithium_set_level; - get_level_fn f_get_level = &wc_dilithium_get_level; - size_fn f_sig_size = &wc_dilithium_sig_size; - - (void)f_init_ex; (void)f_free; (void)f_set_level; (void)f_get_level; - (void)f_sig_size; - #ifdef WOLFSSL_MLDSA_PRIVATE_KEY { size_fn f_size = &wc_dilithium_size; diff --git a/tests/api/test_ocsp.c b/tests/api/test_ocsp.c index e9df5a6068..9bc74de223 100644 --- a/tests/api/test_ocsp.c +++ b/tests/api/test_ocsp.c @@ -170,6 +170,33 @@ int test_ocsp_response_parsing(void) } #endif /* HAVE_OCSP && !NO_SHA */ +#if defined(HAVE_OCSP) && !defined(NO_SHA) && !defined(NO_RSA) && \ + !defined(WOLFSSL_NO_OCSP_ISSUER_CHECK) +int test_ocsp_ancestor_responder_rejected(void) +{ + EXPECT_DECLS; + struct test_conf conf; + + conf.resp = (unsigned char*)resp_server1_cert_ancestor_responder; + conf.respSz = sizeof(resp_server1_cert_ancestor_responder); + conf.ca0 = root_ca_cert_pem; + conf.ca0Sz = sizeof(root_ca_cert_pem); + conf.ca1 = intermediate1_ca_cert_pem; + conf.ca1Sz = sizeof(intermediate1_ca_cert_pem); + conf.targetCert = server1_cert_pem; + conf.targetCertSz = sizeof(server1_cert_pem); + ExpectIntEQ(test_ocsp_response_with_cm(&conf, OCSP_LOOKUP_FAIL), + TEST_SUCCESS); + + return EXPECT_RESULT(); +} +#else +int test_ocsp_ancestor_responder_rejected(void) +{ + return TEST_SKIPPED; +} +#endif + #if defined(HAVE_OCSP) && (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) && \ !defined(NO_RSA) static int test_ocsp_create_x509store(WOLFSSL_X509_STORE** store, diff --git a/tests/api/test_ocsp.h b/tests/api/test_ocsp.h index 41dd21329d..e8e2aa3cf2 100644 --- a/tests/api/test_ocsp.h +++ b/tests/api/test_ocsp.h @@ -34,5 +34,6 @@ int test_ocsp_cert_unknown_crl_fallback(void); int test_ocsp_cert_unknown_crl_fallback_nonleaf(void); int test_tls13_nonblock_ocsp_low_mfl(void); int test_ocsp_responder(void); +int test_ocsp_ancestor_responder_rejected(void); #endif /* WOLFSSL_TEST_OCSP_H */ diff --git a/tests/api/test_ocsp_test_blobs.h b/tests/api/test_ocsp_test_blobs.h index 78d8b956e5..0444f43483 100644 --- a/tests/api/test_ocsp_test_blobs.h +++ b/tests/api/test_ocsp_test_blobs.h @@ -42,37 +42,37 @@ unsigned char resp[] = { 0x72, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6e, 0x66, 0x6f, 0x40, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x18, 0x0f, - 0x32, 0x30, 0x32, 0x36, 0x30, 0x32, 0x32, 0x34, 0x32, 0x31, 0x34, 0x32, - 0x30, 0x31, 0x5a, 0x30, 0x4f, 0x30, 0x4d, 0x30, 0x38, 0x30, 0x07, 0x06, + 0x32, 0x30, 0x32, 0x36, 0x30, 0x35, 0x32, 0x31, 0x31, 0x37, 0x32, 0x34, + 0x33, 0x30, 0x5a, 0x30, 0x4f, 0x30, 0x4d, 0x30, 0x38, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x04, 0x14, 0x44, 0xa8, 0xdb, 0xd1, 0xbc, 0x97, 0x0a, 0x83, 0x3b, 0x5b, 0x31, 0x9a, 0x4c, 0xb8, 0xd2, 0x52, 0x37, 0x15, 0x8a, 0x88, 0x04, 0x14, 0x73, 0xb0, 0x1c, 0xa4, 0x2f, 0x82, 0xcb, 0xcf, 0x47, 0xa5, 0x38, 0xd7, 0xb0, 0x04, 0x82, 0x3a, 0x7e, 0x72, 0x15, 0x21, 0x02, 0x01, 0x01, 0x80, 0x00, 0x18, 0x0f, 0x32, 0x30, 0x32, - 0x36, 0x30, 0x32, 0x32, 0x34, 0x32, 0x31, 0x34, 0x32, 0x30, 0x31, 0x5a, + 0x36, 0x30, 0x35, 0x32, 0x31, 0x31, 0x37, 0x32, 0x34, 0x33, 0x30, 0x5a, 0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, - 0x0b, 0x03, 0x82, 0x01, 0x01, 0x00, 0x7a, 0xc5, 0x6d, 0xfa, 0x8b, 0x75, - 0x9a, 0x46, 0x91, 0x3b, 0x23, 0xc2, 0xa0, 0x0d, 0x60, 0x0e, 0x61, 0x54, - 0x7c, 0xd7, 0xcb, 0x6c, 0x14, 0x9b, 0x11, 0x96, 0xe2, 0x83, 0xfa, 0x0f, - 0x70, 0xc9, 0xc9, 0x07, 0xa8, 0x53, 0x69, 0x90, 0xbb, 0xd5, 0x31, 0xb4, - 0x6f, 0xfc, 0x6b, 0x6b, 0xd9, 0x1a, 0xe5, 0xbc, 0xc8, 0x25, 0x93, 0x0b, - 0x9e, 0x9d, 0xb3, 0x9b, 0x07, 0x38, 0x79, 0x4c, 0xd0, 0xa1, 0xd1, 0x3f, - 0xf6, 0x8a, 0xf0, 0x77, 0xa4, 0xea, 0x8d, 0x23, 0xf4, 0xb0, 0xdf, 0x59, - 0x41, 0x5c, 0x77, 0x0e, 0xc2, 0x1c, 0xab, 0xbb, 0xb6, 0x12, 0x2e, 0x37, - 0x1f, 0xf7, 0x57, 0xa0, 0x02, 0x02, 0xed, 0x8c, 0xb7, 0x4d, 0xdd, 0xd0, - 0x02, 0xb6, 0x5f, 0xff, 0xa3, 0x0a, 0x28, 0x4b, 0x8f, 0x4e, 0x6d, 0x57, - 0x55, 0xd0, 0x4f, 0x3f, 0x4c, 0x45, 0x5b, 0x6f, 0x8c, 0x8e, 0xe4, 0xd9, - 0x62, 0xe8, 0x4c, 0x72, 0xd8, 0x0b, 0x5c, 0xce, 0xc9, 0x53, 0x76, 0x0e, - 0xb1, 0xaf, 0xf8, 0x15, 0xb2, 0x50, 0xd5, 0x69, 0x6f, 0xbe, 0xee, 0x17, - 0x06, 0x43, 0xc6, 0x6d, 0x9a, 0x12, 0x3d, 0x57, 0x14, 0xb3, 0x39, 0xc8, - 0x58, 0x76, 0x46, 0x57, 0xe3, 0xb4, 0x4a, 0x82, 0x8e, 0xf3, 0xdc, 0x99, - 0x0a, 0x34, 0x6e, 0x65, 0x3c, 0xef, 0xe4, 0x42, 0x85, 0x6c, 0xc5, 0xaf, - 0x76, 0xdb, 0x75, 0x2d, 0xd5, 0xb2, 0x69, 0x08, 0xec, 0xa3, 0x1d, 0x8e, - 0xdc, 0x7c, 0xbf, 0xb7, 0xa9, 0x6c, 0x9f, 0x7f, 0x9e, 0xb8, 0x9e, 0x1d, - 0x20, 0x64, 0xcf, 0x30, 0xf2, 0x2d, 0xa7, 0x80, 0x77, 0x53, 0xf9, 0x15, - 0xf1, 0xef, 0xb2, 0xa4, 0x30, 0x02, 0x94, 0xfe, 0x43, 0xad, 0xa0, 0x7c, - 0x67, 0x47, 0xe2, 0x42, 0x4a, 0x2d, 0x02, 0x9e, 0x6a, 0xb6, 0xa1, 0x57, - 0x3e, 0x9a, 0x47, 0xe2, 0xb1, 0xb7, 0xd2, 0x0f, 0x32, 0x8f, 0xa0, 0x82, + 0x0b, 0x03, 0x82, 0x01, 0x01, 0x00, 0x85, 0x29, 0xfc, 0x9a, 0x83, 0x8a, + 0xae, 0x8d, 0xcd, 0xb3, 0x3c, 0x6d, 0xa5, 0xd5, 0x6b, 0x62, 0x51, 0x58, + 0xdd, 0x16, 0xb4, 0x80, 0xe0, 0xf8, 0x78, 0xf6, 0xca, 0xa4, 0xfa, 0x7d, + 0x4a, 0xe6, 0x8a, 0xf7, 0xa8, 0x5f, 0x01, 0xe1, 0x9a, 0xfd, 0xc0, 0x3a, + 0xc5, 0x21, 0x68, 0x82, 0x3f, 0x82, 0xf1, 0x41, 0xab, 0xd6, 0xb1, 0x78, + 0x72, 0x70, 0xdf, 0xa7, 0xb4, 0xc7, 0xc6, 0xab, 0x0d, 0xc8, 0xd5, 0x54, + 0xae, 0xb9, 0x96, 0xad, 0xa1, 0xc7, 0x55, 0x65, 0xd9, 0x86, 0x8b, 0xe1, + 0x01, 0x4a, 0xb3, 0xbd, 0x4c, 0xc8, 0xd2, 0xc7, 0x15, 0xbd, 0xd3, 0x3f, + 0x5c, 0xe2, 0xf1, 0x59, 0xfc, 0x51, 0x04, 0x6f, 0xb1, 0x94, 0x66, 0xb9, + 0xc9, 0xa2, 0xbc, 0x5d, 0x25, 0x9a, 0x4c, 0x48, 0xe0, 0x1b, 0xb6, 0xd2, + 0x80, 0xb5, 0x05, 0x93, 0x3d, 0x6d, 0x28, 0x3f, 0xc5, 0x4e, 0x59, 0x1d, + 0x85, 0x1e, 0x37, 0xd3, 0x3d, 0x9c, 0xd6, 0x1c, 0xcb, 0xf9, 0x0f, 0x40, + 0x3b, 0x4d, 0xb3, 0xc1, 0xb6, 0x9d, 0x66, 0xbb, 0xe9, 0x15, 0x4c, 0xf7, + 0xac, 0x96, 0xfd, 0x32, 0xa6, 0xa7, 0xee, 0x06, 0xb5, 0x08, 0x1c, 0x0c, + 0x71, 0xdc, 0x48, 0x58, 0x41, 0x69, 0xb1, 0xd2, 0xad, 0xd5, 0x9a, 0x0d, + 0x66, 0xba, 0x82, 0x2a, 0x41, 0xcd, 0x86, 0xda, 0x72, 0x09, 0x4d, 0xa2, + 0xc5, 0xb2, 0x43, 0x0f, 0x4c, 0x08, 0x6e, 0x87, 0x00, 0x6f, 0x9d, 0xb7, + 0x10, 0x0a, 0x1f, 0x53, 0x14, 0x64, 0xaf, 0x97, 0xf2, 0x60, 0x12, 0xe5, + 0xe0, 0xd6, 0x11, 0x83, 0x44, 0x97, 0xa7, 0x3f, 0x63, 0xde, 0xc0, 0x27, + 0xd1, 0x48, 0xbe, 0x9f, 0xc3, 0x13, 0xf6, 0x18, 0xd4, 0x22, 0x34, 0x4b, + 0x02, 0x3f, 0x1b, 0xae, 0x33, 0xab, 0xc2, 0x26, 0xef, 0xfe, 0xdb, 0x27, + 0xf5, 0xc5, 0x11, 0xac, 0x25, 0x66, 0xe1, 0x62, 0x8c, 0x41, 0xa0, 0x82, 0x04, 0xc6, 0x30, 0x82, 0x04, 0xc2, 0x30, 0x82, 0x04, 0xbe, 0x30, 0x82, 0x03, 0xa6, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x04, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, @@ -183,37 +183,37 @@ unsigned char resp_rid_bykey[] = { 0x01, 0x01, 0x04, 0x82, 0x06, 0x5c, 0x30, 0x82, 0x06, 0x58, 0x30, 0x7a, 0xa2, 0x16, 0x04, 0x14, 0x32, 0x67, 0xe1, 0xb1, 0x79, 0xd2, 0x81, 0xfc, 0x9f, 0x23, 0x0c, 0x70, 0x40, 0x50, 0xb5, 0x46, 0x56, 0xb8, 0x30, 0x36, - 0x18, 0x0f, 0x32, 0x30, 0x32, 0x36, 0x30, 0x32, 0x32, 0x34, 0x32, 0x31, - 0x34, 0x32, 0x30, 0x31, 0x5a, 0x30, 0x4f, 0x30, 0x4d, 0x30, 0x38, 0x30, + 0x18, 0x0f, 0x32, 0x30, 0x32, 0x36, 0x30, 0x35, 0x32, 0x31, 0x31, 0x37, + 0x32, 0x34, 0x33, 0x30, 0x5a, 0x30, 0x4f, 0x30, 0x4d, 0x30, 0x38, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x04, 0x14, 0x44, 0xa8, 0xdb, 0xd1, 0xbc, 0x97, 0x0a, 0x83, 0x3b, 0x5b, 0x31, 0x9a, 0x4c, 0xb8, 0xd2, 0x52, 0x37, 0x15, 0x8a, 0x88, 0x04, 0x14, 0x73, 0xb0, 0x1c, 0xa4, 0x2f, 0x82, 0xcb, 0xcf, 0x47, 0xa5, 0x38, 0xd7, 0xb0, 0x04, 0x82, 0x3a, 0x7e, 0x72, 0x15, 0x21, 0x02, 0x01, 0x01, 0x80, 0x00, 0x18, 0x0f, 0x32, - 0x30, 0x32, 0x36, 0x30, 0x32, 0x32, 0x34, 0x32, 0x31, 0x34, 0x32, 0x30, - 0x31, 0x5a, 0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, - 0x01, 0x01, 0x0b, 0x03, 0x82, 0x01, 0x01, 0x00, 0x01, 0x8b, 0x06, 0xc9, - 0x4f, 0x6c, 0x1d, 0xc4, 0x4e, 0x1a, 0xc6, 0xd2, 0xbc, 0x6b, 0xbe, 0x3f, - 0x9d, 0x73, 0x0c, 0xbd, 0x3a, 0x82, 0xc0, 0xed, 0xdf, 0x70, 0xaf, 0x00, - 0x7d, 0xdd, 0x53, 0xdd, 0x48, 0xd0, 0x6d, 0xcb, 0xec, 0xd6, 0x31, 0x08, - 0x03, 0x3b, 0xcf, 0x82, 0xce, 0x28, 0x9c, 0x2f, 0xc6, 0x19, 0x48, 0x75, - 0xe4, 0xa7, 0xce, 0x7d, 0x6f, 0xb0, 0x10, 0xb4, 0xc0, 0xbd, 0x1d, 0xe1, - 0x9c, 0x57, 0xbc, 0xff, 0xbf, 0x33, 0x42, 0x0b, 0xea, 0xb4, 0x17, 0x9a, - 0x47, 0x5b, 0x3b, 0xf5, 0xbf, 0xdc, 0x2d, 0xb5, 0xc6, 0xb1, 0xa5, 0xfd, - 0x31, 0xaf, 0xe4, 0x6d, 0xdd, 0xe0, 0x8c, 0x7b, 0x70, 0xe3, 0xcc, 0x59, - 0x77, 0xb3, 0x38, 0x7e, 0x0a, 0xf0, 0xbc, 0x08, 0x86, 0x37, 0xcf, 0x28, - 0xa8, 0x07, 0xe8, 0xae, 0x5c, 0x0d, 0xa5, 0x21, 0x0c, 0xdb, 0xa8, 0x8b, - 0x9e, 0x73, 0x77, 0xf8, 0x0d, 0x05, 0x21, 0xec, 0x4a, 0xf9, 0xb3, 0x71, - 0xcd, 0x4b, 0xc9, 0x5a, 0x22, 0xd4, 0x53, 0x0b, 0xac, 0x28, 0x8e, 0x12, - 0x6c, 0x73, 0xe9, 0x65, 0x53, 0xc8, 0x0e, 0xac, 0x39, 0x7e, 0xd0, 0x77, - 0xaf, 0x82, 0xfe, 0xa4, 0xf2, 0x85, 0xb3, 0x10, 0x73, 0xde, 0x5d, 0xe6, - 0xf0, 0xb6, 0xb9, 0x8c, 0x23, 0x35, 0xcc, 0x5f, 0x29, 0x42, 0x13, 0xd8, - 0x72, 0x6f, 0xc2, 0xf6, 0x10, 0x56, 0xb5, 0x27, 0xe8, 0xd2, 0x2b, 0x15, - 0x5f, 0x4e, 0x8e, 0xa2, 0x19, 0xba, 0x78, 0x0a, 0xa4, 0x24, 0xad, 0xe5, - 0x79, 0x72, 0x18, 0xac, 0xa5, 0xa4, 0x63, 0x0d, 0x33, 0xa3, 0x0c, 0xc0, - 0xbb, 0xcd, 0x15, 0x92, 0x7d, 0xa7, 0x4e, 0xd1, 0x89, 0xb7, 0x00, 0xde, - 0x49, 0x48, 0x0d, 0x28, 0xf1, 0xf1, 0xd8, 0x9c, 0xc3, 0xfa, 0xe8, 0x22, - 0xd9, 0x75, 0x9c, 0x0f, 0xfe, 0x80, 0x7e, 0xbb, 0x68, 0x70, 0x7f, 0x6c, + 0x30, 0x32, 0x36, 0x30, 0x35, 0x32, 0x31, 0x31, 0x37, 0x32, 0x34, 0x33, + 0x30, 0x5a, 0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x0b, 0x03, 0x82, 0x01, 0x01, 0x00, 0x6e, 0xc1, 0x15, 0x9d, + 0xe2, 0xfc, 0x04, 0x22, 0x05, 0x9f, 0x4c, 0xb2, 0x9d, 0xed, 0x7b, 0x15, + 0x05, 0x72, 0x07, 0xad, 0x08, 0xd6, 0xc2, 0xf7, 0x24, 0x37, 0x6b, 0x38, + 0xbb, 0x96, 0x6b, 0x3e, 0x91, 0x12, 0xa0, 0x4b, 0x30, 0x91, 0xbe, 0xbc, + 0xde, 0x8f, 0xcc, 0x25, 0xa3, 0x2d, 0x93, 0x56, 0x03, 0x57, 0x2d, 0xd3, + 0x34, 0x8c, 0xf7, 0x59, 0x1a, 0xa8, 0x81, 0x78, 0xcf, 0xe8, 0xbb, 0x8e, + 0xe4, 0xb1, 0x7f, 0x4f, 0x57, 0x25, 0xc0, 0x49, 0xdf, 0x63, 0x51, 0x35, + 0x46, 0x79, 0x00, 0x1b, 0x41, 0x0e, 0x05, 0x52, 0xe8, 0xc1, 0x9a, 0x93, + 0xa9, 0x12, 0x7a, 0xc9, 0x7d, 0xb6, 0xad, 0x08, 0xe0, 0x1a, 0xc9, 0xca, + 0xde, 0x43, 0x67, 0xfd, 0x98, 0xd7, 0x78, 0x79, 0xd7, 0x46, 0x46, 0x02, + 0xeb, 0x7a, 0x63, 0x32, 0x58, 0x07, 0x83, 0x0d, 0x88, 0xab, 0x9d, 0x76, + 0x68, 0x89, 0x0d, 0xfb, 0x4a, 0x32, 0x30, 0x41, 0xe2, 0x4b, 0x47, 0xd5, + 0xef, 0xcf, 0x6b, 0xd1, 0x6e, 0xf7, 0x30, 0x3c, 0x7f, 0x0c, 0xe9, 0x6d, + 0x60, 0xed, 0x71, 0x1b, 0x03, 0x75, 0x5e, 0x90, 0x27, 0x6f, 0x6b, 0xb7, + 0x25, 0x92, 0x1d, 0x31, 0xfc, 0x52, 0x9b, 0xe3, 0x20, 0x6e, 0x3a, 0x7b, + 0x0c, 0xcd, 0xab, 0x7e, 0x5f, 0x28, 0x18, 0x17, 0x72, 0x4d, 0x85, 0xef, + 0x6e, 0xd7, 0xdf, 0x88, 0xff, 0x15, 0x9d, 0xe0, 0x44, 0x2f, 0x6c, 0xc4, + 0x41, 0xb9, 0xa3, 0x7d, 0x62, 0xe9, 0xd9, 0x1c, 0x25, 0xdb, 0x8c, 0x54, + 0x29, 0x5d, 0xa7, 0x8e, 0x21, 0x6f, 0x50, 0x3e, 0x9e, 0x7e, 0x58, 0x65, + 0x39, 0xd6, 0x97, 0xe8, 0x04, 0x4c, 0x49, 0xb7, 0x74, 0xe7, 0x32, 0xab, + 0xc2, 0x20, 0x4c, 0x55, 0x57, 0x41, 0xa7, 0x85, 0x96, 0x68, 0x20, 0x49, + 0xa3, 0xfc, 0xce, 0x85, 0xc5, 0xf8, 0xed, 0xeb, 0xe3, 0xcf, 0x9e, 0x34, 0xa0, 0x82, 0x04, 0xc6, 0x30, 0x82, 0x04, 0xc2, 0x30, 0x82, 0x04, 0xbe, 0x30, 0x82, 0x03, 0xa6, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x04, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, @@ -337,37 +337,37 @@ unsigned char resp_nocert[] = { 0x72, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6e, 0x66, 0x6f, 0x40, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x18, 0x0f, - 0x32, 0x30, 0x32, 0x36, 0x30, 0x32, 0x32, 0x34, 0x32, 0x31, 0x34, 0x32, - 0x30, 0x31, 0x5a, 0x30, 0x4f, 0x30, 0x4d, 0x30, 0x38, 0x30, 0x07, 0x06, + 0x32, 0x30, 0x32, 0x36, 0x30, 0x35, 0x32, 0x31, 0x31, 0x37, 0x32, 0x34, + 0x33, 0x30, 0x5a, 0x30, 0x4f, 0x30, 0x4d, 0x30, 0x38, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x04, 0x14, 0x44, 0xa8, 0xdb, 0xd1, 0xbc, 0x97, 0x0a, 0x83, 0x3b, 0x5b, 0x31, 0x9a, 0x4c, 0xb8, 0xd2, 0x52, 0x37, 0x15, 0x8a, 0x88, 0x04, 0x14, 0x73, 0xb0, 0x1c, 0xa4, 0x2f, 0x82, 0xcb, 0xcf, 0x47, 0xa5, 0x38, 0xd7, 0xb0, 0x04, 0x82, 0x3a, 0x7e, 0x72, 0x15, 0x21, 0x02, 0x01, 0x01, 0x80, 0x00, 0x18, 0x0f, 0x32, 0x30, 0x32, - 0x36, 0x30, 0x32, 0x32, 0x34, 0x32, 0x31, 0x34, 0x32, 0x30, 0x31, 0x5a, + 0x36, 0x30, 0x35, 0x32, 0x31, 0x31, 0x37, 0x32, 0x34, 0x33, 0x30, 0x5a, 0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, - 0x0b, 0x03, 0x82, 0x01, 0x01, 0x00, 0x7a, 0xc5, 0x6d, 0xfa, 0x8b, 0x75, - 0x9a, 0x46, 0x91, 0x3b, 0x23, 0xc2, 0xa0, 0x0d, 0x60, 0x0e, 0x61, 0x54, - 0x7c, 0xd7, 0xcb, 0x6c, 0x14, 0x9b, 0x11, 0x96, 0xe2, 0x83, 0xfa, 0x0f, - 0x70, 0xc9, 0xc9, 0x07, 0xa8, 0x53, 0x69, 0x90, 0xbb, 0xd5, 0x31, 0xb4, - 0x6f, 0xfc, 0x6b, 0x6b, 0xd9, 0x1a, 0xe5, 0xbc, 0xc8, 0x25, 0x93, 0x0b, - 0x9e, 0x9d, 0xb3, 0x9b, 0x07, 0x38, 0x79, 0x4c, 0xd0, 0xa1, 0xd1, 0x3f, - 0xf6, 0x8a, 0xf0, 0x77, 0xa4, 0xea, 0x8d, 0x23, 0xf4, 0xb0, 0xdf, 0x59, - 0x41, 0x5c, 0x77, 0x0e, 0xc2, 0x1c, 0xab, 0xbb, 0xb6, 0x12, 0x2e, 0x37, - 0x1f, 0xf7, 0x57, 0xa0, 0x02, 0x02, 0xed, 0x8c, 0xb7, 0x4d, 0xdd, 0xd0, - 0x02, 0xb6, 0x5f, 0xff, 0xa3, 0x0a, 0x28, 0x4b, 0x8f, 0x4e, 0x6d, 0x57, - 0x55, 0xd0, 0x4f, 0x3f, 0x4c, 0x45, 0x5b, 0x6f, 0x8c, 0x8e, 0xe4, 0xd9, - 0x62, 0xe8, 0x4c, 0x72, 0xd8, 0x0b, 0x5c, 0xce, 0xc9, 0x53, 0x76, 0x0e, - 0xb1, 0xaf, 0xf8, 0x15, 0xb2, 0x50, 0xd5, 0x69, 0x6f, 0xbe, 0xee, 0x17, - 0x06, 0x43, 0xc6, 0x6d, 0x9a, 0x12, 0x3d, 0x57, 0x14, 0xb3, 0x39, 0xc8, - 0x58, 0x76, 0x46, 0x57, 0xe3, 0xb4, 0x4a, 0x82, 0x8e, 0xf3, 0xdc, 0x99, - 0x0a, 0x34, 0x6e, 0x65, 0x3c, 0xef, 0xe4, 0x42, 0x85, 0x6c, 0xc5, 0xaf, - 0x76, 0xdb, 0x75, 0x2d, 0xd5, 0xb2, 0x69, 0x08, 0xec, 0xa3, 0x1d, 0x8e, - 0xdc, 0x7c, 0xbf, 0xb7, 0xa9, 0x6c, 0x9f, 0x7f, 0x9e, 0xb8, 0x9e, 0x1d, - 0x20, 0x64, 0xcf, 0x30, 0xf2, 0x2d, 0xa7, 0x80, 0x77, 0x53, 0xf9, 0x15, - 0xf1, 0xef, 0xb2, 0xa4, 0x30, 0x02, 0x94, 0xfe, 0x43, 0xad, 0xa0, 0x7c, - 0x67, 0x47, 0xe2, 0x42, 0x4a, 0x2d, 0x02, 0x9e, 0x6a, 0xb6, 0xa1, 0x57, - 0x3e, 0x9a, 0x47, 0xe2, 0xb1, 0xb7, 0xd2, 0x0f, 0x32, 0x8f, + 0x0b, 0x03, 0x82, 0x01, 0x01, 0x00, 0x85, 0x29, 0xfc, 0x9a, 0x83, 0x8a, + 0xae, 0x8d, 0xcd, 0xb3, 0x3c, 0x6d, 0xa5, 0xd5, 0x6b, 0x62, 0x51, 0x58, + 0xdd, 0x16, 0xb4, 0x80, 0xe0, 0xf8, 0x78, 0xf6, 0xca, 0xa4, 0xfa, 0x7d, + 0x4a, 0xe6, 0x8a, 0xf7, 0xa8, 0x5f, 0x01, 0xe1, 0x9a, 0xfd, 0xc0, 0x3a, + 0xc5, 0x21, 0x68, 0x82, 0x3f, 0x82, 0xf1, 0x41, 0xab, 0xd6, 0xb1, 0x78, + 0x72, 0x70, 0xdf, 0xa7, 0xb4, 0xc7, 0xc6, 0xab, 0x0d, 0xc8, 0xd5, 0x54, + 0xae, 0xb9, 0x96, 0xad, 0xa1, 0xc7, 0x55, 0x65, 0xd9, 0x86, 0x8b, 0xe1, + 0x01, 0x4a, 0xb3, 0xbd, 0x4c, 0xc8, 0xd2, 0xc7, 0x15, 0xbd, 0xd3, 0x3f, + 0x5c, 0xe2, 0xf1, 0x59, 0xfc, 0x51, 0x04, 0x6f, 0xb1, 0x94, 0x66, 0xb9, + 0xc9, 0xa2, 0xbc, 0x5d, 0x25, 0x9a, 0x4c, 0x48, 0xe0, 0x1b, 0xb6, 0xd2, + 0x80, 0xb5, 0x05, 0x93, 0x3d, 0x6d, 0x28, 0x3f, 0xc5, 0x4e, 0x59, 0x1d, + 0x85, 0x1e, 0x37, 0xd3, 0x3d, 0x9c, 0xd6, 0x1c, 0xcb, 0xf9, 0x0f, 0x40, + 0x3b, 0x4d, 0xb3, 0xc1, 0xb6, 0x9d, 0x66, 0xbb, 0xe9, 0x15, 0x4c, 0xf7, + 0xac, 0x96, 0xfd, 0x32, 0xa6, 0xa7, 0xee, 0x06, 0xb5, 0x08, 0x1c, 0x0c, + 0x71, 0xdc, 0x48, 0x58, 0x41, 0x69, 0xb1, 0xd2, 0xad, 0xd5, 0x9a, 0x0d, + 0x66, 0xba, 0x82, 0x2a, 0x41, 0xcd, 0x86, 0xda, 0x72, 0x09, 0x4d, 0xa2, + 0xc5, 0xb2, 0x43, 0x0f, 0x4c, 0x08, 0x6e, 0x87, 0x00, 0x6f, 0x9d, 0xb7, + 0x10, 0x0a, 0x1f, 0x53, 0x14, 0x64, 0xaf, 0x97, 0xf2, 0x60, 0x12, 0xe5, + 0xe0, 0xd6, 0x11, 0x83, 0x44, 0x97, 0xa7, 0x3f, 0x63, 0xde, 0xc0, 0x27, + 0xd1, 0x48, 0xbe, 0x9f, 0xc3, 0x13, 0xf6, 0x18, 0xd4, 0x22, 0x34, 0x4b, + 0x02, 0x3f, 0x1b, 0xae, 0x33, 0xab, 0xc2, 0x26, 0xef, 0xfe, 0xdb, 0x27, + 0xf5, 0xc5, 0x11, 0xac, 0x25, 0x66, 0xe1, 0x62, 0x8c, 0x41, }; unsigned char resp_multi[] = { @@ -387,44 +387,44 @@ unsigned char resp_multi[] = { 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6e, 0x66, 0x6f, 0x40, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73, 0x6c, 0x2e, - 0x63, 0x6f, 0x6d, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x36, 0x30, 0x32, 0x32, - 0x34, 0x32, 0x31, 0x34, 0x32, 0x30, 0x31, 0x5a, 0x30, 0x81, 0x9e, 0x30, + 0x63, 0x6f, 0x6d, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x36, 0x30, 0x35, 0x32, + 0x31, 0x31, 0x37, 0x32, 0x34, 0x33, 0x30, 0x5a, 0x30, 0x81, 0x9e, 0x30, 0x4d, 0x30, 0x38, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x04, 0x14, 0x44, 0xa8, 0xdb, 0xd1, 0xbc, 0x97, 0x0a, 0x83, 0x3b, 0x5b, 0x31, 0x9a, 0x4c, 0xb8, 0xd2, 0x52, 0x37, 0x15, 0x8a, 0x88, 0x04, 0x14, 0x73, 0xb0, 0x1c, 0xa4, 0x2f, 0x82, 0xcb, 0xcf, 0x47, 0xa5, 0x38, 0xd7, 0xb0, 0x04, 0x82, 0x3a, 0x7e, 0x72, 0x15, 0x21, 0x02, 0x01, 0x01, 0x80, - 0x00, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x36, 0x30, 0x32, 0x32, 0x34, 0x32, - 0x31, 0x34, 0x32, 0x30, 0x31, 0x5a, 0x30, 0x4d, 0x30, 0x38, 0x30, 0x07, + 0x00, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x36, 0x30, 0x35, 0x32, 0x31, 0x31, + 0x37, 0x32, 0x34, 0x33, 0x30, 0x5a, 0x30, 0x4d, 0x30, 0x38, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x04, 0x14, 0x44, 0xa8, 0xdb, 0xd1, 0xbc, 0x97, 0x0a, 0x83, 0x3b, 0x5b, 0x31, 0x9a, 0x4c, 0xb8, 0xd2, 0x52, 0x37, 0x15, 0x8a, 0x88, 0x04, 0x14, 0x73, 0xb0, 0x1c, 0xa4, 0x2f, 0x82, 0xcb, 0xcf, 0x47, 0xa5, 0x38, 0xd7, 0xb0, 0x04, 0x82, 0x3a, 0x7e, 0x72, 0x15, 0x21, 0x02, 0x01, 0x02, 0x80, 0x00, 0x18, 0x0f, 0x32, 0x30, - 0x32, 0x36, 0x30, 0x32, 0x32, 0x34, 0x32, 0x31, 0x34, 0x32, 0x30, 0x31, + 0x32, 0x36, 0x30, 0x35, 0x32, 0x31, 0x31, 0x37, 0x32, 0x34, 0x33, 0x30, 0x5a, 0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, - 0x01, 0x0b, 0x03, 0x82, 0x01, 0x01, 0x00, 0x41, 0x54, 0xbe, 0x6b, 0x1c, - 0x61, 0x04, 0xd8, 0x18, 0x01, 0xc8, 0x63, 0xc4, 0x27, 0x4d, 0xf6, 0x16, - 0x1e, 0xef, 0x8e, 0x4b, 0x80, 0x90, 0x2d, 0x9d, 0xfe, 0xa6, 0x6c, 0x2b, - 0x91, 0x1c, 0x95, 0xbe, 0x2b, 0x5c, 0xdf, 0xaa, 0xcf, 0x79, 0x07, 0x15, - 0xe8, 0x31, 0x4f, 0xf5, 0xb5, 0x74, 0x47, 0x16, 0x75, 0x97, 0x49, 0x5e, - 0x60, 0xb5, 0x0e, 0x87, 0x35, 0x47, 0x99, 0x1e, 0xd7, 0x6b, 0x06, 0xad, - 0x38, 0xa5, 0x63, 0x00, 0x3e, 0x8c, 0xe5, 0xb1, 0xbf, 0x91, 0x85, 0x1a, - 0x70, 0x25, 0xcd, 0xa6, 0xcc, 0x0c, 0xb3, 0x18, 0x54, 0x4c, 0x52, 0x5e, - 0x33, 0x41, 0x61, 0xf7, 0x1e, 0x24, 0xc2, 0x42, 0xe2, 0xa4, 0xfe, 0xad, - 0x51, 0x09, 0x89, 0xe5, 0xb2, 0x4d, 0x32, 0x47, 0xd3, 0x5f, 0x8a, 0xc5, - 0x78, 0xa9, 0x8b, 0x4e, 0x78, 0xf0, 0xc6, 0xbd, 0x68, 0x72, 0x3a, 0xe7, - 0x1f, 0x80, 0x84, 0xbb, 0x05, 0x23, 0x16, 0x7a, 0x56, 0xf5, 0xff, 0xac, - 0xba, 0xbf, 0x99, 0x63, 0x9e, 0x7e, 0x8b, 0x1b, 0x98, 0xf3, 0x33, 0xcf, - 0xd4, 0x5b, 0x94, 0xcb, 0x4b, 0xd4, 0x4e, 0x55, 0x12, 0x4d, 0x33, 0xcf, - 0x12, 0x2f, 0x9c, 0xbd, 0x42, 0xf6, 0xb1, 0xad, 0x92, 0x81, 0x35, 0x24, - 0x29, 0x50, 0x25, 0x36, 0xb3, 0x6f, 0x9e, 0x78, 0x16, 0x2c, 0x3b, 0x4b, - 0x55, 0x46, 0xf9, 0x42, 0x24, 0x50, 0x4d, 0xba, 0x72, 0xae, 0x6e, 0xa0, - 0xa9, 0xcf, 0x46, 0xe1, 0xb3, 0x14, 0x6b, 0x4c, 0xbb, 0x1d, 0x92, 0x0f, - 0x90, 0xf8, 0xa5, 0x13, 0x88, 0x4c, 0x77, 0xc5, 0xd4, 0x82, 0xa3, 0xde, - 0xef, 0x74, 0x62, 0x4a, 0xc1, 0xb7, 0x8b, 0xb4, 0xac, 0xa4, 0x26, 0x32, - 0xed, 0x69, 0x1b, 0x3e, 0x4c, 0x04, 0xca, 0x5e, 0xbf, 0x19, 0x17, 0xf9, - 0xf1, 0x5e, 0x7a, 0x44, 0xd5, 0x1c, 0x51, 0xc2, 0x06, 0x2f, 0x74, + 0x01, 0x0b, 0x03, 0x82, 0x01, 0x01, 0x00, 0x3b, 0xac, 0x2e, 0xf1, 0xe4, + 0x9a, 0xad, 0x3f, 0xf5, 0x76, 0x41, 0xb0, 0xa5, 0x20, 0x85, 0x68, 0xf4, + 0xba, 0xf4, 0x38, 0x7d, 0x02, 0x9e, 0xe6, 0xcc, 0x18, 0x6f, 0x55, 0xc2, + 0xa9, 0x5c, 0xea, 0x60, 0xed, 0x66, 0x24, 0xab, 0x28, 0x29, 0x99, 0x13, + 0x52, 0x81, 0xae, 0xc2, 0x4a, 0x3c, 0xfa, 0x62, 0xea, 0x38, 0xad, 0x8d, + 0xd2, 0x1f, 0xd1, 0x68, 0x98, 0x9d, 0xbd, 0x3a, 0x34, 0x0d, 0x74, 0xbf, + 0x85, 0x3a, 0x32, 0xf0, 0x91, 0xb9, 0xd8, 0xd4, 0x75, 0x51, 0x8c, 0x0b, + 0x0f, 0x06, 0x57, 0xbb, 0x44, 0xe9, 0x8a, 0x0b, 0x74, 0x8f, 0xec, 0xd0, + 0xfe, 0x68, 0xed, 0x34, 0xef, 0xa3, 0x61, 0xaa, 0x03, 0x2a, 0xb4, 0xe5, + 0x9e, 0x25, 0x80, 0xc4, 0xa3, 0xe7, 0xce, 0xf6, 0x95, 0x5b, 0x0c, 0x86, + 0xdb, 0x57, 0xdd, 0xb9, 0xd2, 0xa5, 0x0c, 0x10, 0xf9, 0x36, 0x38, 0xd1, + 0x88, 0xff, 0x41, 0xb0, 0xbc, 0xc4, 0xb9, 0x6a, 0x38, 0x5f, 0xd2, 0x75, + 0x00, 0xf8, 0xd2, 0x85, 0xe4, 0x9c, 0x11, 0x21, 0x01, 0xec, 0x9a, 0xee, + 0x64, 0x3b, 0x6b, 0x2e, 0x1f, 0x17, 0x09, 0xf6, 0x1c, 0x83, 0x6e, 0x7b, + 0x5e, 0xd2, 0x3b, 0xad, 0x8e, 0x56, 0x4c, 0xc5, 0x84, 0x1f, 0xe7, 0x0c, + 0x6b, 0x9b, 0x70, 0x78, 0xad, 0xeb, 0x4d, 0xb1, 0xbe, 0x55, 0x27, 0x8e, + 0x91, 0x2d, 0x51, 0x37, 0xed, 0x84, 0xfe, 0xf6, 0x7c, 0xa4, 0x08, 0x52, + 0x82, 0x64, 0x39, 0x06, 0x85, 0x91, 0xf1, 0x41, 0xc6, 0x37, 0x4c, 0x63, + 0x20, 0xb7, 0x49, 0xef, 0xfd, 0xd5, 0xeb, 0x81, 0x77, 0x7b, 0xbd, 0xe7, + 0xf6, 0xfd, 0x61, 0xe7, 0x27, 0x0e, 0xe3, 0x8b, 0x16, 0xf6, 0x5b, 0x57, + 0x8b, 0x02, 0x1f, 0x53, 0x0f, 0x7f, 0x57, 0x83, 0x60, 0xd2, 0xe7, 0x19, + 0x67, 0x82, 0x53, 0x22, 0x50, 0xbc, 0xb1, 0xaf, 0xb4, 0x96, 0xd7, }; unsigned char resp_bad_noauth[] = { @@ -444,44 +444,44 @@ unsigned char resp_bad_noauth[] = { 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6e, 0x66, 0x6f, 0x40, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73, 0x6c, 0x2e, - 0x63, 0x6f, 0x6d, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x36, 0x30, 0x32, 0x32, - 0x34, 0x32, 0x31, 0x34, 0x32, 0x30, 0x31, 0x5a, 0x30, 0x81, 0x9e, 0x30, + 0x63, 0x6f, 0x6d, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x36, 0x30, 0x35, 0x32, + 0x31, 0x31, 0x37, 0x32, 0x34, 0x33, 0x30, 0x5a, 0x30, 0x81, 0x9e, 0x30, 0x4d, 0x30, 0x38, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x04, 0x14, 0x44, 0xa8, 0xdb, 0xd1, 0xbc, 0x97, 0x0a, 0x83, 0x3b, 0x5b, 0x31, 0x9a, 0x4c, 0xb8, 0xd2, 0x52, 0x37, 0x15, 0x8a, 0x88, 0x04, 0x14, 0x73, 0xb0, 0x1c, 0xa4, 0x2f, 0x82, 0xcb, 0xcf, 0x47, 0xa5, 0x38, 0xd7, 0xb0, 0x04, 0x82, 0x3a, 0x7e, 0x72, 0x15, 0x21, 0x02, 0x01, 0x01, 0x80, - 0x00, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x36, 0x30, 0x32, 0x32, 0x34, 0x32, - 0x31, 0x34, 0x32, 0x30, 0x31, 0x5a, 0x30, 0x4d, 0x30, 0x38, 0x30, 0x07, + 0x00, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x36, 0x30, 0x35, 0x32, 0x31, 0x31, + 0x37, 0x32, 0x34, 0x33, 0x30, 0x5a, 0x30, 0x4d, 0x30, 0x38, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x04, 0x14, 0xff, 0x66, 0x21, 0x8a, 0x6e, 0xc5, 0x86, 0x61, 0x84, 0x25, 0x9a, 0xba, 0xd6, 0x55, 0x39, 0xfb, 0x25, 0x51, 0x2c, 0xdd, 0x04, 0x14, 0x27, 0x8e, 0x67, 0x11, 0x74, 0xc3, 0x26, 0x1d, 0x3f, 0xed, 0x33, 0x63, 0xb3, 0xa4, 0xd8, 0x1d, 0x30, 0xe5, 0xe8, 0xd5, 0x02, 0x01, 0x01, 0x80, 0x00, 0x18, 0x0f, 0x32, 0x30, - 0x32, 0x36, 0x30, 0x32, 0x32, 0x34, 0x32, 0x31, 0x34, 0x32, 0x30, 0x31, + 0x32, 0x36, 0x30, 0x35, 0x32, 0x31, 0x31, 0x37, 0x32, 0x34, 0x33, 0x30, 0x5a, 0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, - 0x01, 0x0b, 0x03, 0x82, 0x01, 0x01, 0x00, 0x48, 0xda, 0xe8, 0xb5, 0x4d, - 0xaa, 0x6e, 0x28, 0xd8, 0x30, 0xb3, 0x3d, 0x50, 0xf8, 0x83, 0x3c, 0xbb, - 0x2a, 0xb2, 0x10, 0x20, 0x48, 0x53, 0x78, 0x33, 0x8d, 0x31, 0x90, 0xbd, - 0x54, 0xa1, 0x49, 0x6b, 0xc0, 0x2f, 0x8b, 0xf1, 0x02, 0x39, 0x90, 0x73, - 0xfc, 0x81, 0x1e, 0xf2, 0xc9, 0xaa, 0x14, 0x5e, 0xb8, 0xda, 0x89, 0xdb, - 0x1a, 0xde, 0xc1, 0xcf, 0x61, 0xb2, 0xbf, 0x1a, 0xa7, 0x50, 0x51, 0x47, - 0x5e, 0x0e, 0xdb, 0xdb, 0x2f, 0xad, 0x46, 0xcc, 0x02, 0x71, 0xb7, 0x37, - 0xc9, 0x1a, 0x7d, 0xc9, 0xc2, 0x55, 0x45, 0xa3, 0xc6, 0x17, 0xfc, 0x53, - 0x6e, 0x11, 0xf2, 0x31, 0x13, 0x71, 0xe6, 0x65, 0xc0, 0xf7, 0x05, 0xda, - 0x97, 0x33, 0x37, 0xdc, 0x81, 0x4a, 0xc5, 0x99, 0x89, 0xc1, 0xe3, 0x8f, - 0x99, 0x02, 0xb1, 0xda, 0x44, 0x16, 0x63, 0x14, 0x12, 0x20, 0x49, 0x01, - 0x44, 0xa4, 0xe6, 0x6d, 0xde, 0x8f, 0xfb, 0x7a, 0xbd, 0xcb, 0xf8, 0xd4, - 0x2d, 0x18, 0x65, 0x44, 0xc5, 0x5c, 0xec, 0xd4, 0x7a, 0x1f, 0x6a, 0xf6, - 0xa2, 0x71, 0x7b, 0x03, 0x61, 0xa9, 0x9b, 0x2b, 0x3d, 0xe1, 0x8d, 0xea, - 0x75, 0xa8, 0x0c, 0x22, 0xa3, 0xa6, 0x3d, 0xb8, 0x79, 0x88, 0x4b, 0x34, - 0x9c, 0x5b, 0x37, 0x17, 0x85, 0xf7, 0xbb, 0xd4, 0xaa, 0x51, 0x58, 0x09, - 0x39, 0x0c, 0xa1, 0xca, 0x90, 0x50, 0x7c, 0x2f, 0x4e, 0x92, 0xfc, 0xdd, - 0xd3, 0xca, 0x64, 0xcc, 0x25, 0x4c, 0xfc, 0xaa, 0x04, 0x68, 0x5e, 0x66, - 0x7f, 0x3d, 0x04, 0x28, 0x42, 0xae, 0x93, 0xd2, 0x75, 0x38, 0x55, 0x38, - 0xc3, 0xda, 0x5d, 0x93, 0x20, 0x74, 0x31, 0x02, 0x95, 0x07, 0x8e, 0x91, - 0xd0, 0x0e, 0x17, 0xca, 0xe7, 0x8d, 0x1e, 0xb1, 0x56, 0x26, 0x4c, 0x65, - 0x66, 0x5f, 0x53, 0x69, 0x7d, 0xd7, 0x3a, 0xa7, 0x70, 0xf7, 0xbd, + 0x01, 0x0b, 0x03, 0x82, 0x01, 0x01, 0x00, 0x5e, 0x03, 0xfb, 0xde, 0xda, + 0xc4, 0xa8, 0x28, 0x22, 0x16, 0x09, 0x6c, 0xef, 0xe7, 0xf2, 0x9d, 0xb9, + 0x36, 0x99, 0xf1, 0xae, 0x7d, 0xd9, 0x1f, 0x28, 0x67, 0xc1, 0xd5, 0x2a, + 0x0d, 0xaa, 0xe7, 0x42, 0xac, 0x65, 0x79, 0xdf, 0x59, 0xe7, 0x85, 0xdd, + 0x38, 0x03, 0x75, 0x99, 0x4a, 0x9f, 0x7f, 0xc5, 0x8f, 0x2e, 0x49, 0x00, + 0x13, 0xad, 0x08, 0x7e, 0x6e, 0x8b, 0xb6, 0x63, 0xba, 0xe3, 0x3c, 0xe5, + 0x58, 0x68, 0x37, 0x24, 0x5e, 0x27, 0x46, 0x1d, 0x92, 0xc3, 0x7a, 0xd1, + 0xc3, 0x9d, 0xd5, 0xb7, 0xbe, 0x7a, 0xaf, 0xb7, 0x30, 0xa9, 0xbb, 0xbd, + 0xb1, 0xdf, 0xc9, 0x9d, 0xdc, 0x7d, 0x61, 0xe5, 0x58, 0xe8, 0x32, 0x9d, + 0x99, 0xf6, 0xfa, 0xce, 0x03, 0xdf, 0x23, 0x37, 0x4f, 0x05, 0x63, 0xa6, + 0x5a, 0xc9, 0x30, 0x94, 0x39, 0x9c, 0x4f, 0xb7, 0x7d, 0x1b, 0xf5, 0xa7, + 0x69, 0x10, 0xc0, 0x6e, 0xb3, 0x47, 0x5c, 0x76, 0xfe, 0x11, 0xb6, 0x40, + 0x12, 0x8b, 0x25, 0x19, 0x5a, 0x79, 0x1c, 0x14, 0x14, 0xfc, 0x48, 0x95, + 0x0d, 0x2d, 0x4c, 0x6e, 0x80, 0xa1, 0x25, 0xb9, 0x7c, 0xf3, 0x36, 0x9a, + 0xb5, 0xde, 0x25, 0xf1, 0xd9, 0xe1, 0x9a, 0x7a, 0xcd, 0xba, 0x53, 0x02, + 0x32, 0x19, 0x6e, 0x6a, 0xa2, 0x3e, 0x4e, 0x00, 0x26, 0xb1, 0x5b, 0xb9, + 0xd0, 0xa0, 0xd8, 0xcd, 0x08, 0x93, 0xda, 0x98, 0x2c, 0xc8, 0xaa, 0xb4, + 0x05, 0x8b, 0x27, 0x34, 0x9c, 0x52, 0x56, 0x23, 0x43, 0x77, 0x25, 0x6c, + 0x9c, 0x5c, 0xbd, 0x5a, 0x01, 0x85, 0xa5, 0x50, 0x86, 0x7c, 0x92, 0xec, + 0x2d, 0x3d, 0xc7, 0xa3, 0x88, 0x6e, 0xd8, 0xd0, 0xa3, 0xf9, 0x02, 0xe1, + 0xf8, 0xaa, 0x84, 0x9f, 0x35, 0x37, 0x53, 0xab, 0x45, 0x5b, 0x77, 0xaf, + 0x8b, 0xf0, 0x3a, 0xf7, 0xe2, 0xe3, 0xee, 0xb5, 0x85, 0x07, 0xef, }; unsigned char resp_bad_embedded_cert[] = { @@ -501,38 +501,38 @@ unsigned char resp_bad_embedded_cert[] = { 0x6f, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6e, 0x66, 0x6f, 0x40, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73, 0x6c, 0x2e, 0x63, - 0x6f, 0x6d, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x36, 0x30, 0x32, 0x32, 0x34, - 0x32, 0x31, 0x34, 0x32, 0x30, 0x31, 0x5a, 0x30, 0x4f, 0x30, 0x4d, 0x30, + 0x6f, 0x6d, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x36, 0x30, 0x35, 0x32, 0x31, + 0x31, 0x37, 0x32, 0x34, 0x33, 0x30, 0x5a, 0x30, 0x4f, 0x30, 0x4d, 0x30, 0x38, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x04, 0x14, 0x44, 0xa8, 0xdb, 0xd1, 0xbc, 0x97, 0x0a, 0x83, 0x3b, 0x5b, 0x31, 0x9a, 0x4c, 0xb8, 0xd2, 0x52, 0x37, 0x15, 0x8a, 0x88, 0x04, 0x14, 0x73, 0xb0, 0x1c, 0xa4, 0x2f, 0x82, 0xcb, 0xcf, 0x47, 0xa5, 0x38, 0xd7, 0xb0, 0x04, 0x82, 0x3a, 0x7e, 0x72, 0x15, 0x21, 0x02, 0x01, 0x01, 0x80, 0x00, 0x18, - 0x0f, 0x32, 0x30, 0x32, 0x36, 0x30, 0x32, 0x32, 0x34, 0x32, 0x31, 0x34, - 0x32, 0x30, 0x31, 0x5a, 0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, - 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x03, 0x82, 0x01, 0x01, 0x00, 0x8f, 0xd5, - 0x57, 0x10, 0xc3, 0x7e, 0x8c, 0x6c, 0x0b, 0x75, 0x68, 0xca, 0x03, 0x12, - 0x30, 0xa7, 0xdb, 0x48, 0xf8, 0x1e, 0x3c, 0x42, 0x41, 0xdd, 0x4f, 0xf2, - 0x6c, 0xa4, 0x6f, 0x67, 0x15, 0x5a, 0xce, 0x04, 0xb9, 0x6d, 0xcb, 0x9d, - 0x06, 0x24, 0xa7, 0xf4, 0xaa, 0x31, 0x8c, 0xb5, 0x3c, 0x23, 0xbc, 0xea, - 0x5e, 0xe1, 0x47, 0x13, 0xe7, 0xcd, 0x33, 0x93, 0x23, 0x8d, 0xe4, 0x16, - 0x70, 0xdb, 0x75, 0x93, 0x34, 0xeb, 0x25, 0xbf, 0xd4, 0x24, 0x62, 0x27, - 0xe0, 0xfe, 0x20, 0xed, 0x1a, 0xd1, 0x2a, 0xae, 0xc4, 0x2d, 0xb6, 0xd8, - 0xbf, 0xbc, 0x6f, 0x15, 0x9f, 0xa1, 0xdc, 0x7d, 0x49, 0xa2, 0x95, 0x02, - 0xcf, 0x7f, 0x82, 0xeb, 0x27, 0x5a, 0x5b, 0xc2, 0xc9, 0xf8, 0xa9, 0x3c, - 0xc1, 0xc4, 0xa5, 0xed, 0xf2, 0x10, 0x3b, 0x2b, 0x5d, 0x84, 0xea, 0x90, - 0xff, 0x9b, 0xff, 0x23, 0x64, 0x15, 0x8e, 0x7b, 0xaf, 0x53, 0x16, 0x38, - 0x7c, 0x68, 0x3c, 0xfb, 0x29, 0x4c, 0xf4, 0x25, 0xf6, 0xf9, 0x91, 0x38, - 0xdd, 0x41, 0xa2, 0xb6, 0xd6, 0x85, 0x6e, 0xaf, 0xdf, 0x8a, 0x7f, 0x45, - 0xcd, 0x3b, 0x91, 0x84, 0x69, 0x93, 0xe2, 0xf7, 0x97, 0x0f, 0x93, 0x06, - 0xbe, 0x8e, 0x51, 0xda, 0x4f, 0x91, 0xa9, 0x7f, 0x97, 0xc3, 0x4b, 0x4a, - 0x4a, 0xd7, 0x8c, 0x9b, 0xb0, 0x38, 0x80, 0xe4, 0x9e, 0x74, 0xec, 0x2f, - 0x31, 0xb2, 0xa2, 0x77, 0x36, 0x5a, 0x4a, 0x74, 0x00, 0x3b, 0x33, 0x4e, - 0x59, 0xdc, 0xe4, 0xff, 0xb4, 0xfd, 0x1a, 0x37, 0x19, 0x37, 0x5c, 0xf9, - 0x9b, 0x94, 0x55, 0x99, 0xe2, 0x41, 0x78, 0xd2, 0xe0, 0x87, 0xf2, 0xc6, - 0x94, 0x7c, 0xaa, 0xd5, 0x28, 0xc4, 0x44, 0x0b, 0xa2, 0x29, 0xeb, 0xcb, - 0x2e, 0x2e, 0xcb, 0x6f, 0xe3, 0x64, 0xea, 0xe0, 0x77, 0x09, 0xf2, 0x3f, - 0x0b, 0xd6, 0xa0, 0x82, 0x04, 0xf8, 0x30, 0x82, 0x04, 0xf4, 0x30, 0x82, + 0x0f, 0x32, 0x30, 0x32, 0x36, 0x30, 0x35, 0x32, 0x31, 0x31, 0x37, 0x32, + 0x34, 0x33, 0x30, 0x5a, 0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x03, 0x82, 0x01, 0x01, 0x00, 0x78, 0xff, + 0xbc, 0xcc, 0x0e, 0xd8, 0xc6, 0xd9, 0xa4, 0x0e, 0x81, 0x8f, 0x41, 0xaa, + 0x5f, 0xc3, 0x34, 0x47, 0x57, 0x70, 0x4f, 0x6d, 0x09, 0x26, 0x46, 0xb7, + 0x9f, 0x32, 0xb7, 0x66, 0x90, 0x91, 0x88, 0xa6, 0x9b, 0x08, 0x7d, 0xb6, + 0x7a, 0x71, 0xbe, 0x1b, 0x5a, 0xab, 0xff, 0x55, 0x86, 0xb5, 0x19, 0x0d, + 0xb8, 0x6f, 0x98, 0xe3, 0x00, 0xb0, 0x7d, 0x3d, 0xab, 0x65, 0x97, 0x16, + 0x0d, 0x0b, 0xeb, 0x2f, 0x10, 0xb0, 0x9f, 0x6c, 0x92, 0x2e, 0x96, 0xbf, + 0xa4, 0x8a, 0x11, 0x35, 0xd9, 0xf4, 0x2e, 0x34, 0x7e, 0xe6, 0x11, 0x8d, + 0x75, 0x0f, 0xf6, 0x7f, 0xc1, 0x29, 0xd2, 0xe7, 0xb8, 0xf5, 0x0d, 0xb4, + 0xfe, 0xe5, 0xe9, 0xeb, 0x39, 0xb5, 0xf7, 0xaa, 0xb7, 0x09, 0x84, 0x47, + 0x6f, 0x17, 0x60, 0x5b, 0xc0, 0x10, 0x30, 0xc5, 0xba, 0x61, 0x4e, 0xa7, + 0x6e, 0x03, 0xab, 0xe6, 0x5d, 0xb0, 0xb5, 0xb4, 0xee, 0x11, 0x15, 0xa6, + 0x57, 0x1c, 0xf2, 0x2b, 0x16, 0x62, 0x26, 0xf5, 0x3f, 0x2c, 0x12, 0x7d, + 0x62, 0x0f, 0x84, 0xa4, 0x3e, 0xf2, 0xf9, 0x73, 0x2d, 0x35, 0x28, 0x0b, + 0x99, 0x0e, 0xa0, 0xa5, 0xa5, 0xce, 0x78, 0xf6, 0x83, 0xd1, 0xbc, 0x21, + 0xe4, 0xf3, 0x73, 0xe7, 0x52, 0x8c, 0xe8, 0x33, 0x75, 0x4a, 0x96, 0xb6, + 0x05, 0xbc, 0xdb, 0x2e, 0xc5, 0x56, 0xce, 0x9c, 0xb0, 0x8e, 0x31, 0xf3, + 0xcd, 0xa0, 0x52, 0x4d, 0x66, 0x20, 0x53, 0x1d, 0x37, 0xc7, 0x2e, 0x25, + 0x96, 0x44, 0x1e, 0x87, 0x10, 0xd6, 0xe0, 0xe1, 0xc5, 0xd6, 0x12, 0x77, + 0x11, 0x48, 0x4e, 0x1e, 0x0a, 0xdf, 0x69, 0x22, 0x31, 0xb9, 0xab, 0x55, + 0x00, 0xdb, 0xea, 0xf3, 0xc4, 0x2b, 0x40, 0x61, 0xb8, 0xba, 0xff, 0x1c, + 0xf6, 0xc6, 0xbf, 0xe2, 0xea, 0xaa, 0xdd, 0xdc, 0x0a, 0x11, 0x68, 0x54, + 0xa4, 0xa5, 0xa0, 0x82, 0x04, 0xf8, 0x30, 0x82, 0x04, 0xf4, 0x30, 0x82, 0x04, 0xf0, 0x30, 0x82, 0x03, 0xd8, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x02, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0x97, 0x31, 0x0b, 0x30, 0x09, @@ -642,6 +642,58 @@ unsigned char resp_bad_embedded_cert[] = { }; unsigned char resp_server1_cert[] = { + 0x30, 0x82, 0x02, 0x3d, 0x0a, 0x01, 0x00, 0xa0, 0x82, 0x02, 0x36, 0x30, + 0x82, 0x02, 0x32, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, + 0x01, 0x01, 0x04, 0x82, 0x02, 0x23, 0x30, 0x82, 0x02, 0x1f, 0x30, 0x82, + 0x01, 0x09, 0xa1, 0x81, 0xa4, 0x30, 0x81, 0xa1, 0x31, 0x0b, 0x30, 0x09, + 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, + 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, + 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, + 0x55, 0x04, 0x07, 0x0c, 0x07, 0x53, 0x65, 0x61, 0x74, 0x74, 0x6c, 0x65, + 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x07, 0x77, + 0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, + 0x55, 0x04, 0x0b, 0x0c, 0x0b, 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x65, + 0x72, 0x69, 0x6e, 0x67, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x0c, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, 0x20, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x20, + 0x43, 0x41, 0x20, 0x31, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6e, 0x66, + 0x6f, 0x40, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, + 0x6d, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x36, 0x30, 0x35, 0x32, 0x31, 0x31, + 0x37, 0x32, 0x34, 0x33, 0x30, 0x5a, 0x30, 0x4f, 0x30, 0x4d, 0x30, 0x38, + 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x04, 0x14, 0x71, + 0x4d, 0x82, 0x23, 0x40, 0x59, 0xc0, 0x96, 0xa1, 0x37, 0x43, 0xfa, 0x31, + 0xdb, 0xba, 0xb1, 0x43, 0x18, 0xda, 0x04, 0x04, 0x14, 0x83, 0xc6, 0x3a, + 0x89, 0x2c, 0x81, 0xf4, 0x02, 0xd7, 0x9d, 0x4c, 0xe2, 0x2a, 0xc0, 0x71, + 0x82, 0x64, 0x44, 0xda, 0x0e, 0x02, 0x01, 0x05, 0x80, 0x00, 0x18, 0x0f, + 0x32, 0x30, 0x32, 0x36, 0x30, 0x35, 0x32, 0x31, 0x31, 0x37, 0x32, 0x34, + 0x33, 0x30, 0x5a, 0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x0b, 0x03, 0x82, 0x01, 0x01, 0x00, 0x2a, 0x94, 0xb0, + 0xbc, 0x96, 0x8e, 0x92, 0x20, 0x60, 0x50, 0xe9, 0x97, 0xeb, 0xa4, 0xb8, + 0x7d, 0x89, 0x95, 0xd9, 0x52, 0xc1, 0xc5, 0xc5, 0x75, 0x8b, 0x1c, 0xdd, + 0xfb, 0x4a, 0x66, 0x1f, 0x12, 0x9e, 0x7e, 0x31, 0x94, 0xa8, 0xdf, 0xca, + 0xbf, 0x8e, 0xe6, 0xe9, 0x5a, 0x80, 0xc8, 0x4b, 0xad, 0x0b, 0x5e, 0x7f, + 0x21, 0xbc, 0xd5, 0x9b, 0xda, 0x6d, 0x71, 0x5a, 0xa6, 0x8f, 0xc7, 0x51, + 0x7e, 0x6c, 0x79, 0xf7, 0xdb, 0xad, 0xd6, 0x31, 0x28, 0x7d, 0x3b, 0x90, + 0x86, 0xaf, 0xd1, 0x84, 0x58, 0x56, 0xae, 0x40, 0x95, 0xfb, 0xef, 0x9a, + 0x23, 0x5b, 0xe6, 0x88, 0xdf, 0x85, 0x7d, 0xef, 0x56, 0x98, 0x97, 0x2e, + 0x6d, 0x89, 0x54, 0x6a, 0x78, 0xa9, 0x4a, 0xa1, 0x38, 0x3a, 0x66, 0x02, + 0x3d, 0x56, 0xd5, 0x77, 0x7a, 0xe3, 0xfd, 0xba, 0xe6, 0x0c, 0x38, 0x50, + 0xd2, 0x0d, 0x5c, 0x81, 0x2c, 0xd2, 0x2e, 0xa8, 0xb6, 0x10, 0x55, 0xa7, + 0xd0, 0xe0, 0x31, 0x7f, 0x5f, 0x62, 0xf7, 0xdb, 0x36, 0x18, 0x4a, 0x2e, + 0x31, 0xb4, 0x0d, 0x82, 0x68, 0xf4, 0x4b, 0xc6, 0xd6, 0x15, 0x4d, 0xf7, + 0x41, 0x7a, 0x4f, 0xc0, 0x80, 0xfe, 0xfb, 0x42, 0x45, 0x40, 0xb5, 0x66, + 0xf4, 0x69, 0x68, 0xa3, 0xcc, 0x1c, 0x7c, 0xba, 0x48, 0xb6, 0xec, 0xd4, + 0xd5, 0x1f, 0xc5, 0x50, 0xd8, 0xcb, 0x18, 0xa6, 0x9d, 0x86, 0x50, 0x55, + 0x02, 0x07, 0x9e, 0xab, 0xe5, 0x5c, 0x19, 0xa2, 0xcf, 0x3d, 0x66, 0xdc, + 0x9c, 0xaa, 0x94, 0xaa, 0x04, 0x1b, 0xfc, 0xbf, 0x9c, 0xa3, 0xc4, 0xf3, + 0x2e, 0x27, 0xf6, 0xf4, 0x15, 0x9e, 0x15, 0xd0, 0x94, 0xf5, 0x83, 0x5a, + 0x3a, 0xc3, 0xb3, 0xa2, 0x42, 0x24, 0x03, 0xb7, 0xbb, 0xa6, 0x4c, 0x0f, + 0xb4, 0xa9, 0x2d, 0x4f, 0x4e, 0x60, 0xd5, 0x2e, 0xc4, 0x72, 0xb3, 0x8e, + 0xc4, +}; + +unsigned char resp_server1_cert_ancestor_responder[] = { 0x30, 0x82, 0x07, 0x04, 0x0a, 0x01, 0x00, 0xa0, 0x82, 0x06, 0xfd, 0x30, 0x82, 0x06, 0xf9, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01, 0x04, 0x82, 0x06, 0xea, 0x30, 0x82, 0x06, 0xe6, 0x30, 0x82, @@ -659,37 +711,37 @@ unsigned char resp_server1_cert[] = { 0x72, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6e, 0x66, 0x6f, 0x40, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x18, 0x0f, - 0x32, 0x30, 0x32, 0x36, 0x30, 0x32, 0x32, 0x34, 0x32, 0x31, 0x34, 0x32, - 0x30, 0x31, 0x5a, 0x30, 0x4f, 0x30, 0x4d, 0x30, 0x38, 0x30, 0x07, 0x06, + 0x32, 0x30, 0x32, 0x36, 0x30, 0x35, 0x32, 0x31, 0x31, 0x37, 0x32, 0x34, + 0x33, 0x30, 0x5a, 0x30, 0x4f, 0x30, 0x4d, 0x30, 0x38, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x04, 0x14, 0x71, 0x4d, 0x82, 0x23, 0x40, 0x59, 0xc0, 0x96, 0xa1, 0x37, 0x43, 0xfa, 0x31, 0xdb, 0xba, 0xb1, 0x43, 0x18, 0xda, 0x04, 0x04, 0x14, 0x83, 0xc6, 0x3a, 0x89, 0x2c, 0x81, 0xf4, 0x02, 0xd7, 0x9d, 0x4c, 0xe2, 0x2a, 0xc0, 0x71, 0x82, 0x64, 0x44, 0xda, 0x0e, 0x02, 0x01, 0x05, 0x80, 0x00, 0x18, 0x0f, 0x32, 0x30, 0x32, - 0x36, 0x30, 0x32, 0x32, 0x34, 0x32, 0x31, 0x34, 0x32, 0x30, 0x31, 0x5a, + 0x36, 0x30, 0x35, 0x32, 0x31, 0x31, 0x37, 0x32, 0x34, 0x33, 0x30, 0x5a, 0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, - 0x0b, 0x03, 0x82, 0x01, 0x01, 0x00, 0x71, 0x24, 0xd7, 0x8c, 0x32, 0x35, - 0x81, 0xe4, 0x17, 0xd4, 0x7a, 0xa2, 0xc4, 0x8f, 0xb6, 0xa3, 0x02, 0x94, - 0x5b, 0xf4, 0xfc, 0x8e, 0xed, 0x3a, 0xb5, 0x47, 0xfe, 0xe5, 0xe7, 0xb5, - 0x0a, 0xc7, 0x2d, 0x2e, 0x64, 0x80, 0x42, 0x32, 0x89, 0x89, 0x87, 0x6e, - 0x42, 0x08, 0xa8, 0x3e, 0x19, 0x09, 0xb3, 0x8b, 0xde, 0x3c, 0x90, 0x37, - 0x92, 0x9a, 0xb3, 0xf5, 0x71, 0x4b, 0x75, 0x99, 0x71, 0x75, 0xd2, 0xc0, - 0x1a, 0x09, 0xdf, 0x38, 0xf8, 0x08, 0x5e, 0x67, 0xa1, 0x39, 0x24, 0xe7, - 0xb7, 0x2a, 0x0e, 0xd6, 0x5b, 0x27, 0x64, 0xbf, 0x7d, 0x55, 0x13, 0x48, - 0x43, 0xa2, 0xac, 0x17, 0x9a, 0x4a, 0x84, 0x12, 0xb0, 0xb2, 0xdc, 0x8e, - 0xa0, 0xd8, 0x06, 0xb9, 0x85, 0xb1, 0xb3, 0x71, 0xe9, 0x01, 0xdb, 0xc7, - 0x67, 0x53, 0xa3, 0xcf, 0xab, 0x7a, 0x38, 0x43, 0x06, 0xc6, 0xec, 0x50, - 0x7d, 0xb0, 0xb3, 0xdd, 0xa0, 0x04, 0xfc, 0xa3, 0xe1, 0x1b, 0x83, 0xb4, - 0xfd, 0x6e, 0x0f, 0x94, 0xa2, 0x51, 0x02, 0x53, 0xbe, 0xed, 0x77, 0x6d, - 0xe3, 0x3a, 0xec, 0x1d, 0x61, 0xac, 0xcd, 0x24, 0x47, 0xbd, 0x1a, 0xa4, - 0xcd, 0x04, 0x36, 0x6d, 0x31, 0xe2, 0xca, 0x1c, 0xd8, 0x0e, 0xa3, 0x3b, - 0x12, 0xee, 0x35, 0x33, 0xe1, 0x75, 0x88, 0xd5, 0x0d, 0x71, 0x19, 0x9c, - 0xdf, 0x96, 0x62, 0x2f, 0xa5, 0x77, 0xbb, 0x93, 0x51, 0x80, 0xe8, 0x71, - 0x2b, 0xb3, 0x72, 0x1a, 0xda, 0x25, 0x44, 0x7a, 0x9a, 0x8d, 0xb3, 0x14, - 0x64, 0x16, 0xe4, 0xf6, 0x59, 0x32, 0x4e, 0x37, 0xa0, 0x7a, 0x4d, 0xcb, - 0xb8, 0xef, 0x1a, 0xfd, 0x40, 0x0e, 0x29, 0x47, 0x14, 0x7a, 0xd6, 0x2f, - 0xa3, 0x08, 0x5f, 0xe2, 0xe0, 0xf7, 0xac, 0xb8, 0x1e, 0x82, 0xae, 0x1d, - 0x21, 0x61, 0xa5, 0xec, 0x83, 0x57, 0x03, 0x06, 0xdc, 0xe9, 0xa0, 0x82, + 0x0b, 0x03, 0x82, 0x01, 0x01, 0x00, 0x87, 0x90, 0x6e, 0xd1, 0x7a, 0xc8, + 0x9f, 0x4c, 0xb7, 0xf3, 0x15, 0xb7, 0x54, 0x08, 0x7a, 0xda, 0x42, 0x06, + 0x2a, 0xa0, 0x11, 0xe0, 0xb9, 0xf1, 0xc5, 0xdb, 0x61, 0x28, 0x30, 0x68, + 0xe2, 0xe6, 0x24, 0x87, 0x44, 0x5c, 0xe4, 0x7f, 0xe1, 0xbc, 0xab, 0x9a, + 0xcb, 0x47, 0x3c, 0xee, 0x36, 0x73, 0xe8, 0xda, 0x6c, 0xd8, 0x7a, 0xb7, + 0x40, 0x5b, 0x42, 0x8e, 0xc5, 0x26, 0x0e, 0x3d, 0x41, 0x8a, 0xee, 0xee, + 0x24, 0x9b, 0x28, 0x40, 0xb3, 0x24, 0x73, 0x7f, 0xd9, 0xb0, 0x94, 0xfb, + 0x24, 0x64, 0xf1, 0x9a, 0xef, 0xe3, 0x35, 0x84, 0xc5, 0x3b, 0x1a, 0x05, + 0xa0, 0x4f, 0x01, 0x2a, 0x33, 0x96, 0xa3, 0xcc, 0x29, 0x78, 0x4a, 0x34, + 0x9c, 0xe2, 0xe5, 0xe5, 0x48, 0x59, 0x23, 0xf0, 0xf0, 0x3f, 0x1c, 0xd8, + 0x70, 0xcd, 0xe4, 0x0e, 0xaf, 0x8b, 0xac, 0x29, 0x78, 0xa1, 0x65, 0x5a, + 0x8b, 0x2c, 0xe4, 0xb1, 0x4c, 0xea, 0x84, 0xa3, 0xd3, 0x18, 0x10, 0x11, + 0x20, 0xc3, 0x10, 0x3f, 0x1e, 0x94, 0x55, 0xca, 0x53, 0x7a, 0xc3, 0x6d, + 0x8f, 0x78, 0xed, 0x40, 0x27, 0xdd, 0xf0, 0xfd, 0x30, 0x8a, 0x21, 0xa2, + 0x99, 0x86, 0xcb, 0x16, 0x44, 0x5e, 0x5d, 0xd1, 0x0d, 0x9b, 0x0e, 0x19, + 0x73, 0xd4, 0x44, 0x0b, 0x83, 0x22, 0xee, 0x25, 0xcd, 0xcd, 0xa0, 0xef, + 0xd0, 0xbc, 0xc5, 0xda, 0xef, 0x10, 0xcf, 0xf7, 0x2c, 0xb7, 0x72, 0x09, + 0x51, 0xe5, 0x6d, 0xe2, 0x54, 0x6d, 0x9c, 0x83, 0x83, 0x48, 0x2c, 0xb5, + 0x9c, 0x53, 0x99, 0x2f, 0xc9, 0x92, 0x1c, 0xaa, 0x45, 0xdc, 0x7f, 0xc9, + 0xe1, 0x8c, 0xa6, 0xbf, 0x1f, 0x6e, 0x0e, 0x4b, 0x40, 0xf1, 0x14, 0x7b, + 0x37, 0x01, 0x19, 0x2d, 0x8a, 0xda, 0xd9, 0xf2, 0x8a, 0x78, 0xf6, 0x1b, + 0x54, 0x14, 0xf5, 0x28, 0x54, 0x51, 0xda, 0x58, 0x1e, 0xf6, 0xa0, 0x82, 0x04, 0xc6, 0x30, 0x82, 0x04, 0xc2, 0x30, 0x82, 0x04, 0xbe, 0x30, 0x82, 0x03, 0xa6, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x04, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, @@ -812,37 +864,37 @@ unsigned char resp_intermediate1_cert[] = { 0x72, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6e, 0x66, 0x6f, 0x40, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x18, 0x0f, - 0x32, 0x30, 0x32, 0x36, 0x30, 0x32, 0x32, 0x34, 0x32, 0x31, 0x34, 0x32, - 0x30, 0x31, 0x5a, 0x30, 0x4f, 0x30, 0x4d, 0x30, 0x38, 0x30, 0x07, 0x06, + 0x32, 0x30, 0x32, 0x36, 0x30, 0x35, 0x32, 0x31, 0x31, 0x37, 0x32, 0x34, + 0x33, 0x30, 0x5a, 0x30, 0x4f, 0x30, 0x4d, 0x30, 0x38, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x04, 0x14, 0x44, 0xa8, 0xdb, 0xd1, 0xbc, 0x97, 0x0a, 0x83, 0x3b, 0x5b, 0x31, 0x9a, 0x4c, 0xb8, 0xd2, 0x52, 0x37, 0x15, 0x8a, 0x88, 0x04, 0x14, 0x73, 0xb0, 0x1c, 0xa4, 0x2f, 0x82, 0xcb, 0xcf, 0x47, 0xa5, 0x38, 0xd7, 0xb0, 0x04, 0x82, 0x3a, 0x7e, 0x72, 0x15, 0x21, 0x02, 0x01, 0x01, 0x80, 0x00, 0x18, 0x0f, 0x32, 0x30, 0x32, - 0x36, 0x30, 0x32, 0x32, 0x34, 0x32, 0x31, 0x34, 0x32, 0x30, 0x31, 0x5a, + 0x36, 0x30, 0x35, 0x32, 0x31, 0x31, 0x37, 0x32, 0x34, 0x33, 0x30, 0x5a, 0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, - 0x0b, 0x03, 0x82, 0x01, 0x01, 0x00, 0x7a, 0xc5, 0x6d, 0xfa, 0x8b, 0x75, - 0x9a, 0x46, 0x91, 0x3b, 0x23, 0xc2, 0xa0, 0x0d, 0x60, 0x0e, 0x61, 0x54, - 0x7c, 0xd7, 0xcb, 0x6c, 0x14, 0x9b, 0x11, 0x96, 0xe2, 0x83, 0xfa, 0x0f, - 0x70, 0xc9, 0xc9, 0x07, 0xa8, 0x53, 0x69, 0x90, 0xbb, 0xd5, 0x31, 0xb4, - 0x6f, 0xfc, 0x6b, 0x6b, 0xd9, 0x1a, 0xe5, 0xbc, 0xc8, 0x25, 0x93, 0x0b, - 0x9e, 0x9d, 0xb3, 0x9b, 0x07, 0x38, 0x79, 0x4c, 0xd0, 0xa1, 0xd1, 0x3f, - 0xf6, 0x8a, 0xf0, 0x77, 0xa4, 0xea, 0x8d, 0x23, 0xf4, 0xb0, 0xdf, 0x59, - 0x41, 0x5c, 0x77, 0x0e, 0xc2, 0x1c, 0xab, 0xbb, 0xb6, 0x12, 0x2e, 0x37, - 0x1f, 0xf7, 0x57, 0xa0, 0x02, 0x02, 0xed, 0x8c, 0xb7, 0x4d, 0xdd, 0xd0, - 0x02, 0xb6, 0x5f, 0xff, 0xa3, 0x0a, 0x28, 0x4b, 0x8f, 0x4e, 0x6d, 0x57, - 0x55, 0xd0, 0x4f, 0x3f, 0x4c, 0x45, 0x5b, 0x6f, 0x8c, 0x8e, 0xe4, 0xd9, - 0x62, 0xe8, 0x4c, 0x72, 0xd8, 0x0b, 0x5c, 0xce, 0xc9, 0x53, 0x76, 0x0e, - 0xb1, 0xaf, 0xf8, 0x15, 0xb2, 0x50, 0xd5, 0x69, 0x6f, 0xbe, 0xee, 0x17, - 0x06, 0x43, 0xc6, 0x6d, 0x9a, 0x12, 0x3d, 0x57, 0x14, 0xb3, 0x39, 0xc8, - 0x58, 0x76, 0x46, 0x57, 0xe3, 0xb4, 0x4a, 0x82, 0x8e, 0xf3, 0xdc, 0x99, - 0x0a, 0x34, 0x6e, 0x65, 0x3c, 0xef, 0xe4, 0x42, 0x85, 0x6c, 0xc5, 0xaf, - 0x76, 0xdb, 0x75, 0x2d, 0xd5, 0xb2, 0x69, 0x08, 0xec, 0xa3, 0x1d, 0x8e, - 0xdc, 0x7c, 0xbf, 0xb7, 0xa9, 0x6c, 0x9f, 0x7f, 0x9e, 0xb8, 0x9e, 0x1d, - 0x20, 0x64, 0xcf, 0x30, 0xf2, 0x2d, 0xa7, 0x80, 0x77, 0x53, 0xf9, 0x15, - 0xf1, 0xef, 0xb2, 0xa4, 0x30, 0x02, 0x94, 0xfe, 0x43, 0xad, 0xa0, 0x7c, - 0x67, 0x47, 0xe2, 0x42, 0x4a, 0x2d, 0x02, 0x9e, 0x6a, 0xb6, 0xa1, 0x57, - 0x3e, 0x9a, 0x47, 0xe2, 0xb1, 0xb7, 0xd2, 0x0f, 0x32, 0x8f, 0xa0, 0x82, + 0x0b, 0x03, 0x82, 0x01, 0x01, 0x00, 0x85, 0x29, 0xfc, 0x9a, 0x83, 0x8a, + 0xae, 0x8d, 0xcd, 0xb3, 0x3c, 0x6d, 0xa5, 0xd5, 0x6b, 0x62, 0x51, 0x58, + 0xdd, 0x16, 0xb4, 0x80, 0xe0, 0xf8, 0x78, 0xf6, 0xca, 0xa4, 0xfa, 0x7d, + 0x4a, 0xe6, 0x8a, 0xf7, 0xa8, 0x5f, 0x01, 0xe1, 0x9a, 0xfd, 0xc0, 0x3a, + 0xc5, 0x21, 0x68, 0x82, 0x3f, 0x82, 0xf1, 0x41, 0xab, 0xd6, 0xb1, 0x78, + 0x72, 0x70, 0xdf, 0xa7, 0xb4, 0xc7, 0xc6, 0xab, 0x0d, 0xc8, 0xd5, 0x54, + 0xae, 0xb9, 0x96, 0xad, 0xa1, 0xc7, 0x55, 0x65, 0xd9, 0x86, 0x8b, 0xe1, + 0x01, 0x4a, 0xb3, 0xbd, 0x4c, 0xc8, 0xd2, 0xc7, 0x15, 0xbd, 0xd3, 0x3f, + 0x5c, 0xe2, 0xf1, 0x59, 0xfc, 0x51, 0x04, 0x6f, 0xb1, 0x94, 0x66, 0xb9, + 0xc9, 0xa2, 0xbc, 0x5d, 0x25, 0x9a, 0x4c, 0x48, 0xe0, 0x1b, 0xb6, 0xd2, + 0x80, 0xb5, 0x05, 0x93, 0x3d, 0x6d, 0x28, 0x3f, 0xc5, 0x4e, 0x59, 0x1d, + 0x85, 0x1e, 0x37, 0xd3, 0x3d, 0x9c, 0xd6, 0x1c, 0xcb, 0xf9, 0x0f, 0x40, + 0x3b, 0x4d, 0xb3, 0xc1, 0xb6, 0x9d, 0x66, 0xbb, 0xe9, 0x15, 0x4c, 0xf7, + 0xac, 0x96, 0xfd, 0x32, 0xa6, 0xa7, 0xee, 0x06, 0xb5, 0x08, 0x1c, 0x0c, + 0x71, 0xdc, 0x48, 0x58, 0x41, 0x69, 0xb1, 0xd2, 0xad, 0xd5, 0x9a, 0x0d, + 0x66, 0xba, 0x82, 0x2a, 0x41, 0xcd, 0x86, 0xda, 0x72, 0x09, 0x4d, 0xa2, + 0xc5, 0xb2, 0x43, 0x0f, 0x4c, 0x08, 0x6e, 0x87, 0x00, 0x6f, 0x9d, 0xb7, + 0x10, 0x0a, 0x1f, 0x53, 0x14, 0x64, 0xaf, 0x97, 0xf2, 0x60, 0x12, 0xe5, + 0xe0, 0xd6, 0x11, 0x83, 0x44, 0x97, 0xa7, 0x3f, 0x63, 0xde, 0xc0, 0x27, + 0xd1, 0x48, 0xbe, 0x9f, 0xc3, 0x13, 0xf6, 0x18, 0xd4, 0x22, 0x34, 0x4b, + 0x02, 0x3f, 0x1b, 0xae, 0x33, 0xab, 0xc2, 0x26, 0xef, 0xfe, 0xdb, 0x27, + 0xf5, 0xc5, 0x11, 0xac, 0x25, 0x66, 0xe1, 0x62, 0x8c, 0x41, 0xa0, 0x82, 0x04, 0xc6, 0x30, 0x82, 0x04, 0xc2, 0x30, 0x82, 0x04, 0xbe, 0x30, 0x82, 0x03, 0xa6, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x04, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, @@ -965,37 +1017,37 @@ unsigned char resp_root_ca_cert[] = { 0x72, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6e, 0x66, 0x6f, 0x40, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x18, 0x0f, - 0x32, 0x30, 0x32, 0x36, 0x30, 0x32, 0x32, 0x34, 0x32, 0x31, 0x34, 0x32, - 0x30, 0x31, 0x5a, 0x30, 0x4f, 0x30, 0x4d, 0x30, 0x38, 0x30, 0x07, 0x06, + 0x32, 0x30, 0x32, 0x36, 0x30, 0x35, 0x32, 0x31, 0x31, 0x37, 0x32, 0x34, + 0x33, 0x30, 0x5a, 0x30, 0x4f, 0x30, 0x4d, 0x30, 0x38, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x04, 0x14, 0x44, 0xa8, 0xdb, 0xd1, 0xbc, 0x97, 0x0a, 0x83, 0x3b, 0x5b, 0x31, 0x9a, 0x4c, 0xb8, 0xd2, 0x52, 0x37, 0x15, 0x8a, 0x88, 0x04, 0x14, 0x73, 0xb0, 0x1c, 0xa4, 0x2f, 0x82, 0xcb, 0xcf, 0x47, 0xa5, 0x38, 0xd7, 0xb0, 0x04, 0x82, 0x3a, 0x7e, 0x72, 0x15, 0x21, 0x02, 0x01, 0x63, 0x80, 0x00, 0x18, 0x0f, 0x32, 0x30, 0x32, - 0x36, 0x30, 0x32, 0x32, 0x34, 0x32, 0x31, 0x34, 0x32, 0x30, 0x31, 0x5a, + 0x36, 0x30, 0x35, 0x32, 0x31, 0x31, 0x37, 0x32, 0x34, 0x33, 0x30, 0x5a, 0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, - 0x0b, 0x03, 0x82, 0x01, 0x01, 0x00, 0x5b, 0x3e, 0x7d, 0xdc, 0x1b, 0x84, - 0xba, 0x74, 0xae, 0x09, 0x6d, 0xa3, 0xe2, 0x9e, 0x2f, 0x59, 0x10, 0x4c, - 0x8b, 0x65, 0x09, 0xa1, 0x49, 0x89, 0xa2, 0x02, 0x01, 0xd3, 0x94, 0x25, - 0xa6, 0xe4, 0x5a, 0x9a, 0x6b, 0xda, 0xbe, 0x55, 0xf5, 0x5c, 0x18, 0x4f, - 0x8e, 0xda, 0x0e, 0xfe, 0x16, 0x22, 0xc7, 0x08, 0xaa, 0x6b, 0x18, 0x96, - 0x94, 0xaa, 0x64, 0xe4, 0x0e, 0xc4, 0x5d, 0x73, 0x34, 0x6a, 0x29, 0xb0, - 0xe0, 0x4d, 0xc6, 0x9d, 0x7f, 0xea, 0x4c, 0x18, 0x32, 0xff, 0x64, 0x67, - 0x89, 0xbe, 0xbf, 0xe0, 0xf4, 0x0a, 0xe7, 0x03, 0x39, 0x1a, 0xb3, 0x2b, - 0x52, 0xd9, 0xd7, 0x48, 0x7a, 0x18, 0x0f, 0x92, 0x8e, 0xa8, 0xe3, 0x44, - 0x6a, 0x67, 0x65, 0x7c, 0xbe, 0x3f, 0xf9, 0xa0, 0x80, 0x58, 0x29, 0x40, - 0xa7, 0x56, 0xb8, 0x7e, 0x87, 0x78, 0x14, 0x5e, 0xd3, 0xb6, 0x2d, 0x1a, - 0xf0, 0x49, 0xe1, 0xd2, 0xb4, 0x79, 0xfe, 0xab, 0xaf, 0xb8, 0x04, 0x57, - 0xbb, 0x75, 0x4f, 0xe9, 0x55, 0xd2, 0x23, 0xb0, 0xb9, 0xf3, 0x02, 0x67, - 0xd8, 0x94, 0x66, 0x76, 0xd9, 0x5e, 0x3f, 0x77, 0x9b, 0x87, 0x7e, 0x43, - 0xa5, 0xef, 0x35, 0x06, 0xaa, 0xaf, 0x0f, 0x20, 0x2f, 0x09, 0x4f, 0xba, - 0x0b, 0xcd, 0x4f, 0x9a, 0xf4, 0x11, 0x83, 0x02, 0x34, 0x16, 0x25, 0x20, - 0x25, 0x00, 0xb0, 0x91, 0x42, 0x29, 0x5c, 0xd4, 0xb8, 0xf0, 0x28, 0x22, - 0x59, 0x7e, 0xf3, 0xc9, 0xb2, 0x74, 0x0a, 0xf1, 0xd7, 0x84, 0xb9, 0x0e, - 0x1b, 0xb5, 0xde, 0xa3, 0x0c, 0x25, 0xac, 0xd3, 0xef, 0xf2, 0x22, 0x49, - 0x8d, 0xec, 0x49, 0xa1, 0x25, 0xad, 0xd0, 0xa4, 0x93, 0x68, 0x6a, 0x95, - 0x7c, 0x6c, 0x4f, 0x43, 0x2a, 0x19, 0xbf, 0x55, 0x77, 0xe3, 0xdb, 0x77, - 0xc5, 0x85, 0x38, 0x2d, 0x07, 0x4a, 0x54, 0x45, 0x9e, 0xde, 0xa0, 0x82, + 0x0b, 0x03, 0x82, 0x01, 0x01, 0x00, 0x52, 0x9e, 0x80, 0xa7, 0x80, 0xe6, + 0x16, 0x7f, 0xed, 0x1d, 0xb0, 0xe1, 0x03, 0x77, 0x64, 0xe8, 0x78, 0xe1, + 0x7f, 0xfe, 0x3b, 0xb4, 0xcd, 0x75, 0xc6, 0xea, 0xa8, 0x95, 0x36, 0x02, + 0x33, 0x17, 0x78, 0x52, 0x61, 0xf5, 0x35, 0x80, 0x7e, 0xf5, 0x51, 0xe5, + 0xd8, 0xf8, 0x29, 0xf2, 0x47, 0x74, 0xa4, 0xeb, 0x84, 0x7b, 0x59, 0xdc, + 0xf9, 0x24, 0x33, 0x0b, 0x83, 0xb0, 0xb1, 0x92, 0x9b, 0xc6, 0x20, 0x82, + 0xa7, 0x9c, 0x82, 0x7b, 0x3b, 0x93, 0x97, 0x28, 0x7f, 0xe2, 0x5a, 0x1b, + 0x9f, 0xf0, 0xad, 0x72, 0xd4, 0x3b, 0xaf, 0xb3, 0x9c, 0xbf, 0x82, 0x4d, + 0x90, 0xae, 0x93, 0x28, 0x1b, 0x90, 0xf4, 0x1f, 0x61, 0x83, 0x49, 0x01, + 0x3b, 0x83, 0xc7, 0x14, 0x49, 0xf9, 0xa2, 0x07, 0x65, 0xd3, 0x66, 0x33, + 0x7c, 0x37, 0x0c, 0x91, 0x9c, 0xc2, 0xc7, 0xfc, 0xac, 0xf4, 0x56, 0x64, + 0x6e, 0xae, 0x5e, 0x83, 0x21, 0xdd, 0x99, 0x8b, 0xd4, 0x5d, 0x69, 0x4e, + 0xe1, 0x6e, 0x44, 0x31, 0xd1, 0x1f, 0x8a, 0x8c, 0x7d, 0xbd, 0x94, 0x8d, + 0x2c, 0x39, 0x6e, 0xe8, 0x10, 0xea, 0xc9, 0xee, 0x72, 0xc7, 0x31, 0x90, + 0xf2, 0x5d, 0xcf, 0xd5, 0xd4, 0xa4, 0x9d, 0x2f, 0xe3, 0x5c, 0x00, 0x8b, + 0x46, 0x02, 0x71, 0x18, 0xeb, 0xec, 0x20, 0x11, 0x30, 0xc2, 0xba, 0xd2, + 0xb3, 0x22, 0x25, 0xe1, 0x9e, 0xfe, 0xd1, 0x3b, 0x90, 0x24, 0x4f, 0x69, + 0x5c, 0x83, 0xa7, 0x10, 0x19, 0xe3, 0x83, 0x73, 0xf0, 0xf2, 0xec, 0xbf, + 0xe5, 0x66, 0x44, 0x7f, 0x2d, 0xa5, 0x63, 0xb9, 0xc2, 0xfd, 0x5b, 0x43, + 0x09, 0x79, 0x83, 0xec, 0x3c, 0x0a, 0x61, 0x61, 0xf6, 0x32, 0xb6, 0x48, + 0xbe, 0x4d, 0x97, 0x6e, 0x1e, 0x73, 0x64, 0x47, 0x28, 0x14, 0x50, 0x10, + 0x1e, 0x83, 0xff, 0x57, 0x94, 0x97, 0x31, 0x5c, 0x2e, 0xf5, 0xa0, 0x82, 0x04, 0xc6, 0x30, 0x82, 0x04, 0xc2, 0x30, 0x82, 0x04, 0xbe, 0x30, 0x82, 0x03, 0xa6, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x04, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, @@ -1117,38 +1169,38 @@ unsigned char resp_cert_unknown[] = { 0x6f, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6e, 0x66, 0x6f, 0x40, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73, 0x6c, 0x2e, 0x63, - 0x6f, 0x6d, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x36, 0x30, 0x32, 0x32, 0x34, - 0x32, 0x31, 0x34, 0x32, 0x30, 0x31, 0x5a, 0x30, 0x4f, 0x30, 0x4d, 0x30, + 0x6f, 0x6d, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x36, 0x30, 0x35, 0x32, 0x31, + 0x31, 0x37, 0x32, 0x34, 0x33, 0x31, 0x5a, 0x30, 0x4f, 0x30, 0x4d, 0x30, 0x38, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x04, 0x14, 0x44, 0xa8, 0xdb, 0xd1, 0xbc, 0x97, 0x0a, 0x83, 0x3b, 0x5b, 0x31, 0x9a, 0x4c, 0xb8, 0xd2, 0x52, 0x37, 0x15, 0x8a, 0x88, 0x04, 0x14, 0x73, 0xb0, 0x1c, 0xa4, 0x2f, 0x82, 0xcb, 0xcf, 0x47, 0xa5, 0x38, 0xd7, 0xb0, 0x04, 0x82, 0x3a, 0x7e, 0x72, 0x15, 0x21, 0x02, 0x01, 0x01, 0x82, 0x00, 0x18, - 0x0f, 0x32, 0x30, 0x32, 0x36, 0x30, 0x32, 0x32, 0x34, 0x32, 0x31, 0x34, - 0x32, 0x30, 0x31, 0x5a, 0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, - 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x03, 0x82, 0x01, 0x01, 0x00, 0xa6, 0x3c, - 0x6c, 0x8b, 0x2d, 0x50, 0xc4, 0x7f, 0xad, 0x19, 0x9f, 0x59, 0x6d, 0x18, - 0x5c, 0x5c, 0x49, 0x94, 0x20, 0x4b, 0x9d, 0x8d, 0x5a, 0x91, 0x09, 0x0b, - 0x8b, 0xdf, 0x4b, 0x99, 0xc5, 0xba, 0x62, 0xd1, 0x66, 0x25, 0x86, 0x03, - 0xb6, 0xde, 0x92, 0xb4, 0xab, 0x5d, 0x8d, 0x25, 0xdb, 0x32, 0xe8, 0x8d, - 0xe3, 0xd2, 0x07, 0x78, 0xae, 0x05, 0x66, 0xa2, 0x68, 0xa3, 0x3c, 0x13, - 0x78, 0xe2, 0xb2, 0x64, 0x3d, 0xff, 0x44, 0x27, 0x47, 0x42, 0xb6, 0xb5, - 0xea, 0xa6, 0xfc, 0x84, 0x2f, 0x5d, 0xf1, 0x3a, 0xa6, 0x16, 0xea, 0x4d, - 0x46, 0x3a, 0x5a, 0x89, 0x1a, 0x8d, 0x35, 0xd1, 0xe7, 0xb5, 0x31, 0xc5, - 0x64, 0xbe, 0xcd, 0xb0, 0x92, 0xa5, 0xe0, 0xec, 0x82, 0x1f, 0x2c, 0xbb, - 0x57, 0xa2, 0x77, 0x82, 0xf4, 0x08, 0x54, 0xff, 0xee, 0x77, 0xfb, 0xb6, - 0x5f, 0xc2, 0x3c, 0x84, 0x12, 0x60, 0x8e, 0xd8, 0x19, 0xc4, 0x82, 0xec, - 0x4c, 0x5f, 0x95, 0x0c, 0x93, 0xd4, 0xb4, 0x42, 0x0f, 0x67, 0xaf, 0xbb, - 0xaa, 0x26, 0x10, 0x82, 0x9a, 0xdb, 0xcf, 0x3e, 0x33, 0xe5, 0xe6, 0xd0, - 0x26, 0x84, 0xf5, 0x00, 0xc0, 0xe6, 0x9f, 0x62, 0x56, 0xdb, 0xd7, 0x8b, - 0x07, 0xf4, 0xeb, 0x08, 0x4d, 0xe9, 0xd5, 0x74, 0x04, 0xf4, 0x9f, 0xe2, - 0xde, 0x32, 0xc4, 0x60, 0x9f, 0x18, 0x5b, 0x67, 0x72, 0xab, 0x2a, 0x52, - 0x8c, 0x12, 0x5c, 0x4b, 0x6e, 0xda, 0xd9, 0x82, 0xfc, 0xfb, 0x19, 0xfc, - 0x97, 0x58, 0x2e, 0x12, 0x1c, 0x9e, 0x8c, 0x18, 0x57, 0xe9, 0xcb, 0xc8, - 0x6d, 0xea, 0x6b, 0x8c, 0xfc, 0x02, 0x5f, 0x00, 0xc2, 0x2f, 0x10, 0x2d, - 0xcc, 0xce, 0x9b, 0xc5, 0x4d, 0xf5, 0xdd, 0xca, 0xeb, 0x82, 0x4b, 0xfa, - 0x9d, 0x7b, 0x67, 0xe5, 0x98, 0x67, 0xa7, 0x2e, 0xac, 0xc8, 0x5c, 0xb2, - 0x1e, 0x10, 0xa0, 0x82, 0x04, 0xee, 0x30, 0x82, 0x04, 0xea, 0x30, 0x82, + 0x0f, 0x32, 0x30, 0x32, 0x36, 0x30, 0x35, 0x32, 0x31, 0x31, 0x37, 0x32, + 0x34, 0x33, 0x31, 0x5a, 0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x03, 0x82, 0x01, 0x01, 0x00, 0x09, 0x68, + 0xc0, 0xe0, 0x8c, 0xa1, 0x67, 0x19, 0x7e, 0xcb, 0x06, 0x9b, 0x5f, 0xe2, + 0xe4, 0xbd, 0x30, 0x72, 0x66, 0xa8, 0xc0, 0xe8, 0xfb, 0xb8, 0x81, 0xce, + 0xa0, 0xde, 0x49, 0x6d, 0xcb, 0x73, 0xd1, 0x3a, 0xa0, 0xbb, 0x49, 0xe5, + 0x93, 0xcb, 0x0e, 0x29, 0xe0, 0x8c, 0xe8, 0x52, 0x50, 0x0c, 0x7e, 0xc6, + 0x51, 0x98, 0x43, 0x03, 0x14, 0x7e, 0xf9, 0xd3, 0xa9, 0x0b, 0x0a, 0x78, + 0x34, 0xfd, 0x07, 0xfd, 0x76, 0x18, 0x44, 0x49, 0x61, 0xe4, 0x06, 0xc0, + 0x34, 0x29, 0x21, 0xb0, 0xdd, 0x0a, 0x76, 0x0b, 0x62, 0x21, 0xfd, 0x7a, + 0x71, 0x08, 0xf1, 0x8d, 0x38, 0xea, 0x54, 0x81, 0x38, 0x9d, 0x53, 0xef, + 0x01, 0xcb, 0x66, 0x15, 0xb3, 0x7b, 0x5c, 0x9d, 0x11, 0x6e, 0xfa, 0xa3, + 0x40, 0x85, 0x49, 0x3d, 0x66, 0x7e, 0xad, 0x28, 0xd6, 0xad, 0x18, 0xef, + 0xa8, 0xdc, 0xa2, 0xb3, 0x44, 0xbc, 0xd8, 0xd3, 0x43, 0xcd, 0x61, 0x1e, + 0x09, 0x7d, 0x1f, 0x2d, 0x52, 0x53, 0x33, 0x52, 0xb6, 0x38, 0x3f, 0x41, + 0xc7, 0xe5, 0x50, 0x5e, 0x69, 0xc8, 0xe5, 0x9b, 0x95, 0x21, 0x52, 0xc0, + 0xba, 0xc3, 0xa4, 0x60, 0x23, 0x93, 0xd6, 0x92, 0x49, 0x16, 0x14, 0x46, + 0x7c, 0x15, 0x39, 0x6e, 0xb4, 0xe5, 0xc3, 0x21, 0xa1, 0x89, 0x25, 0xaf, + 0x12, 0xca, 0x24, 0xb1, 0x76, 0x4b, 0x36, 0x36, 0xd7, 0xcf, 0xb8, 0xb7, + 0xe2, 0xcb, 0xaa, 0x61, 0xdd, 0xab, 0x54, 0x38, 0x87, 0xab, 0x9b, 0x7d, + 0xee, 0xd6, 0x30, 0xfd, 0x67, 0x24, 0x8e, 0x49, 0x8d, 0xdc, 0x12, 0xf4, + 0x4e, 0xca, 0xb9, 0xe8, 0xd0, 0x48, 0x2e, 0x69, 0x89, 0x28, 0x8b, 0x92, + 0xd0, 0xca, 0x9d, 0xcc, 0x9a, 0x19, 0x0a, 0xb0, 0x16, 0x7b, 0x58, 0x06, + 0x60, 0xd4, 0xc9, 0x15, 0xd1, 0x3b, 0xae, 0xb0, 0x6b, 0x1b, 0x0b, 0x99, + 0xd2, 0x38, 0xa0, 0x82, 0x04, 0xee, 0x30, 0x82, 0x04, 0xea, 0x30, 0x82, 0x04, 0xe6, 0x30, 0x82, 0x03, 0xce, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x63, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0x97, 0x31, 0x0b, 0x30, 0x09, @@ -1273,37 +1325,37 @@ unsigned char resp_server_cert_unknown[] = { 0x6f, 0x6d, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6e, 0x66, 0x6f, 0x40, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x18, - 0x0f, 0x32, 0x30, 0x32, 0x36, 0x30, 0x32, 0x32, 0x34, 0x32, 0x31, 0x34, - 0x32, 0x30, 0x31, 0x5a, 0x30, 0x4f, 0x30, 0x4d, 0x30, 0x38, 0x30, 0x07, + 0x0f, 0x32, 0x30, 0x32, 0x36, 0x30, 0x35, 0x32, 0x31, 0x31, 0x37, 0x32, + 0x34, 0x33, 0x31, 0x5a, 0x30, 0x4f, 0x30, 0x4d, 0x30, 0x38, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x04, 0x14, 0xff, 0x66, 0x21, 0x8a, 0x6e, 0xc5, 0x86, 0x61, 0x84, 0x25, 0x9a, 0xba, 0xd6, 0x55, 0x39, 0xfb, 0x25, 0x51, 0x2c, 0xdd, 0x04, 0x14, 0x27, 0x8e, 0x67, 0x11, 0x74, 0xc3, 0x26, 0x1d, 0x3f, 0xed, 0x33, 0x63, 0xb3, 0xa4, 0xd8, 0x1d, 0x30, 0xe5, 0xe8, 0xd5, 0x02, 0x01, 0x01, 0x82, 0x00, 0x18, 0x0f, 0x32, 0x30, - 0x32, 0x36, 0x30, 0x32, 0x32, 0x34, 0x32, 0x31, 0x34, 0x32, 0x30, 0x31, + 0x32, 0x36, 0x30, 0x35, 0x32, 0x31, 0x31, 0x37, 0x32, 0x34, 0x33, 0x31, 0x5a, 0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, - 0x01, 0x0b, 0x03, 0x82, 0x01, 0x01, 0x00, 0x05, 0x2a, 0x8b, 0x72, 0x45, - 0xf4, 0xd9, 0xc0, 0xd4, 0xb3, 0x3d, 0xe0, 0xe3, 0x81, 0x1d, 0x7a, 0xaa, - 0xc4, 0xe7, 0x2b, 0xe5, 0x31, 0x50, 0x1c, 0x32, 0x7c, 0xe5, 0x15, 0x6a, - 0xdd, 0xe5, 0x8b, 0xb0, 0x61, 0x16, 0x8e, 0xf9, 0x3d, 0x97, 0xc6, 0x71, - 0x05, 0x80, 0x96, 0x64, 0x7f, 0x1f, 0x38, 0x5b, 0x12, 0xba, 0x7e, 0x0c, - 0x1b, 0xe7, 0xaf, 0x51, 0x6c, 0x02, 0xbe, 0xc6, 0xe1, 0xcf, 0xf7, 0x41, - 0xb0, 0x03, 0x89, 0x3d, 0xfd, 0xef, 0x87, 0x0f, 0xda, 0x48, 0xe2, 0x7a, - 0xc8, 0x75, 0x65, 0x38, 0xd6, 0x64, 0xab, 0x86, 0x24, 0x22, 0x20, 0x7f, - 0x8b, 0x36, 0x8c, 0x77, 0x3f, 0x2b, 0x08, 0x53, 0x17, 0x6b, 0xd4, 0x86, - 0x66, 0x42, 0x3e, 0x9d, 0x13, 0x73, 0x3c, 0x9e, 0x1e, 0xe0, 0xf3, 0xf1, - 0x0e, 0x88, 0xfd, 0xb8, 0xc3, 0xe3, 0x4e, 0xf8, 0x35, 0x8b, 0xe5, 0x11, - 0xd3, 0xf1, 0x2e, 0xf8, 0x68, 0x35, 0xd0, 0x73, 0x38, 0xef, 0xf1, 0x4e, - 0x24, 0xb4, 0xc0, 0x84, 0x00, 0xce, 0x7e, 0x9c, 0xe2, 0x67, 0x15, 0x44, - 0x8f, 0x72, 0x25, 0x1c, 0x0a, 0x4d, 0xbc, 0x61, 0xf9, 0x46, 0x0d, 0xb4, - 0x08, 0x0a, 0x21, 0xfd, 0xd5, 0x99, 0x67, 0xe1, 0x72, 0x9f, 0x99, 0x6c, - 0x09, 0xdb, 0xd8, 0xd3, 0xf2, 0x84, 0x7e, 0xb8, 0x84, 0xcf, 0xa5, 0xf6, - 0xfe, 0xc3, 0xa2, 0x86, 0xc5, 0x08, 0xf5, 0xb7, 0xc8, 0x51, 0x25, 0x0b, - 0x7c, 0xce, 0xa4, 0xcd, 0x2f, 0xd7, 0xec, 0x78, 0x1c, 0xce, 0x4b, 0x5b, - 0x95, 0xc3, 0x88, 0xd3, 0xd9, 0x6e, 0xad, 0x9b, 0x02, 0xe8, 0x4e, 0xa5, - 0x1d, 0xc5, 0x4e, 0x44, 0xf5, 0xb2, 0x96, 0xea, 0x18, 0xb7, 0xf1, 0xfd, - 0x7f, 0x01, 0x02, 0x81, 0xf1, 0x11, 0xcf, 0xdc, 0x43, 0x9f, 0x54, 0x1a, - 0x6e, 0x57, 0x1f, 0xc1, 0xb1, 0xe2, 0x1d, 0xbf, 0x11, 0xa2, 0x09, 0xa0, + 0x01, 0x0b, 0x03, 0x82, 0x01, 0x01, 0x00, 0xa7, 0xa0, 0xfb, 0x46, 0x01, + 0xa1, 0x58, 0x83, 0x51, 0x3b, 0x56, 0x6a, 0x8e, 0xd6, 0x9d, 0x31, 0x84, + 0x86, 0xdd, 0x39, 0x26, 0x36, 0x2f, 0xbb, 0xf1, 0xd9, 0x76, 0xab, 0x7d, + 0x56, 0x21, 0x4c, 0x19, 0x31, 0xe9, 0x05, 0xbc, 0x71, 0x9d, 0xe1, 0x26, + 0x32, 0xbb, 0xc6, 0xb4, 0xeb, 0x27, 0xcf, 0xfd, 0x73, 0xf3, 0x7b, 0x5e, + 0xef, 0x54, 0x76, 0x0f, 0xaf, 0x22, 0x9a, 0xf3, 0xce, 0x05, 0x5d, 0x2d, + 0xba, 0xe4, 0x6d, 0x12, 0x94, 0x93, 0x41, 0x3e, 0x8e, 0x7f, 0x81, 0xdc, + 0x33, 0x65, 0x56, 0xdb, 0xd2, 0xec, 0xa2, 0x6d, 0x1c, 0xd9, 0x43, 0x23, + 0xd6, 0x1d, 0x5f, 0x72, 0x40, 0xd3, 0x69, 0xae, 0x3e, 0x3e, 0x98, 0x16, + 0x2b, 0x5d, 0x73, 0xb9, 0x22, 0xbe, 0x1f, 0x08, 0xcf, 0xca, 0x63, 0xff, + 0xcd, 0x52, 0x06, 0xd1, 0x42, 0xfd, 0x73, 0x4b, 0x17, 0xe1, 0x33, 0x70, + 0x8f, 0x62, 0xd7, 0xf8, 0xdf, 0x1e, 0x72, 0x6d, 0x11, 0x57, 0x92, 0xa9, + 0xd0, 0x28, 0x0f, 0x78, 0xca, 0x0a, 0x2b, 0x19, 0xa3, 0xf2, 0xbe, 0xcc, + 0x4a, 0xcd, 0xde, 0xbf, 0xcb, 0x2a, 0x8d, 0xf5, 0xd4, 0x76, 0x8e, 0x2a, + 0x00, 0xda, 0x96, 0x69, 0x22, 0x7c, 0x45, 0xb2, 0x0d, 0x50, 0xf6, 0xbc, + 0xb6, 0xf3, 0x73, 0x61, 0x8d, 0x2f, 0x71, 0x8f, 0x94, 0x80, 0x68, 0x9e, + 0x8e, 0xc5, 0xf2, 0xe5, 0xa4, 0xc5, 0xf4, 0xe6, 0xd4, 0x10, 0xc8, 0xc9, + 0xca, 0x68, 0xed, 0xb0, 0x4b, 0x53, 0x90, 0x7a, 0x07, 0xbd, 0x65, 0xb7, + 0xa4, 0x5b, 0x96, 0x53, 0x46, 0xe2, 0xcf, 0x8e, 0xcd, 0x2f, 0xd0, 0x6c, + 0xd6, 0x1c, 0x73, 0x57, 0x28, 0xcb, 0xb9, 0x48, 0x3a, 0xb1, 0x7f, 0xb5, + 0x6c, 0x93, 0x7c, 0x50, 0xf0, 0x15, 0xf5, 0xd3, 0x40, 0x01, 0x91, 0x26, + 0x77, 0x3a, 0x14, 0x83, 0x9c, 0x95, 0x4b, 0xda, 0xcd, 0xf8, 0xdf, 0xa0, 0x82, 0x05, 0x07, 0x30, 0x82, 0x05, 0x03, 0x30, 0x82, 0x04, 0xff, 0x30, 0x82, 0x03, 0xe7, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x14, 0x3f, 0x29, 0x11, 0x20, 0x57, 0x71, 0xe7, 0x8e, 0xf9, 0x18, 0x0d, 0xca, 0x70, 0x4d, @@ -1432,37 +1484,37 @@ unsigned char resp_certid_keyhash_mismatch[] = { 0x72, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6e, 0x66, 0x6f, 0x40, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x18, 0x0f, - 0x32, 0x30, 0x32, 0x36, 0x30, 0x34, 0x32, 0x36, 0x31, 0x38, 0x32, 0x36, - 0x33, 0x32, 0x5a, 0x30, 0x4f, 0x30, 0x4d, 0x30, 0x38, 0x30, 0x07, 0x06, + 0x32, 0x30, 0x32, 0x36, 0x30, 0x35, 0x32, 0x31, 0x31, 0x37, 0x32, 0x34, + 0x33, 0x31, 0x5a, 0x30, 0x4f, 0x30, 0x4d, 0x30, 0x38, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x04, 0x14, 0x44, 0xa8, 0xdb, 0xd1, 0xbc, 0x97, 0x0a, 0x83, 0x3b, 0x5b, 0x31, 0x9a, 0x4c, 0xb8, 0xd2, 0x52, 0x37, 0x15, 0x8a, 0x88, 0x04, 0x14, 0x73, 0x64, 0x66, 0x3e, 0x9a, 0xde, 0x12, 0xec, 0x44, 0xc2, 0x5b, 0x05, 0x64, 0x62, 0x1d, 0x63, 0x23, 0x43, 0x55, 0xe5, 0x02, 0x01, 0x01, 0x80, 0x00, 0x18, 0x0f, 0x32, 0x30, 0x32, - 0x36, 0x30, 0x34, 0x32, 0x36, 0x31, 0x38, 0x32, 0x36, 0x33, 0x32, 0x5a, + 0x36, 0x30, 0x35, 0x32, 0x31, 0x31, 0x37, 0x32, 0x34, 0x33, 0x31, 0x5a, 0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, - 0x0b, 0x03, 0x82, 0x01, 0x01, 0x00, 0x45, 0x7f, 0xe9, 0x4a, 0x3b, 0x66, - 0x29, 0x88, 0xfb, 0x2a, 0xce, 0x7a, 0xd4, 0xcf, 0xe0, 0x98, 0xec, 0xd4, - 0x52, 0xb4, 0x98, 0x95, 0xd1, 0x0a, 0x60, 0x37, 0xae, 0x48, 0x9d, 0xc9, - 0x93, 0x49, 0xb1, 0x39, 0x2e, 0x03, 0x66, 0xb4, 0x97, 0x21, 0xc9, 0x60, - 0x1b, 0xda, 0x7d, 0xbd, 0x64, 0xb3, 0xf1, 0xc6, 0x73, 0xff, 0x48, 0xb1, - 0x5c, 0xe0, 0xa1, 0x2d, 0xd7, 0xab, 0x4e, 0x15, 0x51, 0x78, 0xab, 0x8c, - 0x1c, 0x47, 0x0f, 0x03, 0xfe, 0x49, 0xe2, 0x80, 0x94, 0xfe, 0x03, 0x62, - 0x16, 0x09, 0xf8, 0xda, 0x12, 0x12, 0x08, 0xf6, 0x8e, 0xea, 0x8e, 0x7c, - 0xdf, 0xbf, 0x17, 0xe2, 0xe8, 0x34, 0xb7, 0xef, 0x54, 0x51, 0xb1, 0x0e, - 0xd4, 0xec, 0x47, 0xcb, 0x3b, 0xc4, 0x1b, 0x7e, 0xd0, 0x2e, 0x61, 0x83, - 0x35, 0x1b, 0xec, 0x0d, 0xc0, 0xea, 0x62, 0xa2, 0x92, 0x8b, 0xff, 0x2e, - 0x6b, 0x96, 0x94, 0x29, 0x28, 0xe0, 0x7d, 0x33, 0x77, 0x09, 0xa4, 0xc4, - 0xd3, 0x89, 0x9d, 0x34, 0xce, 0xbc, 0xff, 0x46, 0xbf, 0x14, 0x7c, 0x87, - 0xdf, 0x96, 0xb8, 0xe9, 0x2d, 0x79, 0x49, 0xba, 0x9b, 0xcf, 0xf6, 0x86, - 0x13, 0x04, 0xab, 0x9f, 0x93, 0xf5, 0x3c, 0x01, 0x06, 0x05, 0x39, 0xa4, - 0xeb, 0xbc, 0xb2, 0x6b, 0xf9, 0x38, 0x60, 0xeb, 0xfd, 0x96, 0xf3, 0x85, - 0xb4, 0xca, 0x89, 0xf9, 0x16, 0x8a, 0xdd, 0x9c, 0xbc, 0x13, 0x75, 0xe8, - 0x5e, 0x86, 0x50, 0x5b, 0x29, 0x12, 0x7f, 0xbc, 0xfc, 0xe1, 0xf3, 0x10, - 0xb3, 0xf6, 0x20, 0x42, 0xe0, 0x58, 0xbc, 0x78, 0x87, 0x14, 0x56, 0xf4, - 0x68, 0xe4, 0x34, 0x11, 0xe9, 0x9e, 0x16, 0x17, 0x9f, 0x43, 0xe3, 0x69, - 0xcf, 0x91, 0x33, 0xfb, 0x2e, 0xef, 0x0a, 0xd0, 0xd5, 0x10, 0x32, 0x69, - 0x82, 0xe6, 0x50, 0x73, 0xfb, 0x58, 0x2d, 0x25, 0x56, 0x97, 0xa0, 0x82, + 0x0b, 0x03, 0x82, 0x01, 0x01, 0x00, 0x98, 0xd9, 0x01, 0x43, 0x11, 0x08, + 0x70, 0x04, 0xa4, 0x9c, 0xab, 0x6c, 0x01, 0xb3, 0xb9, 0xa5, 0x9d, 0x0c, + 0x9b, 0x06, 0x4f, 0xc3, 0x3b, 0xe4, 0xc7, 0xea, 0x19, 0xd2, 0x5d, 0xf1, + 0xf0, 0x33, 0x48, 0xec, 0x0e, 0x9e, 0xb5, 0x47, 0x3d, 0xb3, 0x58, 0x53, + 0x2c, 0x75, 0x32, 0xd8, 0xb9, 0xf1, 0x73, 0x90, 0x32, 0x46, 0xa4, 0x84, + 0xdf, 0x44, 0x64, 0x40, 0x28, 0xfb, 0x91, 0x35, 0x0b, 0xaf, 0xbf, 0xa9, + 0xbb, 0x27, 0x71, 0x9f, 0xc6, 0x93, 0xe2, 0xf9, 0xc4, 0x9d, 0xa5, 0xc6, + 0xd5, 0x75, 0x93, 0x34, 0x97, 0x21, 0xfe, 0x80, 0xd2, 0x06, 0xfb, 0xc9, + 0x72, 0x6c, 0x04, 0x5a, 0x1d, 0x3d, 0x9a, 0x11, 0xbc, 0xd6, 0x87, 0xd2, + 0xb9, 0xe7, 0x8a, 0x2e, 0x30, 0xb5, 0x4f, 0xf2, 0x65, 0xcb, 0x93, 0xdc, + 0x56, 0x75, 0x67, 0xa1, 0x38, 0x23, 0xaf, 0x9c, 0x1b, 0x04, 0x5d, 0x79, + 0xa3, 0x8a, 0x17, 0xe1, 0xad, 0x20, 0x84, 0x23, 0x8f, 0x9b, 0xdd, 0x52, + 0x9a, 0x30, 0x32, 0xbc, 0x8e, 0xa0, 0xaa, 0xce, 0x21, 0x0c, 0x63, 0x86, + 0x19, 0x43, 0xa3, 0xcc, 0xb5, 0x4f, 0x0d, 0xc6, 0x34, 0x7e, 0x46, 0x8e, + 0xa4, 0xc0, 0x5c, 0x73, 0x65, 0xb7, 0x41, 0x75, 0x8e, 0x76, 0xdb, 0x53, + 0x81, 0x7e, 0x3c, 0x63, 0x65, 0xf2, 0x81, 0xb6, 0x40, 0xb5, 0xf8, 0x58, + 0x6f, 0xc1, 0x36, 0x1a, 0x94, 0x9e, 0x72, 0xb2, 0x91, 0x95, 0x87, 0x3a, + 0x26, 0xdd, 0xca, 0xc8, 0xcc, 0x6f, 0x00, 0xe4, 0x0d, 0xb1, 0x04, 0xa6, + 0x92, 0x75, 0xca, 0xfa, 0x9e, 0xc6, 0x91, 0x2d, 0xd4, 0x07, 0xe9, 0x01, + 0x5b, 0xc4, 0xd3, 0x48, 0xde, 0x8b, 0xd4, 0x6d, 0xb9, 0x0c, 0x95, 0x54, + 0x29, 0x14, 0x7c, 0xa0, 0xce, 0xe8, 0x54, 0xaf, 0xf1, 0x65, 0x12, 0xbf, + 0xfb, 0xbc, 0x81, 0x8f, 0xa9, 0xb6, 0x9b, 0x56, 0x6b, 0x6c, 0xa0, 0x82, 0x04, 0xc6, 0x30, 0x82, 0x04, 0xc2, 0x30, 0x82, 0x04, 0xbe, 0x30, 0x82, 0x03, 0xa6, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x04, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, @@ -2215,43 +2267,152 @@ unsigned char imposter_root_ca_cert_pem[] = { 0xe4, 0x38, 0xf7, 0x3e, 0x66, 0xc3, 0x20, 0xf3, 0xc0, 0xf3, 0x38, 0xc9, }; +unsigned char server1_cert_pem[] = { + 0x30, 0x82, 0x04, 0xee, 0x30, 0x82, 0x03, 0xd6, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x01, 0x05, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0xa1, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, + 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e, 0x31, 0x10, 0x30, 0x0e, + 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x07, 0x53, 0x65, 0x61, 0x74, 0x74, + 0x6c, 0x65, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, + 0x07, 0x77, 0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, 0x31, 0x14, 0x30, 0x12, + 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x0b, 0x45, 0x6e, 0x67, 0x69, 0x6e, + 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x0c, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, + 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, + 0x65, 0x20, 0x43, 0x41, 0x20, 0x31, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, + 0x6e, 0x66, 0x6f, 0x40, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73, 0x6c, 0x2e, + 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x35, 0x31, 0x31, 0x31, + 0x33, 0x32, 0x30, 0x34, 0x31, 0x33, 0x36, 0x5a, 0x17, 0x0d, 0x32, 0x38, + 0x30, 0x38, 0x30, 0x39, 0x32, 0x30, 0x34, 0x31, 0x33, 0x36, 0x5a, 0x30, + 0x81, 0x98, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, + 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e, + 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x07, 0x53, + 0x65, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, + 0x55, 0x04, 0x0a, 0x0c, 0x07, 0x77, 0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, + 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x0b, 0x45, + 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x31, 0x19, + 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x10, 0x77, 0x77, 0x77, + 0x31, 0x2e, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, + 0x6d, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6e, 0x66, 0x6f, 0x40, 0x77, + 0x6f, 0x6c, 0x66, 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x82, + 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, + 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xe6, 0x96, 0x55, 0x75, 0xcf, + 0x8a, 0x97, 0x68, 0x8c, 0xb6, 0x38, 0xf6, 0x7a, 0x05, 0xbe, 0x33, 0xb6, + 0x51, 0x47, 0x37, 0x8a, 0xf7, 0xdb, 0x91, 0xbe, 0x92, 0x6b, 0xb7, 0x00, + 0x8c, 0xf2, 0xc5, 0x24, 0x6e, 0x18, 0xe9, 0x92, 0x00, 0x81, 0x01, 0xdc, + 0xb3, 0x4c, 0x28, 0xa9, 0xb7, 0x80, 0xf1, 0x96, 0xcf, 0x23, 0x7a, 0x2f, + 0xae, 0xf8, 0xe3, 0x0f, 0x2d, 0xd3, 0x5e, 0x23, 0xe7, 0xdb, 0x4c, 0xb2, + 0x5d, 0x89, 0x16, 0x17, 0xbe, 0xbe, 0x81, 0xdb, 0xfb, 0x12, 0x6d, 0x28, + 0x4b, 0x10, 0xa0, 0x12, 0x04, 0x27, 0xc1, 0xc9, 0xd0, 0x79, 0x95, 0xef, + 0xe8, 0x8d, 0x8c, 0x59, 0x9b, 0x4e, 0x72, 0x7d, 0xbc, 0x49, 0x2b, 0x22, + 0x4e, 0xf8, 0x4f, 0xe2, 0x0c, 0xf1, 0xe9, 0xe9, 0x97, 0xf9, 0xdf, 0x8c, + 0x5a, 0x0a, 0xaa, 0x38, 0x1d, 0x43, 0x04, 0xa3, 0xa7, 0x89, 0xa1, 0xe2, + 0x83, 0xa4, 0x4b, 0xb5, 0x4e, 0x45, 0x88, 0xa6, 0x22, 0x5d, 0xac, 0xa9, + 0x58, 0x67, 0x88, 0xc1, 0xd5, 0x61, 0xef, 0xbd, 0x11, 0x05, 0x27, 0x94, + 0x47, 0xbb, 0x33, 0xa5, 0x8a, 0xca, 0xee, 0x1f, 0x8d, 0xc0, 0x6e, 0x24, + 0xaf, 0xcd, 0xca, 0xbf, 0x80, 0x47, 0x71, 0x95, 0xac, 0xa9, 0xf1, 0x5d, + 0x23, 0x6c, 0xf5, 0x4b, 0xb4, 0xa9, 0xe1, 0xc4, 0x66, 0xfb, 0xe5, 0xc4, + 0xa1, 0x9f, 0xa7, 0x51, 0xd1, 0x78, 0xcd, 0x2e, 0xb4, 0x3f, 0x2e, 0xe2, + 0x82, 0xf3, 0x7f, 0xc4, 0xa7, 0xf4, 0x31, 0xcf, 0x76, 0x27, 0x3f, 0xdb, + 0x2e, 0xd2, 0x6e, 0xc3, 0x47, 0x23, 0x82, 0xa3, 0x48, 0x40, 0x8c, 0xa7, + 0xc1, 0x13, 0xf0, 0x63, 0x50, 0x54, 0x43, 0xf6, 0x71, 0x12, 0xe1, 0x6f, + 0xa5, 0x7a, 0x58, 0x26, 0xf7, 0xfd, 0x8b, 0x3b, 0x70, 0x18, 0xa0, 0x43, + 0xba, 0x01, 0x6b, 0xb3, 0xf8, 0xd5, 0xbe, 0x05, 0x13, 0x64, 0x31, 0x02, + 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x36, 0x30, 0x82, 0x01, 0x32, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, + 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xcc, 0x55, + 0x15, 0x00, 0xe2, 0x44, 0x89, 0x92, 0x63, 0x6d, 0x10, 0x5d, 0xb9, 0x9e, + 0x73, 0xb6, 0x5d, 0x3a, 0x19, 0xca, 0x30, 0x81, 0xc4, 0x06, 0x03, 0x55, + 0x1d, 0x23, 0x04, 0x81, 0xbc, 0x30, 0x81, 0xb9, 0x80, 0x14, 0x83, 0xc6, + 0x3a, 0x89, 0x2c, 0x81, 0xf4, 0x02, 0xd7, 0x9d, 0x4c, 0xe2, 0x2a, 0xc0, + 0x71, 0x82, 0x64, 0x44, 0xda, 0x0e, 0xa1, 0x81, 0x9d, 0xa4, 0x81, 0x9a, + 0x30, 0x81, 0x97, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, + 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, + 0x6e, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x07, + 0x53, 0x65, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x31, 0x10, 0x30, 0x0e, 0x06, + 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x07, 0x77, 0x6f, 0x6c, 0x66, 0x53, 0x53, + 0x4c, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x0b, + 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x31, + 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0f, 0x77, 0x6f, + 0x6c, 0x66, 0x53, 0x53, 0x4c, 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x20, 0x43, + 0x41, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6e, 0x66, 0x6f, 0x40, 0x77, + 0x6f, 0x6c, 0x66, 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x82, 0x01, + 0x01, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, + 0x05, 0xe0, 0x30, 0x32, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x01, 0x01, 0x04, 0x26, 0x30, 0x24, 0x30, 0x22, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x16, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, + 0x3a, 0x32, 0x32, 0x32, 0x32, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, + 0x01, 0x00, 0x59, 0x54, 0x71, 0x40, 0x62, 0x0a, 0xe5, 0xf0, 0x61, 0x0b, + 0xab, 0x2e, 0xb0, 0xdd, 0x23, 0x51, 0x2b, 0x7b, 0xbf, 0x54, 0x71, 0x29, + 0x4d, 0xe2, 0x94, 0x12, 0xec, 0xc4, 0x3a, 0x18, 0x00, 0xd8, 0x66, 0x53, + 0xbc, 0xf9, 0x39, 0x0e, 0xba, 0x10, 0x59, 0xf5, 0x8c, 0x58, 0x4d, 0xdd, + 0x35, 0x55, 0xfa, 0x7d, 0x41, 0x2d, 0x7a, 0x19, 0x1f, 0xa8, 0xc4, 0x11, + 0xcf, 0xa7, 0x8e, 0x43, 0xd2, 0x98, 0x9b, 0xc0, 0xdb, 0x79, 0x20, 0x23, + 0xf5, 0x28, 0x95, 0x2e, 0x06, 0xab, 0xb4, 0xfe, 0xa9, 0x0c, 0x91, 0xc6, + 0x32, 0x1d, 0x35, 0x2e, 0x8b, 0x85, 0xaf, 0xa8, 0x21, 0x40, 0x14, 0xe7, + 0x82, 0x71, 0xdc, 0x07, 0xa3, 0xbb, 0x84, 0x5c, 0x1f, 0x1c, 0x6a, 0x47, + 0x4a, 0x01, 0x27, 0x05, 0xd4, 0x5e, 0x4e, 0x82, 0x27, 0x89, 0xd8, 0x36, + 0x8a, 0xfe, 0x0f, 0xd9, 0xa6, 0xec, 0x1f, 0x38, 0x0a, 0x26, 0x4f, 0xbf, + 0x58, 0x12, 0x66, 0x71, 0x33, 0x63, 0xc4, 0xa1, 0x23, 0x03, 0x58, 0xde, + 0x6d, 0x4c, 0xa6, 0x0b, 0xc6, 0x2a, 0x89, 0x5e, 0xc2, 0x8c, 0x56, 0x2f, + 0xc4, 0x01, 0x5e, 0xef, 0x08, 0xc9, 0x7e, 0x35, 0x9f, 0x23, 0xfd, 0xfe, + 0xf3, 0x96, 0x33, 0x4b, 0x59, 0x04, 0x3b, 0x80, 0x06, 0x19, 0x8e, 0x4a, + 0x1c, 0x24, 0xa7, 0xa4, 0x17, 0x12, 0x32, 0xb8, 0x86, 0xeb, 0x72, 0x9c, + 0xd8, 0xd8, 0xba, 0x19, 0x0e, 0x9c, 0x87, 0x07, 0x41, 0x12, 0x86, 0x28, + 0xf0, 0x25, 0x85, 0x53, 0x51, 0xf4, 0xd9, 0x1b, 0xca, 0x52, 0x67, 0x98, + 0x4c, 0xb3, 0x8c, 0xb2, 0x6f, 0xc7, 0xc7, 0x1d, 0xb8, 0x4b, 0x80, 0x6b, + 0x86, 0x17, 0x6e, 0xe7, 0xfa, 0x29, 0xc2, 0xa0, 0x8f, 0xb6, 0xc3, 0xb2, + 0xa7, 0xfc, 0x0a, 0xed, 0xe3, 0x14, 0x6f, 0x80, 0x41, 0x54, 0x93, 0x15, + 0xd9, 0x8f, 0x0a, 0x4c, 0x1e, 0x15, +}; + unsigned char resp_bad[] = { 0x30, 0x82, 0x01, 0xa9, 0xa0, 0x82, 0x01, 0xa5, 0x30, 0x82, 0x01, 0xa1, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01, 0x04, 0x82, 0x01, 0x92, 0x30, 0x82, 0x01, 0x8e, 0x30, 0x7a, 0xa2, 0x16, 0x04, 0x14, 0x32, 0x67, 0xe1, 0xb1, 0x79, 0xd2, 0x81, 0xfc, 0x9f, 0x23, 0x0c, 0x70, 0x40, 0x50, 0xb5, 0x46, 0x56, 0xb8, 0x30, 0x36, 0x18, 0x0f, 0x32, - 0x30, 0x32, 0x36, 0x30, 0x32, 0x32, 0x34, 0x32, 0x31, 0x34, 0x32, 0x30, + 0x30, 0x32, 0x36, 0x30, 0x35, 0x32, 0x31, 0x31, 0x37, 0x32, 0x34, 0x33, 0x31, 0x5a, 0x30, 0x4f, 0x30, 0x4d, 0x30, 0x38, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x04, 0x14, 0x44, 0xa8, 0xdb, 0xd1, 0xbc, 0x97, 0x0a, 0x83, 0x3b, 0x5b, 0x31, 0x9a, 0x4c, 0xb8, 0xd2, 0x52, 0x37, 0x15, 0x8a, 0x88, 0x04, 0x14, 0x73, 0xb0, 0x1c, 0xa4, 0x2f, 0x82, 0xcb, 0xcf, 0x47, 0xa5, 0x38, 0xd7, 0xb0, 0x04, 0x82, 0x3a, 0x7e, 0x72, 0x15, 0x21, 0x02, 0x01, 0x01, 0x80, 0x00, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x36, - 0x30, 0x32, 0x32, 0x34, 0x32, 0x31, 0x34, 0x32, 0x30, 0x31, 0x5a, 0x30, + 0x30, 0x35, 0x32, 0x31, 0x31, 0x37, 0x32, 0x34, 0x33, 0x31, 0x5a, 0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, - 0x03, 0x82, 0x01, 0x01, 0x00, 0x01, 0x8b, 0x06, 0xc9, 0x4f, 0x6c, 0x1d, - 0xc4, 0x4e, 0x1a, 0xc6, 0xd2, 0xbc, 0x6b, 0xbe, 0x3f, 0x9d, 0x73, 0x0c, - 0xbd, 0x3a, 0x82, 0xc0, 0xed, 0xdf, 0x70, 0xaf, 0x00, 0x7d, 0xdd, 0x53, - 0xdd, 0x48, 0xd0, 0x6d, 0xcb, 0xec, 0xd6, 0x31, 0x08, 0x03, 0x3b, 0xcf, - 0x82, 0xce, 0x28, 0x9c, 0x2f, 0xc6, 0x19, 0x48, 0x75, 0xe4, 0xa7, 0xce, - 0x7d, 0x6f, 0xb0, 0x10, 0xb4, 0xc0, 0xbd, 0x1d, 0xe1, 0x9c, 0x57, 0xbc, - 0xff, 0xbf, 0x33, 0x42, 0x0b, 0xea, 0xb4, 0x17, 0x9a, 0x47, 0x5b, 0x3b, - 0xf5, 0xbf, 0xdc, 0x2d, 0xb5, 0xc6, 0xb1, 0xa5, 0xfd, 0x31, 0xaf, 0xe4, - 0x6d, 0xdd, 0xe0, 0x8c, 0x7b, 0x70, 0xe3, 0xcc, 0x59, 0x77, 0xb3, 0x38, - 0x7e, 0x0a, 0xf0, 0xbc, 0x08, 0x86, 0x37, 0xcf, 0x28, 0xa8, 0x07, 0xe8, - 0xae, 0x5c, 0x0d, 0xa5, 0x21, 0x0c, 0xdb, 0xa8, 0x8b, 0x9e, 0x73, 0x77, - 0xf8, 0x0d, 0x05, 0x21, 0xec, 0x4a, 0xf9, 0xb3, 0x71, 0xcd, 0x4b, 0xc9, - 0x5a, 0x22, 0xd4, 0x53, 0x0b, 0xac, 0x28, 0x8e, 0x12, 0x6c, 0x73, 0xe9, - 0x65, 0x53, 0xc8, 0x0e, 0xac, 0x39, 0x7e, 0xd0, 0x77, 0xaf, 0x82, 0xfe, - 0xa4, 0xf2, 0x85, 0xb3, 0x10, 0x73, 0xde, 0x5d, 0xe6, 0xf0, 0xb6, 0xb9, - 0x8c, 0x23, 0x35, 0xcc, 0x5f, 0x29, 0x42, 0x13, 0xd8, 0x72, 0x6f, 0xc2, - 0xf6, 0x10, 0x56, 0xb5, 0x27, 0xe8, 0xd2, 0x2b, 0x15, 0x5f, 0x4e, 0x8e, - 0xa2, 0x19, 0xba, 0x78, 0x0a, 0xa4, 0x24, 0xad, 0xe5, 0x79, 0x72, 0x18, - 0xac, 0xa5, 0xa4, 0x63, 0x0d, 0x33, 0xa3, 0x0c, 0xc0, 0xbb, 0xcd, 0x15, - 0x92, 0x7d, 0xa7, 0x4e, 0xd1, 0x89, 0xb7, 0x00, 0xde, 0x49, 0x48, 0x0d, - 0x28, 0xf1, 0xf1, 0xd8, 0x9c, 0xc3, 0xfa, 0xe8, 0x22, 0xd9, 0x75, 0x9c, - 0x0f, 0xfe, 0x80, 0x7e, 0xbb, 0x68, 0x70, 0x7f, 0x6c, + 0x03, 0x82, 0x01, 0x01, 0x00, 0xae, 0x10, 0x78, 0x6c, 0xa3, 0x67, 0x45, + 0xf1, 0x35, 0x13, 0x7f, 0xe7, 0xa6, 0xf8, 0x10, 0xb8, 0xa9, 0xb4, 0x63, + 0x0e, 0x05, 0x08, 0x0f, 0xfa, 0xef, 0x47, 0x4d, 0xe1, 0x8a, 0x42, 0x59, + 0x51, 0x12, 0xda, 0x8b, 0x58, 0x1f, 0x4b, 0x4c, 0xe9, 0xcd, 0xc3, 0x74, + 0x44, 0xc0, 0x92, 0xdd, 0x0a, 0xb5, 0x7e, 0x1d, 0xc6, 0xff, 0x00, 0xf5, + 0x6f, 0xb4, 0x07, 0x38, 0xb1, 0x3e, 0x7f, 0xc2, 0x08, 0xc2, 0xff, 0x05, + 0x17, 0x96, 0x9b, 0x4b, 0xa9, 0xb2, 0x00, 0x72, 0x65, 0x6b, 0xa1, 0xd8, + 0x71, 0xe0, 0x5e, 0x2a, 0x60, 0x4e, 0x87, 0xce, 0x05, 0x15, 0xcf, 0xcc, + 0xb6, 0x28, 0xe5, 0x57, 0x64, 0x71, 0xa3, 0xb8, 0xa8, 0x30, 0x45, 0x7d, + 0x4f, 0x38, 0x27, 0xa4, 0x9b, 0x79, 0xf1, 0x1f, 0x97, 0xea, 0xcc, 0x0c, + 0x5c, 0x27, 0x37, 0x0a, 0x2d, 0x2b, 0x68, 0x3a, 0x72, 0xfd, 0x22, 0x72, + 0x32, 0x50, 0x22, 0x2b, 0xad, 0xc3, 0x71, 0xa7, 0x6e, 0x24, 0x8b, 0xb9, + 0x5d, 0x28, 0xbf, 0x8b, 0x0b, 0x44, 0xe8, 0x25, 0xe2, 0x3f, 0x5b, 0x81, + 0x70, 0x3d, 0x21, 0x18, 0xca, 0xef, 0xc7, 0x2e, 0xf4, 0xe1, 0xb7, 0xf3, + 0xb6, 0xb4, 0x83, 0x80, 0x2e, 0xd8, 0xe6, 0xfe, 0xe1, 0x01, 0x81, 0x74, + 0x76, 0xe9, 0xb6, 0x40, 0x71, 0x72, 0x84, 0xbd, 0x87, 0xcc, 0x92, 0x49, + 0x6e, 0x94, 0xd1, 0xc3, 0x35, 0xcc, 0xec, 0xc0, 0x2c, 0xce, 0x0d, 0x88, + 0x3c, 0x78, 0x4f, 0x35, 0x1d, 0xe2, 0xc8, 0x51, 0xd0, 0xab, 0x90, 0xd7, + 0xdb, 0x5f, 0x32, 0xc2, 0x3f, 0xdd, 0x2c, 0xe3, 0xb6, 0xec, 0xab, 0x2b, + 0x5d, 0xcf, 0xcb, 0x08, 0x41, 0xaf, 0xff, 0xe3, 0xb8, 0x7f, 0xda, 0x52, + 0xbd, 0x73, 0x93, 0x18, 0xac, 0x5f, 0xa0, 0xf2, 0x56, 0xb6, 0x77, 0xe2, + 0x63, 0x29, 0xc6, 0xa8, 0x97, 0x4b, 0x14, 0xff, 0xd2, }; #endif /* OCSP_TEST_BLOBS_H */ diff --git a/tests/api/test_ossl_cipher.c b/tests/api/test_ossl_cipher.c index f40b097546..c618d45c4d 100644 --- a/tests/api/test_ossl_cipher.c +++ b/tests/api/test_ossl_cipher.c @@ -965,7 +965,9 @@ int test_wolfSSL_RC4(void) wolfSSL_RC4(NULL, 0, data, enc); ExpectIntEQ(1, 1); - for (i = 0; EXPECT_SUCCESS() && (i <= sizeof(key)); i++) { + /* Start at a key length of 1: a zero-length key is invalid and leaves the + * Arc4 object without a key set, so encrypt/decrypt is a no-op. */ + for (i = 1; EXPECT_SUCCESS() && (i <= sizeof(key)); i++) { for (j = 0; EXPECT_SUCCESS() && (j <= sizeof(data)); j++) { XMEMSET(enc, 0, sizeof(enc)); XMEMSET(dec, 0, sizeof(dec)); diff --git a/tests/api/test_ossl_ec.c b/tests/api/test_ossl_ec.c index 51391da519..30cdb3fc86 100644 --- a/tests/api/test_ossl_ec.c +++ b/tests/api/test_ossl_ec.c @@ -1555,6 +1555,11 @@ int test_wolfSSL_ECDSA_SIG(void) sig = NULL; ExpectNull(wolfSSL_d2i_ECDSA_SIG(NULL, NULL, sizeof(sigData))); + /* Reject non-positive length and *pp == NULL (PR #10207). */ + cp = sigData; + ExpectNull(wolfSSL_d2i_ECDSA_SIG(NULL, &cp, -1)); + cp = NULL; + ExpectNull(wolfSSL_d2i_ECDSA_SIG(NULL, &cp, sizeof(sigData))); cp = sigDataBad; ExpectNull(wolfSSL_d2i_ECDSA_SIG(NULL, &cp, sizeof(sigDataBad))); cp = sigData; diff --git a/tests/api/test_ossl_x509_io.c b/tests/api/test_ossl_x509_io.c index 900a9c834b..8e3cd7673e 100644 --- a/tests/api/test_ossl_x509_io.c +++ b/tests/api/test_ossl_x509_io.c @@ -72,6 +72,67 @@ int test_wolfSSL_i2d_X509(void) return EXPECT_RESULT(); } +int test_wolfSSL_X509_get_der_length_guards(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && defined(USE_CERT_BUFFERS_2048) && !defined(NO_RSA) + const unsigned char* cert_buf = server_cert_der_2048; + X509* cert = NULL; + int derSz = 0; + word32 origLen = 0; + + ExpectNotNull(d2i_X509(&cert, &cert_buf, sizeof_server_cert_der_2048)); + ExpectNotNull(cert); + ExpectNotNull(cert->derCert); + + if (EXPECT_SUCCESS()) { + origLen = cert->derCert->length; + cert->derCert->length = ((word32)INT_MAX) + 1U; + ExpectNull(wolfSSL_X509_get_der(cert, &derSz)); + cert->derCert->length = origLen; + } + + X509_free(cert); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_i2d_X509_der_length_guards(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && defined(USE_CERT_BUFFERS_2048) && !defined(NO_RSA) + const unsigned char* cert_buf = server_cert_der_2048; + unsigned char buf[4] = { 0x11, 0x22, 0x33, 0x44 }; + const unsigned char origBuf[4] = { 0x11, 0x22, 0x33, 0x44 }; + unsigned char* callerOut = buf; + X509* cert = NULL; + word32 origLen = 0; + + ExpectNotNull(d2i_X509(&cert, &cert_buf, sizeof_server_cert_der_2048)); + ExpectNotNull(cert); + ExpectNotNull(cert->derCert); + + if (EXPECT_SUCCESS()) { + origLen = cert->derCert->length; + + cert->derCert->length = ((word32)INT_MAX) + 1U; + ExpectIntEQ(i2d_X509(cert, &callerOut), MEMORY_E); + ExpectPtrEq(callerOut, buf); + ExpectIntEQ(XMEMCMP(buf, origBuf, sizeof(buf)), 0); + + cert->derCert->length = 0; + ExpectIntEQ(i2d_X509(cert, &callerOut), MEMORY_E); + ExpectPtrEq(callerOut, buf); + ExpectIntEQ(XMEMCMP(buf, origBuf, sizeof(buf)), 0); + + cert->derCert->length = origLen; + } + + X509_free(cert); +#endif + return EXPECT_RESULT(); +} + int test_wolfSSL_PEM_read_X509(void) { EXPECT_DECLS; @@ -244,4 +305,3 @@ int test_wolfSSL_PEM_write_bio_X509(void) #endif return EXPECT_RESULT(); } - diff --git a/tests/api/test_ossl_x509_io.h b/tests/api/test_ossl_x509_io.h index ec346fbdd9..f8ef4d4a51 100644 --- a/tests/api/test_ossl_x509_io.h +++ b/tests/api/test_ossl_x509_io.h @@ -25,11 +25,17 @@ #include int test_wolfSSL_i2d_X509(void); +int test_wolfSSL_X509_get_der_length_guards(void); +int test_wolfSSL_i2d_X509_der_length_guards(void); int test_wolfSSL_PEM_read_X509(void); int test_wolfSSL_PEM_write_bio_X509(void); #define TEST_OSSL_X509_IO_DECLS \ TEST_DECL_GROUP("ossl_x509_io", test_wolfSSL_i2d_X509), \ + TEST_DECL_GROUP("ossl_x509_io", \ + test_wolfSSL_X509_get_der_length_guards), \ + TEST_DECL_GROUP("ossl_x509_io", \ + test_wolfSSL_i2d_X509_der_length_guards), \ TEST_DECL_GROUP("ossl_x509_io", test_wolfSSL_PEM_read_X509), \ TEST_DECL_GROUP("ossl_x509_io", test_wolfSSL_PEM_write_bio_X509) diff --git a/tests/api/test_pkcs7.c b/tests/api/test_pkcs7.c index 810573a6d1..eaa20d365d 100644 --- a/tests/api/test_pkcs7.c +++ b/tests/api/test_pkcs7.c @@ -3933,6 +3933,224 @@ int test_wc_PKCS7_EncodeEncryptedData(void) } /* END test_wc_PKCS7_EncodeEncryptedData() */ +/* + * Regression test for an integer overflow in the PKCS#7 attribute encode + * path. An application-supplied PKCS7Attrib.valueSz close to UINT32_MAX used + * to wrap the word32 size accumulation in EncodeAttributes() / + * FlattenEncodedAttribs(), yielding an undersized allocation followed by a + * multi-gigabyte XMEMCPY (heap buffer overflow). The encode call must now + * reject the oversized attribute with an error rather than overflow. + */ +int test_wc_PKCS7_EncodeEncryptedData_AttribOverflow(void) +{ + EXPECT_DECLS; +#if defined(HAVE_PKCS7) && !defined(NO_PKCS7_ENCRYPTED_DATA) && ( \ + (!defined(NO_AES) && defined(HAVE_AES_CBC) && \ + (defined(WOLFSSL_AES_256) || defined(WOLFSSL_AES_128))) || \ + !defined(NO_DES3)) + PKCS7* pkcs7 = NULL; + byte output[TWOK_BUF]; + PKCS7Attrib attrib; + int i; + /* Two values that each overflow the size arithmetic in EncodeAttributes() + * but trip a different guard: + * 0xFFFFFFF4 - wraps the word32 component sum (first guard), and + * 0x7FFFFFF0 - stays within word32 but pushes the per-attribute total + * past the signed int maximum (second guard). */ + static const word32 overflowSz[] = { 0xFFFFFFF4U, 0x7FFFFFF0U }; + /* Small, valid attribute buffers. The encode path must reject the + * oversized valueSz before ever dereferencing attrib.value. */ + static const byte oid[] = { 0x06, 0x03, 0x55, 0x04, 0x03 }; + static const byte value[] = { 0x04, 0x01, 0x00 }; + const byte data[] = { /* Hello World */ + 0x48,0x65,0x6c,0x6c,0x6f,0x20,0x57,0x6f,0x72,0x6c,0x64 + }; +#if !defined(NO_AES) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_256) + byte key[] = { + 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08, + 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08, + 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08, + 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08 + }; + int encryptOID = AES256CBCb; +#elif !defined(NO_AES) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_128) + byte key[] = { + 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08, + 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08 + }; + int encryptOID = AES128CBCb; +#else + byte key[] = { + 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef, + 0xfe,0xde,0xba,0x98,0x76,0x54,0x32,0x10, + 0x89,0xab,0xcd,0xef,0x01,0x23,0x45,0x67 + }; + int encryptOID = DES3b; +#endif + + XMEMSET(&attrib, 0, sizeof(attrib)); + attrib.oid = oid; + attrib.oidSz = (word32)sizeof(oid); + attrib.value = value; + + for (i = 0; i < (int)(sizeof(overflowSz) / sizeof(overflowSz[0])); i++) { + attrib.valueSz = overflowSz[i]; + + ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId)); + ExpectIntEQ(wc_PKCS7_Init(pkcs7, HEAP_HINT, testDevId), 0); + if (pkcs7 != NULL) { + pkcs7->content = (byte*)data; + pkcs7->contentSz = (word32)sizeof(data); + pkcs7->contentOID = DATA; + pkcs7->encryptOID = encryptOID; + pkcs7->encryptionKey = key; + pkcs7->encryptionKeySz = (word32)sizeof(key); + pkcs7->unprotectedAttribs = &attrib; + pkcs7->unprotectedAttribsSz = 1; + } + + ExpectIntEQ(wc_PKCS7_EncodeEncryptedData(pkcs7, output, sizeof(output)), + WC_NO_ERR_TRACE(BUFFER_E)); + + wc_PKCS7_Free(pkcs7); + pkcs7 = NULL; + } +#endif + return EXPECT_RESULT(); +} /* END test_wc_PKCS7_EncodeEncryptedData_AttribOverflow() */ + + +/* + * Same overflow guard, exercised through the SignedData attribute path + * (pkcs7->signedAttribs -> wc_PKCS7_BuildSignedAttributes -> EncodeAttributes). + * The encode must reject the oversized attribute instead of overflowing. + */ +int test_wc_PKCS7_EncodeSignedData_AttribOverflow(void) +{ + EXPECT_DECLS; +#if defined(HAVE_PKCS7) && defined(USE_CERT_BUFFERS_2048) && !defined(NO_RSA) + PKCS7* pkcs7 = NULL; + WC_RNG rng; + byte output[FOURK_BUF]; + byte data[] = "Test data to encode."; + PKCS7Attrib attrib; + static const byte oid[] = { 0x06, 0x03, 0x55, 0x04, 0x03 }; + static const byte value[] = { 0x04, 0x01, 0x00 }; + + XMEMSET(&rng, 0, sizeof(WC_RNG)); + XMEMSET(&attrib, 0, sizeof(attrib)); + attrib.oid = oid; + attrib.oidSz = (word32)sizeof(oid); + attrib.value = value; + /* word32 wraparound trigger */ + attrib.valueSz = 0xFFFFFFF4U; + + ExpectIntEQ(wc_InitRng(&rng), 0); + ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId)); + ExpectIntEQ(wc_PKCS7_Init(pkcs7, HEAP_HINT, INVALID_DEVID), 0); + ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, (byte*)client_cert_der_2048, + (word32)sizeof(client_cert_der_2048)), 0); + if (pkcs7 != NULL) { + pkcs7->content = data; + pkcs7->contentSz = (word32)sizeof(data); + pkcs7->privateKey = (byte*)client_key_der_2048; + pkcs7->privateKeySz = (word32)sizeof(client_key_der_2048); + pkcs7->encryptOID = RSAk; + #if defined(NO_SHA) || defined(WC_FIPS_186_5_PLUS) + pkcs7->hashOID = SHA256h; + #else + pkcs7->hashOID = SHAh; + #endif + pkcs7->rng = &rng; + pkcs7->signedAttribs = &attrib; + pkcs7->signedAttribsSz = 1; + } + + ExpectIntEQ(wc_PKCS7_EncodeSignedData(pkcs7, output, sizeof(output)), + WC_NO_ERR_TRACE(BUFFER_E)); + + wc_PKCS7_Free(pkcs7); + DoExpectIntEQ(wc_FreeRng(&rng), 0); +#endif + return EXPECT_RESULT(); +} /* END test_wc_PKCS7_EncodeSignedData_AttribOverflow() */ + + +/* + * Same overflow guard, exercised through the AuthEnvelopedData attribute + * paths. Case 1 covers a malicious authenticated attribute; case 2 supplies a + * valid authenticated attribute (which forces allocation of the auth attrib + * and AAD buffers) together with a malicious unauthenticated attribute, so the + * more complex unauth cleanup path (FreeEncodedRecipientSet + XFREE(aadBuffer) + * + XFREE(flatAuthAttribs)) is exercised. Both must return an error. + */ +int test_wc_PKCS7_EncodeAuthEnvelopedData_AttribOverflow(void) +{ + EXPECT_DECLS; +#if defined(HAVE_PKCS7) && defined(USE_CERT_BUFFERS_2048) && !defined(NO_RSA) && \ + defined(HAVE_AESGCM) && !defined(NO_AES) && defined(WOLFSSL_AES_256) + PKCS7* pkcs7 = NULL; + byte output[FOURK_BUF]; + byte data[] = "Test data to encode."; + PKCS7Attrib bad; + PKCS7Attrib good; + static const byte oid[] = { 0x06, 0x03, 0x55, 0x04, 0x03 }; + static const byte value[] = { 0x04, 0x01, 0x00 }; + + XMEMSET(&bad, 0, sizeof(bad)); + bad.oid = oid; + bad.oidSz = (word32)sizeof(oid); + bad.value = value; + /* word32 wraparound trigger */ + bad.valueSz = 0xFFFFFFF4U; + + XMEMSET(&good, 0, sizeof(good)); + good.oid = oid; + good.oidSz = (word32)sizeof(oid); + good.value = value; + good.valueSz = (word32)sizeof(value); + + /* Case 1: malicious authenticated attribute. */ + ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId)); + ExpectIntEQ(wc_PKCS7_Init(pkcs7, HEAP_HINT, INVALID_DEVID), 0); + ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, (byte*)client_cert_der_2048, + (word32)sizeof(client_cert_der_2048)), 0); + if (pkcs7 != NULL) { + pkcs7->content = data; + pkcs7->contentSz = (word32)sizeof(data); + pkcs7->contentOID = DATA; + pkcs7->encryptOID = AES256GCMb; + pkcs7->authAttribs = &bad; + pkcs7->authAttribsSz = 1; + } + ExpectIntEQ(wc_PKCS7_EncodeAuthEnvelopedData(pkcs7, output, sizeof(output)), + WC_NO_ERR_TRACE(BUFFER_E)); + wc_PKCS7_Free(pkcs7); + pkcs7 = NULL; + + /* Case 2: valid authenticated attribute + malicious unauthenticated one. */ + ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId)); + ExpectIntEQ(wc_PKCS7_Init(pkcs7, HEAP_HINT, INVALID_DEVID), 0); + ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, (byte*)client_cert_der_2048, + (word32)sizeof(client_cert_der_2048)), 0); + if (pkcs7 != NULL) { + pkcs7->content = data; + pkcs7->contentSz = (word32)sizeof(data); + pkcs7->contentOID = DATA; + pkcs7->encryptOID = AES256GCMb; + pkcs7->authAttribs = &good; + pkcs7->authAttribsSz = 1; + pkcs7->unauthAttribs = &bad; + pkcs7->unauthAttribsSz = 1; + } + ExpectIntEQ(wc_PKCS7_EncodeAuthEnvelopedData(pkcs7, output, sizeof(output)), + WC_NO_ERR_TRACE(BUFFER_E)); + wc_PKCS7_Free(pkcs7); +#endif + return EXPECT_RESULT(); +} /* END test_wc_PKCS7_EncodeAuthEnvelopedData_AttribOverflow() */ + + #if defined(HAVE_PKCS7) && defined(USE_CERT_BUFFERS_2048) && !defined(NO_DES3) && !defined(NO_RSA) && !defined(NO_SHA) static void build_test_EncryptedKeyPackage(byte * out, word32 * out_size, byte * in_data, word32 in_size, size_t in_content_type, size_t test_vector) { diff --git a/tests/api/test_pkcs7.h b/tests/api/test_pkcs7.h index 1dfd7f5626..bf25365cc7 100644 --- a/tests/api/test_pkcs7.h +++ b/tests/api/test_pkcs7.h @@ -29,6 +29,8 @@ int test_wc_PKCS7_Init(void); int test_wc_PKCS7_InitWithCert(void); int test_wc_PKCS7_EncodeData(void); int test_wc_PKCS7_EncodeSignedData(void); +int test_wc_PKCS7_EncodeSignedData_AttribOverflow(void); +int test_wc_PKCS7_EncodeAuthEnvelopedData_AttribOverflow(void); #if defined(HAVE_PKCS7) && defined(WC_RSA_PSS) && !defined(NO_RSA) && \ !defined(NO_FILESYSTEM) && !defined(NO_SHA256) int test_wc_PKCS7_EncodeSignedData_RSA_PSS(void); @@ -56,6 +58,7 @@ int test_wc_PKCS7_EncodeDecodeEnvelopedData(void); int test_wc_PKCS7_SetAESKeyWrapUnwrapCb(void); int test_wc_PKCS7_GetEnvelopedDataKariRid(void); int test_wc_PKCS7_EncodeEncryptedData(void); +int test_wc_PKCS7_EncodeEncryptedData_AttribOverflow(void); int test_wc_PKCS7_DecodeEncryptedKeyPackage(void); int test_wc_PKCS7_DecodeSymmetricKeyPackage(void); int test_wc_PKCS7_DecodeOneSymmetricKey(void); @@ -112,6 +115,7 @@ int test_wc_PKCS7_VerifySignedData_TruncCertSetTag(void); TEST_DECL_GROUP("pkcs7_sd", test_wc_PKCS7_InitWithCert), \ TEST_DECL_GROUP("pkcs7_sd", test_wc_PKCS7_EncodeData), \ TEST_DECL_GROUP("pkcs7_sd", test_wc_PKCS7_EncodeSignedData), \ + TEST_DECL_GROUP("pkcs7_sd", test_wc_PKCS7_EncodeSignedData_AttribOverflow), \ TEST_PKCS7_RSA_PSS_SD_DECL \ TEST_DECL_GROUP("pkcs7_sd", test_wc_PKCS7_EncodeSignedData_ex), \ TEST_DECL_GROUP("pkcs7_sd", test_wc_PKCS7_VerifySignedData_RSA), \ @@ -134,6 +138,8 @@ int test_wc_PKCS7_VerifySignedData_TruncCertSetTag(void); TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_SetAESKeyWrapUnwrapCb), \ TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_GetEnvelopedDataKariRid), \ TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_EncodeEncryptedData), \ + TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_EncodeEncryptedData_AttribOverflow), \ + TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_EncodeAuthEnvelopedData_AttribOverflow), \ TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_DecodeEncryptedKeyPackage), \ TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_DecodeSymmetricKeyPackage), \ TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_DecodeOneSymmetricKey), \ diff --git a/tests/api/test_random.c b/tests/api/test_random.c index cdd7e84499..fc70df7cd4 100644 --- a/tests/api/test_random.c +++ b/tests/api/test_random.c @@ -30,6 +30,9 @@ #include #include +#ifdef HAVE_ENTROPY_MEMUSE + #include +#endif #include #include @@ -739,3 +742,30 @@ int test_wc_RNG_HealthTest_SHA512(void) return EXPECT_RESULT(); } +int test_wc_Entropy_Get(void) +{ + EXPECT_DECLS; +#ifdef HAVE_ENTROPY_MEMUSE + byte entropy[WC_SHA3_256_DIGEST_SIZE]; /* 32 bytes */ + + /* bits <= 0: must reject */ + ExpectIntEQ(wc_Entropy_Get(0, entropy, sizeof(entropy)), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_Entropy_Get(-1, entropy, sizeof(entropy)), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* bits > MAX_ENTROPY_BITS: must reject (overflow guard) */ + ExpectIntEQ(wc_Entropy_Get(MAX_ENTROPY_BITS + 1, entropy, sizeof(entropy)), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_Entropy_Get(MAX_ENTROPY_BITS * 8 + 1, entropy, sizeof(entropy)), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* entropy == NULL with len > 0: must reject */ + ExpectIntEQ(wc_Entropy_Get(MAX_ENTROPY_BITS, NULL, sizeof(entropy)), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* valid call: bits == MAX_ENTROPY_BITS */ + ExpectIntEQ(wc_Entropy_Get(MAX_ENTROPY_BITS, entropy, sizeof(entropy)), 0); +#endif /* HAVE_ENTROPY_MEMUSE */ + return EXPECT_RESULT(); +} diff --git a/tests/api/test_random.h b/tests/api/test_random.h index 0f41b3e04a..07a86e6904 100644 --- a/tests/api/test_random.h +++ b/tests/api/test_random.h @@ -37,6 +37,7 @@ int test_wc_RNG_DRBG_Reseed(void); int test_wc_RNG_TestSeed(void); int test_wc_RNG_HealthTest(void); int test_wc_RNG_HealthTest_SHA512(void); +int test_wc_Entropy_Get(void); #define TEST_RANDOM_DECLS \ TEST_DECL_GROUP("random", test_wc_InitRng), \ @@ -51,6 +52,7 @@ int test_wc_RNG_HealthTest_SHA512(void); TEST_DECL_GROUP("random", test_wc_RNG_DRBG_Reseed), \ TEST_DECL_GROUP("random", test_wc_RNG_TestSeed), \ TEST_DECL_GROUP("random", test_wc_RNG_HealthTest), \ - TEST_DECL_GROUP("random", test_wc_RNG_HealthTest_SHA512) + TEST_DECL_GROUP("random", test_wc_RNG_HealthTest_SHA512), \ + TEST_DECL_GROUP("random", test_wc_Entropy_Get) #endif /* WOLFCRYPT_TEST_RANDOM_H */ diff --git a/tests/api/test_rsa.c b/tests/api/test_rsa.c index 7678737573..81e1c7cdd1 100644 --- a/tests/api/test_rsa.c +++ b/tests/api/test_rsa.c @@ -1211,6 +1211,76 @@ int test_wc_RsaDecrypt_BoundsCheck(void) return EXPECT_RESULT(); } /* END test_wc_RsaDecryptBoundsCheck */ +/* + * Oversized RSA modulus (mp_bitsused(n) > RSA_MAX_SIZE) must not overflow the + * static stack buffer used by RsaFunctionCheckIn (DECL_MP_INT_SIZE_DYN). + * + * The buffer is sized for RSA_MAX_SIZE digits, and NEW_MP_INT_SIZE would zero + * mp_bitsused(&key->n) digits of it -- so an oversized modulus must be + * caught by MP_BITS_OVER_MAX *before* NEW_MP_INT_SIZE is reached. We feed + * wc_RsaDirect() an input/output buffer matching the oversized modulus byte + * size so we get past wc_RsaDirect()'s inLen sanity check and reach the + * RsaFunctionCheckIn() guard inside wc_RsaFunction_ex(). + */ +int test_wc_RsaFunctionCheckIn_OversizedModulus(void) +{ + EXPECT_DECLS; +#if !defined(NO_RSA) && defined(WC_RSA_NO_PADDING) && defined(WC_RSA_DIRECT) && \ + defined(WOLFSSL_PUBLIC_MP) && !defined(NO_RSA_BOUNDS_CHECK) && \ + !defined(WOLFSSL_RSA_VERIFY_ONLY) && !defined(TEST_UNPAD_CONSTANT_TIME) && \ + (defined(WOLFSSL_SP_MATH) || defined(WOLFSSL_SP_MATH_ALL)) && \ + !defined(WOLFSSL_SMALL_STACK) && \ + (defined(USE_CERT_BUFFERS_1024) || defined(USE_CERT_BUFFERS_2048)) + /* Setting bit RSA_MAX_SIZE makes the modulus RSA_MAX_SIZE+1 bits, i.e. + * (RSA_MAX_SIZE/8 + 1) bytes -- size buffers accordingly with slack. */ + #define WC_RSA_OVERSIZED_BUF_LEN ((RSA_MAX_SIZE / 8) + 8) + WC_RNG rng; + RsaKey key; + const byte* derKey; + word32 derKeySz; + word32 idx = 0; + byte flatC[WC_RSA_OVERSIZED_BUF_LEN]; + word32 flatCSz; + byte out[WC_RSA_OVERSIZED_BUF_LEN]; + word32 outSz = sizeof(out); + int encSz; + + #ifdef USE_CERT_BUFFERS_1024 + derKey = server_key_der_1024; + derKeySz = (word32)sizeof_server_key_der_1024; + #else + derKey = server_key_der_2048; + derKeySz = (word32)sizeof_server_key_der_2048; + #endif + + XMEMSET(&key, 0, sizeof(RsaKey)); + XMEMSET(&rng, 0, sizeof(WC_RNG)); + + ExpectIntEQ(wc_InitRsaKey(&key, HEAP_HINT), 0); + ExpectIntEQ(wc_InitRng(&rng), 0); + ExpectIntEQ(wc_RsaPrivateKeyDecode(derKey, &idx, &key, derKeySz), 0); + /* Force modulus bit count above RSA_MAX_SIZE. */ + ExpectIntEQ(mp_set_bit(&key.n, RSA_MAX_SIZE), 0); + + /* Match wc_RsaDirect()'s inLen check so we actually reach + * RsaFunctionCheckIn() (where the MP_BITS_OVER_MAX guard lives). */ + encSz = wc_RsaEncryptSize(&key); + ExpectIntGT(encSz, 0); + ExpectIntLE(encSz, (int)sizeof(flatC)); + if (encSz > 0 && (size_t)encSz <= sizeof(flatC)) { + flatCSz = (word32)encSz; + XMEMSET(flatC, 0, flatCSz); + ExpectIntEQ(wc_RsaDirect(flatC, flatCSz, out, &outSz, &key, + RSA_PRIVATE_DECRYPT, &rng), WC_NO_ERR_TRACE(WC_KEY_SIZE_E)); + } + + DoExpectIntEQ(wc_FreeRsaKey(&key), 0); + DoExpectIntEQ(wc_FreeRng(&rng), 0); + #undef WC_RSA_OVERSIZED_BUF_LEN +#endif + return EXPECT_RESULT(); +} /* END test_wc_RsaFunctionCheckIn_OversizedModulus */ + /* * Test wc_RsaKeyToDer with an mp_int large enough to wrap size calculations. */ diff --git a/tests/api/test_rsa.h b/tests/api/test_rsa.h index 7de2fd3532..27bc8f6402 100644 --- a/tests/api/test_rsa.h +++ b/tests/api/test_rsa.h @@ -43,6 +43,7 @@ int test_wc_RsaEncryptSize(void); int test_wc_RsaSSL_SignVerify(void); int test_wc_RsaFlattenPublicKey(void); int test_wc_RsaDecrypt_BoundsCheck(void); +int test_wc_RsaFunctionCheckIn_OversizedModulus(void); int test_wc_RsaKeyToDer_SizeOverflow(void); #define TEST_RSA_DECLS \ @@ -65,6 +66,7 @@ int test_wc_RsaKeyToDer_SizeOverflow(void); TEST_DECL_GROUP("rsa", test_wc_RsaSSL_SignVerify), \ TEST_DECL_GROUP("rsa", test_wc_RsaFlattenPublicKey), \ TEST_DECL_GROUP("rsa", test_wc_RsaDecrypt_BoundsCheck), \ + TEST_DECL_GROUP("rsa", test_wc_RsaFunctionCheckIn_OversizedModulus), \ TEST_DECL_GROUP("rsa", test_wc_RsaKeyToDer_SizeOverflow) #endif /* WOLFCRYPT_TEST_RSA_H */ diff --git a/tests/api/test_sha512.c b/tests/api/test_sha512.c index 419fb60b31..eb5a31c8f5 100644 --- a/tests/api/test_sha512.c +++ b/tests/api/test_sha512.c @@ -874,3 +874,284 @@ int test_wc_Sha384_Flags(void) return EXPECT_RESULT(); } +/* The SHA-512/224 and SHA-512/256 variants are only available under these + * build conditions. */ +#if defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_224) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5, 3)) && !defined(HAVE_SELFTEST) + #define TEST_WC_SHA512_224_FALLBACK +#endif +#if defined(WOLFSSL_SHA512) && !defined(WOLFSSL_NOSHA512_256) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5, 3)) && !defined(HAVE_SELFTEST) + #define TEST_WC_SHA512_256_FALLBACK +#endif + +#if defined(WOLF_CRYPTO_CB) && defined(WOLFSSL_SHA512) && \ + !defined(NO_SHA2_CRYPTO_CB) && \ + ((!defined(WOLF_CRYPTO_CB_NO_SHA512_FALLBACK) && \ + (defined(WOLFSSL_SHA384) || defined(TEST_WC_SHA512_224_FALLBACK) || \ + defined(TEST_WC_SHA512_256_FALLBACK))) || \ + defined(WOLF_CRYPTO_CB_ONLY_SHA512)) + +#include + +#define TEST_CRYPTOCB_SHA512_DEVID 2 + +typedef struct { + int variantSeen; /* SHA-384 / SHA-512-224 / SHA-512-256 callback declined */ + int sha512Seen; /* generic SHA-512 callback the fallback lands on */ +#ifdef WOLF_CRYPTO_CB_FREE + int freeSeen; /* SHA-512-family free callbacks the CB-only free routes to */ +#endif +} Sha512DevCbCtx; + +/* Shared SHA-512 crypto-callback test device. For HASH ops it declines every + * SHA-512 variant callback so the cryptocb dispatcher falls back to the generic + * SHA-512 callback; that callback fills a recognisable digest and deliberately + * leaves the SHA-512 IV in the caller's state, forcing the dispatcher to reset + * the state back to the variant IV. */ +static int sha512_dev_cb(int devIdArg, wc_CryptoInfo* info, void* ctx) +{ + Sha512DevCbCtx* cbCtx = (Sha512DevCbCtx*)ctx; + int i; + + (void)devIdArg; + + if (info == NULL || cbCtx == NULL) + return BAD_FUNC_ARG; + +#ifdef WOLF_CRYPTO_CB_FREE + if (info->algo_type == WC_ALGO_TYPE_FREE) { + /* Count SHA-512-family frees so the test can confirm the + * CB-only free path reaches the callback instead of only zeroing the + * struct. Decline so the caller still performs its standard cleanup. */ + if (info->free.algo == WC_ALGO_TYPE_HASH && + (info->free.type == WC_HASH_TYPE_SHA512 || + info->free.type == WC_HASH_TYPE_SHA384)) + cbCtx->freeSeen++; + return CRYPTOCB_UNAVAILABLE; + } +#endif + + if (info->algo_type != WC_ALGO_TYPE_HASH) + return CRYPTOCB_UNAVAILABLE; + + switch (info->hash.type) { + case WC_HASH_TYPE_SHA384: + case WC_HASH_TYPE_SHA512_224: + case WC_HASH_TYPE_SHA512_256: + cbCtx->variantSeen++; + return CRYPTOCB_UNAVAILABLE; + + case WC_HASH_TYPE_SHA512: + cbCtx->sha512Seen++; + if (info->hash.digest != NULL) { + for (i = 0; i < WC_SHA512_DIGEST_SIZE; i++) + info->hash.digest[i] = (byte)(0x80 + i); + } + #ifndef WOLF_CRYPTO_CB_NO_SHA512_FALLBACK + /* leave the SHA-512 IV in the caller's state to force the + * dispatcher's variant IV reset; backends that drop the digest[] + * field disable the fallback, so this only runs when it exists */ + if (info->hash.sha512 != NULL) { + for (i = 0; i < (int)(sizeof(info->hash.sha512->digest) / + sizeof(info->hash.sha512->digest[0])); i++) { + info->hash.sha512->digest[i] = W64LIT(0xdeadbeefcafebabe); + } + } + #endif + return 0; + + default: + return CRYPTOCB_UNAVAILABLE; + } +} + +#endif + +int test_wc_sha512_cryptocb_fallback(void) +{ + EXPECT_DECLS; +#if defined(WOLF_CRYPTO_CB) && defined(WOLFSSL_SHA512) && \ + !defined(NO_SHA2_CRYPTO_CB) && \ + !defined(WOLF_CRYPTO_CB_NO_SHA512_FALLBACK) && \ + (defined(WOLFSSL_SHA384) || defined(TEST_WC_SHA512_224_FALLBACK) || \ + defined(TEST_WC_SHA512_256_FALLBACK)) + typedef struct { + const char* name; + int (*initFn)(wc_Sha512* sha, void* heap, int devId); + int (*finalFn)(wc_Sha512* sha, byte* hash); + word32 digestSz; + } Sha512FallbackCase; + static const Sha512FallbackCase sha512FallbackCases[] = { +#ifdef WOLFSSL_SHA384 + { "SHA-384", wc_InitSha384_ex, wc_Sha384Final, WC_SHA384_DIGEST_SIZE }, +#endif +#ifdef TEST_WC_SHA512_224_FALLBACK + { "SHA-512/224", wc_InitSha512_224_ex, wc_Sha512_224Final, + WC_SHA512_224_DIGEST_SIZE }, +#endif +#ifdef TEST_WC_SHA512_256_FALLBACK + { "SHA-512/256", wc_InitSha512_256_ex, wc_Sha512_256Final, + WC_SHA512_256_DIGEST_SIZE }, +#endif + }; + wc_Sha512 sha; + wc_Sha512 refSha; + Sha512DevCbCtx cbCtx; + byte hash[WC_SHA512_DIGEST_SIZE]; + byte devCtxMarker; + const Sha512FallbackCase* tc; + size_t c; + word32 i; + + for (c = 0; + c < sizeof(sha512FallbackCases) / sizeof(sha512FallbackCases[0]); + c++) { + tc = &sha512FallbackCases[c]; + devCtxMarker = 0; + + XMEMSET(&sha, 0, sizeof(sha)); + sha.devId = INVALID_DEVID; + sha.devCtx = NULL; + XMEMSET(&refSha, 0, sizeof(refSha)); + XMEMSET(&cbCtx, 0, sizeof(cbCtx)); + XMEMSET(hash, 0, sizeof(hash)); + + /* Reference struct capturing the freshly-initialised variant IV state, + * against which we verify the test struct after Final. */ + ExpectIntEQ(tc->initFn(&refSha, HEAP_HINT, INVALID_DEVID), 0); + + ExpectIntEQ(wc_CryptoCb_RegisterDevice( + TEST_CRYPTOCB_SHA512_DEVID, sha512_dev_cb, + &cbCtx), 0); + + ExpectIntEQ(tc->initFn(&sha, HEAP_HINT, + TEST_CRYPTOCB_SHA512_DEVID), 0); + sha.devCtx = &devCtxMarker; + + ExpectIntEQ(tc->finalFn(&sha, hash), 0); + + /* the variant callback is declined, forcing the generic SHA-512 + * fallback */ + ExpectIntEQ(cbCtx.variantSeen, 1); + ExpectIntEQ(cbCtx.sha512Seen, 1); + + /* devId and devCtx must be preserved across the SHA-512 fallback. */ + ExpectIntEQ(sha.devId, TEST_CRYPTOCB_SHA512_DEVID); + ExpectPtrEq(sha.devCtx, &devCtxMarker); + + /* the digest is the generic SHA-512 output truncated to the variant + * digest size */ + for (i = 0; i < tc->digestSz; i++) + ExpectIntEQ(hash[i], (byte)(0x80 + i)); + + /* the SHA-512 fallback leaves the SHA-512 IV in the state buffer; the + * fallback must reset it back to the variant IV so the struct is ready + * to hash a new message */ + ExpectIntEQ(XMEMCMP(sha.digest, refSha.digest, sizeof(sha.digest)), 0); + + wc_Sha512Free(&sha); + wc_Sha512Free(&refSha); + wc_CryptoCb_UnRegisterDevice(TEST_CRYPTOCB_SHA512_DEVID); + } +#endif + return EXPECT_RESULT(); +} + +/* Regression test for the no-_ex SHA-512/224 and SHA-512/256 initializers under + * WOLF_CRYPTO_CB_ONLY_SHA512. With the software path stripped, they must adopt + * the registered default CryptoCb device just like wc_InitSha512() and + * wc_InitSha384(); otherwise devId stays INVALID_DEVID and the public streaming + * API returns NO_VALID_DEVID even though a default device is registered. */ +int test_wc_sha512_variants_default_devid(void) +{ + EXPECT_DECLS; +#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_ONLY_SHA512) && \ + defined(WOLFSSL_SHA512) && !defined(NO_SHA2_CRYPTO_CB) && \ + !defined(WC_NO_DEFAULT_DEVID) && \ + (!defined(WOLFSSL_NOSHA512_224) || !defined(WOLFSSL_NOSHA512_256)) + typedef struct { + const char* name; + int (*initFn)(wc_Sha512* sha); + } Sha512VariantCase; + static const Sha512VariantCase cases[] = { +#ifndef WOLFSSL_NOSHA512_224 + { "SHA-512/224", wc_InitSha512_224 }, +#endif +#ifndef WOLFSSL_NOSHA512_256 + { "SHA-512/256", wc_InitSha512_256 }, +#endif + }; + Sha512DevCbCtx cbCtx; + int defaultDevId; + wc_Sha512 sha; + const Sha512VariantCase* tc; + size_t c; + + XMEMSET(&cbCtx, 0, sizeof(cbCtx)); + + ExpectIntEQ(wc_CryptoCb_RegisterDevice(TEST_CRYPTOCB_SHA512_DEVID, + sha512_dev_cb, &cbCtx), 0); + defaultDevId = wc_CryptoCb_DefaultDevID(); + ExpectIntNE(defaultDevId, INVALID_DEVID); + + for (c = 0; c < sizeof(cases) / sizeof(cases[0]); c++) { + tc = &cases[c]; + + XMEMSET(&sha, 0, sizeof(sha)); + sha.devId = INVALID_DEVID; + + /* the no-_ex initializer must adopt the default device rather than + * leaving devId INVALID_DEVID (which the stripped software path would + * surface as NO_VALID_DEVID from the public streaming API) */ + ExpectIntEQ(tc->initFn(&sha), 0); + ExpectIntEQ(sha.devId, defaultDevId); + + wc_Sha512Free(&sha); + } + + wc_CryptoCb_UnRegisterDevice(TEST_CRYPTOCB_SHA512_DEVID); +#endif + return EXPECT_RESULT(); +} + +/* WOLF_CRYPTO_CB_FREE under WOLF_CRYPTO_CB_ONLY_SHA512: the + * stripped-software wc_Sha512Free()/wc_Sha384Free() must route through the + * crypto callback. */ +int test_wc_sha512_cryptocb_free(void) +{ + EXPECT_DECLS; +#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_FREE) && \ + defined(WOLF_CRYPTO_CB_ONLY_SHA512) && defined(WOLFSSL_SHA512) + Sha512DevCbCtx cbCtx; + wc_Sha512 sha512; +#ifdef WOLFSSL_SHA384 + wc_Sha384 sha384; +#endif + + XMEMSET(&cbCtx, 0, sizeof(cbCtx)); + + ExpectIntEQ(wc_CryptoCb_RegisterDevice(TEST_CRYPTOCB_SHA512_DEVID, + sha512_dev_cb, &cbCtx), 0); + + XMEMSET(&sha512, 0, sizeof(sha512)); + ExpectIntEQ(wc_InitSha512_ex(&sha512, HEAP_HINT, + TEST_CRYPTOCB_SHA512_DEVID), 0); + wc_Sha512Free(&sha512); + /* the free must reach the device callback */ + ExpectIntEQ(cbCtx.freeSeen, 1); + +#ifdef WOLFSSL_SHA384 + cbCtx.freeSeen = 0; + XMEMSET(&sha384, 0, sizeof(sha384)); + ExpectIntEQ(wc_InitSha384_ex(&sha384, HEAP_HINT, + TEST_CRYPTOCB_SHA512_DEVID), 0); + wc_Sha384Free(&sha384); + ExpectIntEQ(cbCtx.freeSeen, 1); +#endif + + wc_CryptoCb_UnRegisterDevice(TEST_CRYPTOCB_SHA512_DEVID); +#endif + return EXPECT_RESULT(); +} + diff --git a/tests/api/test_sha512.h b/tests/api/test_sha512.h index 48882c4daa..3347424455 100644 --- a/tests/api/test_sha512.h +++ b/tests/api/test_sha512.h @@ -66,6 +66,9 @@ int test_wc_Sha384_other(void); int test_wc_Sha384Copy(void); int test_wc_Sha384GetHash(void); int test_wc_Sha384_Flags(void); +int test_wc_sha512_cryptocb_fallback(void); +int test_wc_sha512_variants_default_devid(void); +int test_wc_sha512_cryptocb_free(void); #define TEST_SHA512_DECLS \ TEST_DECL_GROUP("sha512", test_wc_InitSha512), \ @@ -77,7 +80,10 @@ int test_wc_Sha384_Flags(void); TEST_DECL_GROUP("sha512", test_wc_Sha512Copy), \ TEST_DECL_GROUP("sha512", test_wc_Sha512GetHash), \ TEST_DECL_GROUP("sha512", test_wc_Sha512Transform), \ - TEST_DECL_GROUP("sha512", test_wc_Sha512_Flags) + TEST_DECL_GROUP("sha512", test_wc_Sha512_Flags), \ + TEST_DECL_GROUP("sha512", test_wc_sha512_cryptocb_fallback), \ + TEST_DECL_GROUP("sha512", test_wc_sha512_variants_default_devid), \ + TEST_DECL_GROUP("sha512", test_wc_sha512_cryptocb_free) #define TEST_SHA512_224_DECLS \ TEST_DECL_GROUP("sha512_224", test_wc_InitSha512_224), \ diff --git a/tests/api/test_ssl_cert.c b/tests/api/test_ssl_cert.c new file mode 100644 index 0000000000..3a3ef77f3c --- /dev/null +++ b/tests/api/test_ssl_cert.c @@ -0,0 +1,406 @@ +/* test_ssl_cert.c + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL 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. + * + * wolfSSL 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 + +#ifdef NO_INLINE + #include +#else + #define WOLFSSL_MISC_INCLUDED + #include +#endif + +#include +#include + +#include +#include + +/* Tests for the certificate APIs in src/ssl_api_cert.c (moved from ssl.c). */ + +int test_wolfSSL_get_verify_mode(void) +{ + EXPECT_DECLS; +#if (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) || defined(HAVE_STUNNEL) || \ + defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(WOLFSSL_NGINX)) && \ + !defined(NO_CERTS) && !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + int mode; + + ExpectIntEQ(wolfSSL_get_verify_mode(NULL), WOLFSSL_FAILURE); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + wolfSSL_set_verify(ssl, WOLFSSL_VERIFY_NONE, NULL); + ExpectIntEQ(wolfSSL_get_verify_mode(ssl), WOLFSSL_VERIFY_NONE); + + wolfSSL_set_verify(ssl, WOLFSSL_VERIFY_PEER, NULL); + ExpectIntEQ(wolfSSL_get_verify_mode(ssl), WOLFSSL_VERIFY_PEER); + + wolfSSL_set_verify(ssl, WOLFSSL_VERIFY_PEER | + WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); + ExpectIntEQ(wolfSSL_get_verify_mode(ssl), + WOLFSSL_VERIFY_PEER | WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT); + + /* Exercise the fail-except-PSK option. */ + wolfSSL_set_verify(ssl, WOLFSSL_VERIFY_FAIL_EXCEPT_PSK, NULL); + mode = wolfSSL_get_verify_mode(ssl); + ExpectIntEQ(mode & WOLFSSL_VERIFY_FAIL_EXCEPT_PSK, + WOLFSSL_VERIFY_FAIL_EXCEPT_PSK); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_CTX_get_verify_mode(void) +{ + EXPECT_DECLS; +#if (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) || defined(HAVE_STUNNEL) || \ + defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(WOLFSSL_NGINX)) && \ + !defined(NO_CERTS) && !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + int mode; + + ExpectIntEQ(wolfSSL_CTX_get_verify_mode(NULL), WOLFSSL_FAILURE); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + + wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_NONE, NULL); + ExpectIntEQ(wolfSSL_CTX_get_verify_mode(ctx), WOLFSSL_VERIFY_NONE); + + wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER | + WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); + ExpectIntEQ(wolfSSL_CTX_get_verify_mode(ctx), + WOLFSSL_VERIFY_PEER | WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT); + + wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_FAIL_EXCEPT_PSK, NULL); + mode = wolfSSL_CTX_get_verify_mode(ctx); + ExpectIntEQ(mode & WOLFSSL_VERIFY_FAIL_EXCEPT_PSK, + WOLFSSL_VERIFY_FAIL_EXCEPT_PSK); + +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) + /* Exercise the post-handshake auth option. */ + wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER | + WOLFSSL_VERIFY_POST_HANDSHAKE, NULL); + mode = wolfSSL_CTX_get_verify_mode(ctx); + ExpectIntEQ(mode & WOLFSSL_VERIFY_POST_HANDSHAKE, + WOLFSSL_VERIFY_POST_HANDSHAKE); +#endif + + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +#if defined(OPENSSL_ALL) && !defined(NO_CERTS) && !defined(NO_WOLFSSL_CLIENT) +static int test_cert_verify_cb(int preverify, WOLFSSL_X509_STORE_CTX* store) +{ + (void)store; + return preverify; +} +#endif + +int test_wolfSSL_get_verify_callback(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_ALL) && !defined(NO_CERTS) && !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + /* CTX verify callback getter. */ + ExpectNull(wolfSSL_CTX_get_verify_callback(NULL)); + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNull(wolfSSL_CTX_get_verify_callback(ctx)); + wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER, test_cert_verify_cb); + ExpectTrue(wolfSSL_CTX_get_verify_callback(ctx) == test_cert_verify_cb); + + /* SSL verify callback getter. */ + ExpectNull(wolfSSL_get_verify_callback(NULL)); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + wolfSSL_set_verify(ssl, WOLFSSL_VERIFY_PEER, test_cert_verify_cb); + ExpectTrue(wolfSSL_get_verify_callback(ssl) == test_cert_verify_cb); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_CTX_get_extra_chain_certs(void) +{ + EXPECT_DECLS; +#if (defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) || \ + defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL)) && \ + !defined(NO_CERTS) && !defined(NO_FILESYSTEM) && !defined(NO_RSA) && \ + !defined(NO_WOLFSSL_SERVER) + WOLFSSL_CTX* ctx = NULL; + WOLF_STACK_OF(WOLFSSL_X509)* sk = NULL; + + /* NULL arguments fail. */ + ExpectIntEQ(wolfSSL_CTX_get_extra_chain_certs(NULL, &sk), WOLFSSL_FAILURE); + + /* No certificate chain loaded: succeeds with an empty (NULL) stack. */ + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); + sk = NULL; + ExpectIntEQ(wolfSSL_CTX_get_extra_chain_certs(ctx, &sk), WOLFSSL_SUCCESS); + ExpectNull(sk); + wolfSSL_CTX_free(ctx); + ctx = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); + /* server-cert.pem holds a 2-cert chain, so the CA goes into certChain. */ + ExpectIntEQ(wolfSSL_CTX_use_certificate_chain_file(ctx, svrCertFile), + WOLFSSL_SUCCESS); + + /* Builds a stack of X509 from the stored chain. */ + sk = NULL; + ExpectIntEQ(wolfSSL_CTX_get_extra_chain_certs(ctx, &sk), WOLFSSL_SUCCESS); + ExpectNotNull(sk); + + /* get0 returns the same (cached) chain. */ + sk = NULL; + ExpectIntEQ(wolfSSL_CTX_get0_chain_certs(ctx, &sk), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_get0_chain_certs(NULL, &sk), WOLFSSL_FAILURE); + + wolfSSL_CTX_free(ctx); + ctx = NULL; + + /* A longer chain (leaf + 2 certs) exercises appending past the first + * node, building a multi-element stack. */ + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); + ExpectIntEQ(wolfSSL_CTX_use_certificate_chain_file(ctx, + "certs/intermediate/server-chain.pem"), WOLFSSL_SUCCESS); + sk = NULL; + ExpectIntEQ(wolfSSL_CTX_get_extra_chain_certs(ctx, &sk), WOLFSSL_SUCCESS); + ExpectNotNull(sk); + ExpectIntGE(wolfSSL_sk_X509_num(sk), 2); + +#if (defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO) || \ + defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_NGINX) || \ + defined(WOLFSSL_QT)) && !defined(NO_WOLFSSL_STUB) + /* Stub: returns via the control command. */ + wolfSSL_CTX_clear_extra_chain_certs(ctx); +#endif + + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_get_peer_chain(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(SESSION_CERTS) && \ + !defined(WOLFSSL_NO_TLS12) && !defined(NO_RSA) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + WOLFSSL_X509_CHAIN* chain = NULL; + + /* NULL / not-yet-populated cases. */ + ExpectNull(wolfSSL_get_peer_chain(NULL)); + ExpectIntEQ(wolfSSL_get_chain_count(NULL), 0); + ExpectIntEQ(wolfSSL_get_chain_length(NULL, 0), 0); + ExpectNull(wolfSSL_get_chain_cert(NULL, 0)); + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + /* The client now holds the server's certificate chain. */ + ExpectNotNull(chain = wolfSSL_get_peer_chain(ssl_c)); + ExpectIntGT(wolfSSL_get_chain_count(chain), 0); + ExpectIntGT(wolfSSL_get_chain_length(chain, 0), 0); + ExpectNotNull(wolfSSL_get_chain_cert(chain, 0)); + +#ifdef WOLFSSL_ALT_CERT_CHAINS + ExpectNull(wolfSSL_get_peer_alt_chain(NULL)); + ExpectNotNull(wolfSSL_get_peer_alt_chain(ssl_c)); +#endif + +#if (defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) || \ + defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL)) && defined(KEEP_OUR_CERT) + { + WOLF_STACK_OF(WOLFSSL_X509)* osk = NULL; + ExpectIntEQ(wolfSSL_get0_chain_certs(NULL, &osk), WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_get0_chain_certs(ssl_c, &osk), WOLFSSL_SUCCESS); + } +#endif + + wolfSSL_free(ssl_s); + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_s); + wolfSSL_CTX_free(ctx_c); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_get_chain_X509(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(SESSION_CERTS) && \ + !defined(WOLFSSL_NO_TLS12) && !defined(NO_RSA) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + WOLFSSL_X509_CHAIN* chain = NULL; + WOLFSSL_X509* x509 = NULL; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + ExpectNotNull(chain = wolfSSL_get_peer_chain(ssl_c)); + + /* A valid index returns a parseable certificate. */ + ExpectNotNull(x509 = wolfSSL_get_chain_X509(chain, 0)); + wolfSSL_X509_free(x509); + x509 = NULL; + /* NULL chain and an index past MAX_CHAIN_DEPTH return NULL up front. */ + ExpectNull(wolfSSL_get_chain_X509(NULL, 0)); + ExpectNull(wolfSSL_get_chain_X509(chain, MAX_CHAIN_DEPTH)); + /* An index past the populated certs exercises the parse-failure path. */ + ExpectNull(wolfSSL_get_chain_X509(chain, wolfSSL_get_chain_count(chain))); + + wolfSSL_free(ssl_s); + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_s); + wolfSSL_CTX_free(ctx_c); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_get_chain_cert_pem(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(SESSION_CERTS) && \ + !defined(WOLFSSL_NO_TLS12) && !defined(NO_RSA) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + WOLFSSL_X509_CHAIN* chain = NULL; + byte pem[4096]; + int pemSz = 0; + int needed = 0; + int chainLen = 0; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + ExpectNotNull(chain = wolfSSL_get_peer_chain(ssl_c)); + + /* Successful PEM conversion. */ + pemSz = (int)sizeof(pem); + ExpectIntEQ(wolfSSL_get_chain_cert_pem(chain, 0, pem, (int)sizeof(pem), + &pemSz), WOLFSSL_SUCCESS); + ExpectIntGT(pemSz, 0); + + /* Argument validation. */ + pemSz = (int)sizeof(pem); + ExpectIntEQ(wolfSSL_get_chain_cert_pem(NULL, 0, pem, (int)sizeof(pem), + &pemSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_get_chain_cert_pem(chain, -1, pem, (int)sizeof(pem), + &pemSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_get_chain_cert_pem(chain, 99, pem, (int)sizeof(pem), + &pemSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_get_chain_cert_pem(chain, 0, pem, (int)sizeof(pem), + NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* NULL buffer returns the size needed (length-only query). */ + needed = 0; + ExpectIntEQ(wolfSSL_get_chain_cert_pem(chain, 0, NULL, 0, &needed), + WC_NO_ERR_TRACE(LENGTH_ONLY_E)); + ExpectIntGT(needed, 0); + ExpectIntLE(needed, (int)sizeof(pem)); + + /* A buffer shorter than the DER certificate fails up front. */ + pemSz = (int)sizeof(pem); + ExpectIntEQ(wolfSSL_get_chain_cert_pem(chain, 0, pem, 1, &pemSz), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* One byte short of the full size leaves no room for the footer. */ + pemSz = (int)sizeof(pem); + ExpectIntEQ(wolfSSL_get_chain_cert_pem(chain, 0, pem, needed - 1, &pemSz), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* Room for the DER length but not the base64-expanded body: the encoder + * reports an error (negative return). */ + chainLen = wolfSSL_get_chain_length(chain, 0); + pemSz = (int)sizeof(pem); + ExpectIntLT(wolfSSL_get_chain_cert_pem(chain, 0, pem, chainLen + 100, + &pemSz), 0); + + wolfSSL_free(ssl_s); + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_s); + wolfSSL_CTX_free(ctx_c); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_cmp_peer_cert_to_file(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(OPENSSL_EXTRA) && \ + defined(KEEP_PEER_CERT) && defined(HAVE_EX_DATA) && \ + !defined(NO_FILESYSTEM) && !defined(WOLFSSL_NO_TLS12) && !defined(NO_RSA) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + /* NULL arguments report failure. */ + ExpectIntEQ(wolfSSL_cmp_peer_cert_to_file(NULL, svrCertFile), + WOLFSSL_FATAL_ERROR); + ExpectIntEQ(wolfSSL_cmp_peer_cert_to_file(ssl_c, NULL), + WOLFSSL_FATAL_ERROR); + + /* The peer (server) certificate matches the file it was loaded from. */ + ExpectIntEQ(wolfSSL_cmp_peer_cert_to_file(ssl_c, svrCertFile), 0); + /* A different certificate does not match. */ + ExpectIntEQ(wolfSSL_cmp_peer_cert_to_file(ssl_c, caCertFile), + WOLFSSL_FATAL_ERROR); + /* A missing file reports a file error. */ + ExpectIntEQ(wolfSSL_cmp_peer_cert_to_file(ssl_c, + "certs/does-not-exist.pem"), WC_NO_ERR_TRACE(WOLFSSL_BAD_FILE)); + /* A readable file that is not PEM-encoded fails conversion. */ + ExpectIntEQ(wolfSSL_cmp_peer_cert_to_file(ssl_c, cliCertDerFile), + WOLFSSL_FATAL_ERROR); + + wolfSSL_free(ssl_s); + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_s); + wolfSSL_CTX_free(ctx_c); +#endif + return EXPECT_RESULT(); +} diff --git a/tests/api/test_ssl_cert.h b/tests/api/test_ssl_cert.h new file mode 100644 index 0000000000..ed459891e2 --- /dev/null +++ b/tests/api/test_ssl_cert.h @@ -0,0 +1,44 @@ +/* test_ssl_cert.h + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL 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. + * + * wolfSSL 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 TESTS_API_SSL_CERT_H +#define TESTS_API_SSL_CERT_H + +int test_wolfSSL_get_verify_mode(void); +int test_wolfSSL_CTX_get_verify_mode(void); +int test_wolfSSL_get_verify_callback(void); +int test_wolfSSL_CTX_get_extra_chain_certs(void); +int test_wolfSSL_get_peer_chain(void); +int test_wolfSSL_get_chain_X509(void); +int test_wolfSSL_get_chain_cert_pem(void); +int test_wolfSSL_cmp_peer_cert_to_file(void); + +#define TEST_SSL_CERT_DECLS \ + TEST_DECL_GROUP("ssl_cert", test_wolfSSL_get_verify_mode), \ + TEST_DECL_GROUP("ssl_cert", test_wolfSSL_CTX_get_verify_mode), \ + TEST_DECL_GROUP("ssl_cert", test_wolfSSL_get_verify_callback), \ + TEST_DECL_GROUP("ssl_cert", test_wolfSSL_CTX_get_extra_chain_certs), \ + TEST_DECL_GROUP("ssl_cert", test_wolfSSL_get_peer_chain), \ + TEST_DECL_GROUP("ssl_cert", test_wolfSSL_get_chain_X509), \ + TEST_DECL_GROUP("ssl_cert", test_wolfSSL_get_chain_cert_pem), \ + TEST_DECL_GROUP("ssl_cert", test_wolfSSL_cmp_peer_cert_to_file) + +#endif /* TESTS_API_SSL_CERT_H */ diff --git a/tests/api/test_ssl_ext.c b/tests/api/test_ssl_ext.c new file mode 100644 index 0000000000..9d0eda9868 --- /dev/null +++ b/tests/api/test_ssl_ext.c @@ -0,0 +1,688 @@ +/* test_ssl_ext.c + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL 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. + * + * wolfSSL 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 + +#ifdef NO_INLINE + #include +#else + #define WOLFSSL_MISC_INCLUDED + #include +#endif + +#include +#include + +#include +#include + +/* Tests for the TLS extension APIs in src/ssl_api_ext.c (moved from ssl.c). + * These cover functions not already exercised elsewhere in api.c. */ + +int test_wolfSSL_NoTicketTLSv12_ext(void) +{ + EXPECT_DECLS; +#if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_SERVER) && \ + (defined(NO_CERTS) || !defined(NO_RSA)) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + /* NULL arguments are rejected. */ + ExpectIntEQ(wolfSSL_CTX_NoTicketTLSv12(NULL), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_NoTicketTLSv12(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); + ExpectIntEQ(wolfSSL_CTX_NoTicketTLSv12(ctx), WOLFSSL_SUCCESS); +#ifndef NO_CERTS + /* A server WOLFSSL needs a key and certificate set on the context. */ + ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, CERT_FILETYPE), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile, + CERT_FILETYPE), WOLFSSL_SUCCESS); +#endif + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntEQ(wolfSSL_NoTicketTLSv12(ssl), WOLFSSL_SUCCESS); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_CTX_UseMaxFragment_ext(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MAX_FRAGMENT) && !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + + /* NULL context is rejected. */ + ExpectIntEQ(wolfSSL_CTX_UseMaxFragment(NULL, WOLFSSL_MFL_2_9), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectIntEQ(wolfSSL_CTX_UseMaxFragment(ctx, WOLFSSL_MFL_2_9), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_UseMaxFragment(ctx, WOLFSSL_MFL_2_12), + WOLFSSL_SUCCESS); + + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_CTX_num_tickets_ext(void) +{ + EXPECT_DECLS; +#if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TLS13) && \ + !defined(NO_WOLFSSL_SERVER) + WOLFSSL_CTX* ctx = NULL; + + /* NULL context: set fails, get returns zero. */ + ExpectIntEQ(wolfSSL_CTX_set_num_tickets(NULL, 5), WOLFSSL_FAILURE); + ExpectIntEQ((int)wolfSSL_CTX_get_num_tickets(NULL), 0); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); + ExpectIntEQ(wolfSSL_CTX_set_num_tickets(ctx, 3), WOLFSSL_SUCCESS); + ExpectIntEQ((int)wolfSSL_CTX_get_num_tickets(ctx), 3); + + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_set1_groups_ext(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && defined(HAVE_SUPPORTED_CURVES) && \ + !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + int dummy[1]; +#ifdef HAVE_ECC + int groups[1]; +#endif + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* A zero or too-large group count is rejected. */ + ExpectIntEQ(wolfSSL_CTX_set1_groups(ctx, dummy, 0), WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_CTX_set1_groups(ctx, dummy, + WOLFSSL_MAX_GROUP_COUNT + 1), WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_set1_groups(ssl, dummy, 0), WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_set1_groups(ssl, dummy, + WOLFSSL_MAX_GROUP_COUNT + 1), WOLFSSL_FAILURE); + +#ifdef HAVE_ECC + /* A valid named group succeeds. */ + groups[0] = WOLFSSL_ECC_SECP256R1; + ExpectIntEQ(wolfSSL_CTX_set1_groups(ctx, groups, 1), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set1_groups(ssl, groups, 1), WOLFSSL_SUCCESS); +#endif + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_set1_groups_list_ext(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && defined(HAVE_ECC) && defined(WOLFSSL_TLS13) && \ + defined(HAVE_SUPPORTED_CURVES) && !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + /* NULL arguments are rejected. */ + ExpectIntEQ(wolfSSL_CTX_set1_groups_list(NULL, "P-256"), WOLFSSL_FAILURE); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + ExpectIntEQ(wolfSSL_CTX_set1_groups_list(ctx, NULL), WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_set1_groups_list(ssl, NULL), WOLFSSL_FAILURE); + + /* A known group name succeeds. */ + ExpectIntEQ(wolfSSL_CTX_set1_groups_list(ctx, "P-256"), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set1_groups_list(ssl, "P-256"), WOLFSSL_SUCCESS); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_CTX_set_TicketHint_ext(void) +{ + EXPECT_DECLS; +#if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_SERVER) + WOLFSSL_CTX* ctx = NULL; + + ExpectIntEQ(wolfSSL_CTX_set_TicketHint(NULL, 100), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); + /* RFC 8446 caps the hint at 604800 seconds (7 days). */ + ExpectIntEQ(wolfSSL_CTX_set_TicketHint(ctx, -1), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_CTX_set_TicketHint(ctx, 604801), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_CTX_set_TicketHint(ctx, 0), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_set_TicketHint(ctx, 604800), WOLFSSL_SUCCESS); + + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_tlsext_max_fragment_length_ext(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && defined(HAVE_MAX_FRAGMENT) && \ + !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectIntEQ(wolfSSL_CTX_set_tlsext_max_fragment_length(NULL, + WOLFSSL_MFL_2_9), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* Modes outside the WOLFSSL_MFL_2_9..WOLFSSL_MFL_2_12 range are rejected. */ + ExpectIntEQ(wolfSSL_CTX_set_tlsext_max_fragment_length(ctx, + WOLFSSL_MFL_2_9 - 1), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_CTX_set_tlsext_max_fragment_length(ctx, + WOLFSSL_MFL_2_12 + 1), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_CTX_set_tlsext_max_fragment_length(ctx, + WOLFSSL_MFL_2_9), WOLFSSL_SUCCESS); + + ExpectIntEQ(wolfSSL_set_tlsext_max_fragment_length(NULL, WOLFSSL_MFL_2_9), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_set_tlsext_max_fragment_length(ssl, WOLFSSL_MFL_2_12), + WOLFSSL_SUCCESS); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_DisableExtendedMasterSecret_ext(void) +{ + EXPECT_DECLS; +#if defined(HAVE_EXTENDED_MASTER) && !defined(NO_WOLFSSL_CLIENT) && \ + !defined(NO_TLS) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectIntEQ(wolfSSL_CTX_DisableExtendedMasterSecret(NULL), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_DisableExtendedMasterSecret(NULL), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectIntEQ(wolfSSL_CTX_DisableExtendedMasterSecret(ctx), WOLFSSL_SUCCESS); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntEQ(wolfSSL_DisableExtendedMasterSecret(ssl), WOLFSSL_SUCCESS); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_set_tlsext_host_name_ext(void) +{ + EXPECT_DECLS; +#if (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) && defined(HAVE_SNI) && \ + !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + ExpectIntEQ(wolfSSL_set_tlsext_host_name(ssl, "localhost"), + WOLFSSL_SUCCESS); +#ifndef NO_WOLFSSL_SERVER + /* On the client the host name just set is returned. */ + ExpectStrEQ(wolfSSL_get_servername(ssl, WOLFSSL_SNI_HOST_NAME), + "localhost"); + ExpectNull(wolfSSL_get_servername(NULL, WOLFSSL_SNI_HOST_NAME)); +#endif + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_CTX_set_tlsext_servername_callback_ext(void) +{ + EXPECT_DECLS; +#if (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) && defined(HAVE_SNI) && \ + !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + + ExpectIntEQ(wolfSSL_CTX_set_tlsext_servername_callback(NULL, NULL), + WOLFSSL_FAILURE); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectIntEQ(wolfSSL_CTX_set_tlsext_servername_callback(ctx, NULL), + WOLFSSL_SUCCESS); + + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_set_tlsext_debug_arg_ext(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && defined(HAVE_PK_CALLBACKS) && \ + !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + int arg = 0; + + ExpectIntEQ(wolfSSL_set_tlsext_debug_arg(NULL, &arg), WOLFSSL_FAILURE); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntEQ(wolfSSL_set_tlsext_debug_arg(ssl, &arg), WOLFSSL_SUCCESS); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_set_SessionTicket_cb_ext(void) +{ + EXPECT_DECLS; +#if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectIntEQ(wolfSSL_set_SessionTicket_cb(NULL, NULL, NULL), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + ExpectIntEQ(wolfSSL_set_SessionTicket_cb(ssl, NULL, NULL), + WOLFSSL_SUCCESS); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_set1_curves_list_ext(void) +{ + EXPECT_DECLS; +#if (defined(OPENSSL_EXTRA) || defined(HAVE_CURL)) && \ + (defined(HAVE_ECC) || defined(HAVE_CURVE25519) || defined(HAVE_CURVE448)) \ + && !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* NULL object or list is rejected. */ + ExpectIntEQ(wolfSSL_set1_curves_list(NULL, "P-256"), WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_set1_curves_list(ssl, NULL), WOLFSSL_FAILURE); +#ifdef HAVE_ECC + ExpectIntEQ(wolfSSL_set1_curves_list(ssl, "P-256"), WOLFSSL_SUCCESS); +#endif + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_SecureResume_ext(void) +{ + EXPECT_DECLS; +#if defined(HAVE_SECURE_RENEGOTIATION) && !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectIntEQ(wolfSSL_SecureResume(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + /* Secure renegotiation has not been forced on, so resume is refused. */ + ExpectIntEQ(wolfSSL_SecureResume(ssl), + WC_NO_ERR_TRACE(SECURE_RENEGOTIATION_E)); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_CTX_UseSecureRenegotiation_ext(void) +{ + EXPECT_DECLS; +#if defined(HAVE_SERVER_RENEGOTIATION_INFO) && !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + + /* NULL context is rejected. */ + ExpectIntEQ(wolfSSL_CTX_UseSecureRenegotiation(NULL), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectIntEQ(wolfSSL_CTX_UseSecureRenegotiation(ctx), WOLFSSL_SUCCESS); + + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_next_proto_cb_ext(void) +{ + EXPECT_DECLS; +#if (defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || \ + defined(WOLFSSL_HAPROXY) || defined(HAVE_LIGHTY) || \ + defined(WOLFSSL_QUIC)) && defined(HAVE_ALPN) && \ + !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + const unsigned char* data = NULL; + unsigned int len = 0; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* These NPN APIs are no-op stubs for OpenSSL compatibility. Exercise + * them to confirm they accept NULL callbacks without crashing. */ + wolfSSL_CTX_set_next_protos_advertised_cb(ctx, NULL, NULL); + wolfSSL_CTX_set_next_proto_select_cb(ctx, NULL, NULL); + wolfSSL_get0_next_proto_negotiated(ssl, &data, &len); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_tlsext_status_exts_ids_ext(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && !defined(NO_WOLFSSL_STUB) && \ + !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* These status_request extension/id APIs are unimplemented stubs that + * always report failure. */ + ExpectIntEQ(wolfSSL_get_tlsext_status_exts(ssl, NULL), WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_set_tlsext_status_exts(ssl, NULL), WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_get_tlsext_status_ids(ssl, NULL), WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_set_tlsext_status_ids(ssl, NULL), WOLFSSL_FAILURE); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_SNI_GetFromBuffer_inval_ext(void) +{ + EXPECT_DECLS; +#if defined(HAVE_SNI) && !defined(NO_WOLFSSL_SERVER) && !defined(NO_TLS) + byte sni[32]; + word32 sniSz = (word32)sizeof(sni); + byte hello[8] = { 0 }; + + /* A NULL ClientHello buffer is rejected. */ + ExpectIntEQ(wolfSSL_SNI_GetFromBuffer(NULL, (word32)sizeof(hello), 0, sni, + &sniSz), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_UseTrustedCA_inval_ext(void) +{ + EXPECT_DECLS; +#if defined(HAVE_TRUSTED_CA) && !defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + const byte id[1] = { 0 }; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* The pre-agreed type must not carry an identifier. */ + ExpectIntEQ(wolfSSL_UseTrustedCA(ssl, WOLFSSL_TRUSTED_CA_PRE_AGREED, id, 1), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_UseMaxFragment_inval_ext(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MAX_FRAGMENT) && !defined(NO_WOLFSSL_CLIENT) && \ + !defined(NO_TLS) + /* A NULL object is rejected. */ + ExpectIntEQ(wolfSSL_UseMaxFragment(NULL, WOLFSSL_MFL_2_9), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_set1_groups_inval_ext(void) +{ + EXPECT_DECLS; +#if defined(HAVE_SUPPORTED_CURVES) && defined(OPENSSL_EXTRA) && \ + defined(HAVE_ECC) && !defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + int badGroups[1]; + + badGroups[0] = 0xFFFE; /* neither a named group nor a valid curve NID */ + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* An unrecognized group identifier is rejected. */ + ExpectIntEQ(wolfSSL_set1_groups(ssl, badGroups, 1), WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_CTX_set1_groups(ctx, badGroups, 1), WOLFSSL_FAILURE); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_UseALPN_inval_ext(void) +{ + EXPECT_DECLS; +#if defined(HAVE_ALPN) && !defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + char proto[] = "h2"; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* A protocol-list length beyond the maximum is rejected. */ + ExpectIntEQ(wolfSSL_UseALPN(ssl, proto, + (word32)(WOLFSSL_MAX_ALPN_NUMBER * WOLFSSL_MAX_ALPN_PROTO_NAME_LEN + + WOLFSSL_MAX_ALPN_NUMBER + 1), + WOLFSSL_ALPN_CONTINUE_ON_MISMATCH), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + /* No mismatch option set is rejected. */ + ExpectIntEQ(wolfSSL_UseALPN(ssl, proto, (word32)XSTRLEN(proto), 0), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_ALPN_GetPeerProtocol_inval_ext(void) +{ + EXPECT_DECLS; +#if defined(HAVE_ALPN) && !defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + char* list = NULL; + word16 listSz = 0; + + /* NULL arguments are rejected. */ + ExpectIntEQ(wolfSSL_ALPN_GetPeerProtocol(NULL, &list, &listSz), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_ALPN_FreePeerProtocol(NULL, &list), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* The peer has not offered any protocols yet. */ + ExpectIntEQ(wolfSSL_ALPN_GetPeerProtocol(ssl, &list, &listSz), + WC_NO_ERR_TRACE(BUFFER_ERROR)); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_CTX_set_TicketEncCb_inval_ext(void) +{ + EXPECT_DECLS; +#if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_SERVER) && \ + !defined(NO_TLS) + /* A NULL context is rejected. */ + ExpectIntEQ(wolfSSL_CTX_set_TicketEncCb(NULL, NULL), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_SessionTicket_inval_ext(void) +{ + EXPECT_DECLS; +#if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_CLIENT) && \ + !defined(NO_TLS) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + byte tick[8] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + byte out[8]; + word32 outSz; + byte big[4096]; + + XMEMSET(big, 0x5a, sizeof(big)); + + /* NULL object checks. */ + ExpectIntEQ(wolfSSL_UseSessionTicket(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_CTX_UseSessionTicket(NULL), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_set_SessionTicket(NULL, tick, (word32)sizeof(tick)), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* set: a non-zero size with a NULL buffer is rejected. */ + ExpectIntEQ(wolfSSL_set_SessionTicket(ssl, NULL, 4), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + /* get: NULL object and NULL buffer with non-zero size are rejected. */ + outSz = (word32)sizeof(out); + ExpectIntEQ(wolfSSL_get_SessionTicket(NULL, out, &outSz), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + outSz = (word32)sizeof(out); + ExpectIntEQ(wolfSSL_get_SessionTicket(ssl, NULL, &outSz), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* Store a short ticket (static-buffer path). */ + ExpectIntEQ(wolfSSL_set_SessionTicket(ssl, tick, (word32)sizeof(tick)), + WOLFSSL_SUCCESS); + /* Retrieving into a buffer that is too small reports zero length. */ + outSz = 2; + ExpectIntEQ(wolfSSL_get_SessionTicket(ssl, out, &outSz), WOLFSSL_SUCCESS); + ExpectIntEQ(outSz, 0); + + /* A ticket larger than the static buffer (SESSION_TICKET_LEN) uses + * dynamic storage; growing it again frees the previous allocation, and a + * later short ticket returns to the static buffer. */ + ExpectIntEQ(wolfSSL_set_SessionTicket(ssl, big, 3000), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_SessionTicket(ssl, big, 4000), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_SessionTicket(ssl, tick, (word32)sizeof(tick)), + WOLFSSL_SUCCESS); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_CTX_set_servername_arg_inval_ext(void) +{ + EXPECT_DECLS; +#if defined(HAVE_SNI) + /* A NULL context is rejected. */ + ExpectIntEQ(wolfSSL_CTX_set_servername_arg(NULL, NULL), WOLFSSL_FAILURE); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_CTX_set_alpn_protos_inval_ext(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && !defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS) + WOLFSSL_CTX* ctx = NULL; + const unsigned char protos[] = { 2, 'h', '2' }; +#if defined(WOLFSSL_ERROR_CODE_OPENSSL) + const int good = 0; +#else + const int good = WOLFSSL_SUCCESS; +#endif + + /* A NULL context is rejected. */ + ExpectIntEQ(wolfSSL_CTX_set_alpn_protos(NULL, protos, (unsigned int) + sizeof(protos)), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + /* Setting twice exercises the free-previous-list path. */ + ExpectIntEQ(wolfSSL_CTX_set_alpn_protos(ctx, protos, + (unsigned int)sizeof(protos)), good); + ExpectIntEQ(wolfSSL_CTX_set_alpn_protos(ctx, protos, + (unsigned int)sizeof(protos)), good); + + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} diff --git a/tests/api/test_ssl_ext.h b/tests/api/test_ssl_ext.h new file mode 100644 index 0000000000..ffb42f5fc8 --- /dev/null +++ b/tests/api/test_ssl_ext.h @@ -0,0 +1,92 @@ +/* test_ssl_ext.h + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL 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. + * + * wolfSSL 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 TESTS_API_SSL_EXT_H +#define TESTS_API_SSL_EXT_H + +int test_wolfSSL_NoTicketTLSv12_ext(void); +int test_wolfSSL_CTX_UseMaxFragment_ext(void); +int test_wolfSSL_CTX_num_tickets_ext(void); +int test_wolfSSL_set1_groups_ext(void); +int test_wolfSSL_set1_groups_list_ext(void); +int test_wolfSSL_CTX_set_TicketHint_ext(void); +int test_wolfSSL_tlsext_max_fragment_length_ext(void); +int test_wolfSSL_DisableExtendedMasterSecret_ext(void); +int test_wolfSSL_set_tlsext_host_name_ext(void); +int test_wolfSSL_CTX_set_tlsext_servername_callback_ext(void); +int test_wolfSSL_set_tlsext_debug_arg_ext(void); +int test_wolfSSL_set_SessionTicket_cb_ext(void); +int test_wolfSSL_set1_curves_list_ext(void); +int test_wolfSSL_SecureResume_ext(void); +int test_wolfSSL_CTX_UseSecureRenegotiation_ext(void); +int test_wolfSSL_next_proto_cb_ext(void); +int test_wolfSSL_tlsext_status_exts_ids_ext(void); +int test_wolfSSL_SNI_GetFromBuffer_inval_ext(void); +int test_wolfSSL_UseTrustedCA_inval_ext(void); +int test_wolfSSL_UseMaxFragment_inval_ext(void); +int test_wolfSSL_set1_groups_inval_ext(void); +int test_wolfSSL_UseALPN_inval_ext(void); +int test_wolfSSL_ALPN_GetPeerProtocol_inval_ext(void); +int test_wolfSSL_CTX_set_TicketEncCb_inval_ext(void); +int test_wolfSSL_SessionTicket_inval_ext(void); +int test_wolfSSL_CTX_set_servername_arg_inval_ext(void); +int test_wolfSSL_CTX_set_alpn_protos_inval_ext(void); + +#define TEST_SSL_EXT_DECLS \ + TEST_DECL_GROUP("ssl_ext", test_wolfSSL_NoTicketTLSv12_ext), \ + TEST_DECL_GROUP("ssl_ext", test_wolfSSL_CTX_UseMaxFragment_ext), \ + TEST_DECL_GROUP("ssl_ext", test_wolfSSL_CTX_num_tickets_ext), \ + TEST_DECL_GROUP("ssl_ext", test_wolfSSL_set1_groups_ext), \ + TEST_DECL_GROUP("ssl_ext", test_wolfSSL_set1_groups_list_ext), \ + TEST_DECL_GROUP("ssl_ext", test_wolfSSL_CTX_set_TicketHint_ext), \ + TEST_DECL_GROUP("ssl_ext", \ + test_wolfSSL_tlsext_max_fragment_length_ext), \ + TEST_DECL_GROUP("ssl_ext", \ + test_wolfSSL_DisableExtendedMasterSecret_ext), \ + TEST_DECL_GROUP("ssl_ext", test_wolfSSL_set_tlsext_host_name_ext), \ + TEST_DECL_GROUP("ssl_ext", \ + test_wolfSSL_CTX_set_tlsext_servername_callback_ext), \ + TEST_DECL_GROUP("ssl_ext", test_wolfSSL_set_tlsext_debug_arg_ext), \ + TEST_DECL_GROUP("ssl_ext", test_wolfSSL_set_SessionTicket_cb_ext), \ + TEST_DECL_GROUP("ssl_ext", test_wolfSSL_set1_curves_list_ext), \ + TEST_DECL_GROUP("ssl_ext", test_wolfSSL_SecureResume_ext), \ + TEST_DECL_GROUP("ssl_ext", \ + test_wolfSSL_CTX_UseSecureRenegotiation_ext), \ + TEST_DECL_GROUP("ssl_ext", test_wolfSSL_next_proto_cb_ext), \ + TEST_DECL_GROUP("ssl_ext", \ + test_wolfSSL_tlsext_status_exts_ids_ext), \ + TEST_DECL_GROUP("ssl_ext", \ + test_wolfSSL_SNI_GetFromBuffer_inval_ext), \ + TEST_DECL_GROUP("ssl_ext", test_wolfSSL_UseTrustedCA_inval_ext), \ + TEST_DECL_GROUP("ssl_ext", test_wolfSSL_UseMaxFragment_inval_ext), \ + TEST_DECL_GROUP("ssl_ext", test_wolfSSL_set1_groups_inval_ext), \ + TEST_DECL_GROUP("ssl_ext", test_wolfSSL_UseALPN_inval_ext), \ + TEST_DECL_GROUP("ssl_ext", \ + test_wolfSSL_ALPN_GetPeerProtocol_inval_ext), \ + TEST_DECL_GROUP("ssl_ext", \ + test_wolfSSL_CTX_set_TicketEncCb_inval_ext), \ + TEST_DECL_GROUP("ssl_ext", test_wolfSSL_SessionTicket_inval_ext), \ + TEST_DECL_GROUP("ssl_ext", \ + test_wolfSSL_CTX_set_servername_arg_inval_ext), \ + TEST_DECL_GROUP("ssl_ext", \ + test_wolfSSL_CTX_set_alpn_protos_inval_ext) + +#endif /* TESTS_API_SSL_EXT_H */ diff --git a/tests/api/test_ssl_pk.c b/tests/api/test_ssl_pk.c new file mode 100644 index 0000000000..a05f0cdbbe --- /dev/null +++ b/tests/api/test_ssl_pk.c @@ -0,0 +1,567 @@ +/* test_ssl_pk.c + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL 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. + * + * wolfSSL 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 + +#ifdef NO_INLINE + #include +#else + #define WOLFSSL_MISC_INCLUDED + #include +#endif + +#include +#include +#include + +#include +#include + +/* Tests for the public-key APIs in src/ssl_api_pk.c (moved from ssl.c). */ + +int test_wolfSSL_CTX_SetMinEccKey_Sz(void) +{ + EXPECT_DECLS; +#if defined(HAVE_ECC) && !defined(NO_WOLFSSL_SERVER) && !defined(NO_TLS) + WOLFSSL_CTX* ctx = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); + + /* NULL context and negative size are rejected. */ + ExpectIntEQ(wolfSSL_CTX_SetMinEccKey_Sz(NULL, 256), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_CTX_SetMinEccKey_Sz(ctx, -1), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* Multiple-of-8 and non-multiple-of-8 bit sizes both succeed. */ + ExpectIntEQ(wolfSSL_CTX_SetMinEccKey_Sz(ctx, 256), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_SetMinEccKey_Sz(ctx, 255), WOLFSSL_SUCCESS); + + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_SetMinEccKey_Sz(void) +{ + EXPECT_DECLS; +#if defined(HAVE_ECC) && !defined(NO_WOLFSSL_SERVER) && \ + (defined(NO_CERTS) || !defined(NO_RSA)) && !defined(NO_TLS) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); +#ifndef NO_CERTS + /* A server WOLFSSL needs a key and certificate set on the context. */ + ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, CERT_FILETYPE), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile, + CERT_FILETYPE), WOLFSSL_SUCCESS); +#endif + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* NULL object and negative size are rejected. */ + ExpectIntEQ(wolfSSL_SetMinEccKey_Sz(NULL, 256), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_SetMinEccKey_Sz(ssl, -1), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* Multiple-of-8 and non-multiple-of-8 bit sizes both succeed. */ + ExpectIntEQ(wolfSSL_SetMinEccKey_Sz(ssl, 256), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_SetMinEccKey_Sz(ssl, 255), WOLFSSL_SUCCESS); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_CTX_SetMinRsaKey_Sz(void) +{ + EXPECT_DECLS; +#if !defined(NO_RSA) && !defined(NO_WOLFSSL_SERVER) && !defined(NO_TLS) + WOLFSSL_CTX* ctx = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); + + /* NULL context, negative size and non-multiple-of-8 size are rejected. */ + ExpectIntEQ(wolfSSL_CTX_SetMinRsaKey_Sz(NULL, 2048), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_CTX_SetMinRsaKey_Sz(ctx, -8), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_CTX_SetMinRsaKey_Sz(ctx, 1001), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectIntEQ(wolfSSL_CTX_SetMinRsaKey_Sz(ctx, 2048), WOLFSSL_SUCCESS); + + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_SetMinRsaKey_Sz(void) +{ + EXPECT_DECLS; +#if !defined(NO_RSA) && !defined(NO_WOLFSSL_SERVER) && !defined(NO_TLS) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); +#ifndef NO_CERTS + /* A server WOLFSSL needs a key and certificate set on the context. */ + ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, CERT_FILETYPE), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile, + CERT_FILETYPE), WOLFSSL_SUCCESS); +#endif + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* NULL object, negative size and non-multiple-of-8 size are rejected. */ + ExpectIntEQ(wolfSSL_SetMinRsaKey_Sz(NULL, 2048), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_SetMinRsaKey_Sz(ssl, -8), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_SetMinRsaKey_Sz(ssl, 1001), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectIntEQ(wolfSSL_SetMinRsaKey_Sz(ssl, 2048), WOLFSSL_SUCCESS); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_SetEnableDhKeyTest(void) +{ + EXPECT_DECLS; +#if !defined(NO_DH) && !defined(WOLFSSL_OLD_PRIME_CHECK) && \ + !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ + !defined(NO_WOLFSSL_SERVER) && (defined(NO_CERTS) || !defined(NO_RSA)) && \ + !defined(NO_TLS) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); +#ifndef NO_CERTS + /* A server WOLFSSL needs a key and certificate set on the context. */ + ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, CERT_FILETYPE), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile, + CERT_FILETYPE), WOLFSSL_SUCCESS); +#endif + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* NULL object is rejected. */ + ExpectIntEQ(wolfSSL_SetEnableDhKeyTest(NULL, 1), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* Disable then enable the prime test. */ + ExpectIntEQ(wolfSSL_SetEnableDhKeyTest(ssl, 0), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_SetEnableDhKeyTest(ssl, 1), WOLFSSL_SUCCESS); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_CTX_SetMinDhKey_Sz(void) +{ + EXPECT_DECLS; +#if !defined(NO_DH) && !defined(NO_WOLFSSL_SERVER) && \ + (defined(NO_CERTS) || !defined(NO_RSA)) && !defined(NO_TLS) + WOLFSSL_CTX* ctx = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); + + /* NULL context, oversized and non-multiple-of-8 sizes are rejected. */ + ExpectIntEQ(wolfSSL_CTX_SetMinDhKey_Sz(NULL, 1024), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_CTX_SetMinDhKey_Sz(ctx, 16008), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_CTX_SetMinDhKey_Sz(ctx, 1001), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectIntEQ(wolfSSL_CTX_SetMinDhKey_Sz(ctx, 1024), WOLFSSL_SUCCESS); + + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_SetMinDhKey_Sz(void) +{ + EXPECT_DECLS; +#if !defined(NO_DH) && !defined(NO_WOLFSSL_SERVER) && \ + (defined(NO_CERTS) || !defined(NO_RSA)) && !defined(NO_TLS) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); +#ifndef NO_CERTS + /* A server WOLFSSL needs a key and certificate set on the context. */ + ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, CERT_FILETYPE), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile, + CERT_FILETYPE), WOLFSSL_SUCCESS); +#endif + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* NULL object, oversized and non-multiple-of-8 sizes are rejected. */ + ExpectIntEQ(wolfSSL_SetMinDhKey_Sz(NULL, 1024), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_SetMinDhKey_Sz(ssl, 16008), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_SetMinDhKey_Sz(ssl, 1001), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectIntEQ(wolfSSL_SetMinDhKey_Sz(ssl, 1024), WOLFSSL_SUCCESS); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_CTX_SetMaxDhKey_Sz(void) +{ + EXPECT_DECLS; +#if !defined(NO_DH) && !defined(NO_WOLFSSL_SERVER) && !defined(NO_TLS) + WOLFSSL_CTX* ctx = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); + + /* NULL context, oversized and non-multiple-of-8 sizes are rejected. */ + ExpectIntEQ(wolfSSL_CTX_SetMaxDhKey_Sz(NULL, 4096), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_CTX_SetMaxDhKey_Sz(ctx, 16008), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_CTX_SetMaxDhKey_Sz(ctx, 1001), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectIntEQ(wolfSSL_CTX_SetMaxDhKey_Sz(ctx, 4096), WOLFSSL_SUCCESS); + + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_SetMaxDhKey_Sz(void) +{ + EXPECT_DECLS; +#if !defined(NO_DH) && !defined(NO_WOLFSSL_SERVER) && \ + (defined(NO_CERTS) || !defined(NO_RSA)) && !defined(NO_TLS) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); +#ifndef NO_CERTS + /* A server WOLFSSL needs a key and certificate set on the context. */ + ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, CERT_FILETYPE), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile, + CERT_FILETYPE), WOLFSSL_SUCCESS); +#endif + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* NULL object, oversized and non-multiple-of-8 sizes are rejected. */ + ExpectIntEQ(wolfSSL_SetMaxDhKey_Sz(NULL, 4096), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_SetMaxDhKey_Sz(ssl, 16008), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_SetMaxDhKey_Sz(ssl, 1001), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectIntEQ(wolfSSL_SetMaxDhKey_Sz(ssl, 4096), WOLFSSL_SUCCESS); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_GetDhKey_Sz(void) +{ + EXPECT_DECLS; +#if !defined(NO_DH) && !defined(NO_WOLFSSL_SERVER) && \ + (defined(NO_CERTS) || !defined(NO_RSA)) && !defined(NO_TLS) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); +#ifndef NO_CERTS + /* A server WOLFSSL needs a key and certificate set on the context. */ + ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, CERT_FILETYPE), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile, + CERT_FILETYPE), WOLFSSL_SUCCESS); +#endif + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* NULL object is rejected. */ + ExpectIntEQ(wolfSSL_GetDhKey_Sz(NULL), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* Valid object returns the negotiated size (0 before a handshake). */ + ExpectIntGE(wolfSSL_GetDhKey_Sz(ssl), 0); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_get_privatekey(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && !defined(NO_WOLFSSL_STUB) + /* Stub for OpenSSL compatibility - always returns NULL. */ + ExpectNull(wolfSSL_get_privatekey(NULL)); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_get_signature_nid(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && !defined(NO_WOLFSSL_SERVER) && \ + (defined(NO_CERTS) || !defined(NO_RSA)) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + int nid = 0; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); +#ifndef NO_CERTS + /* A server WOLFSSL needs a key and certificate set on the context. */ + ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, CERT_FILETYPE), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile, + CERT_FILETYPE), WOLFSSL_SUCCESS); +#endif + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* NULL object or output pointer is rejected. */ + ExpectIntEQ(wolfSSL_get_signature_nid(NULL, &nid), WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_get_signature_nid(ssl, NULL), WOLFSSL_FAILURE); + + /* Valid object maps the hash algorithm to a NID. */ + ExpectIntEQ(wolfSSL_get_signature_nid(ssl, &nid), WOLFSSL_SUCCESS); + + /* Drive every hash-algorithm case (HashToNid). */ + if (EXPECT_SUCCESS()) { + static const byte hashAlgos[] = { + no_mac, md5_mac, sha_mac, sha224_mac, sha256_mac, sha384_mac, + sha512_mac, rmd_mac, blake2b_mac, sm3_mac + }; + size_t i; + + for (i = 0; i < sizeof(hashAlgos) / sizeof(hashAlgos[0]); i++) { + ssl->options.hashAlgo = hashAlgos[i]; + ExpectIntEQ(wolfSSL_get_signature_nid(ssl, &nid), WOLFSSL_SUCCESS); + } + /* An unknown hash algorithm is rejected. */ + ssl->options.hashAlgo = 0xFF; + ExpectIntEQ(wolfSSL_get_signature_nid(ssl, &nid), WOLFSSL_FAILURE); + } + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_get_signature_type_nid(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && !defined(NO_WOLFSSL_SERVER) && \ + (defined(NO_CERTS) || !defined(NO_RSA)) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + int nid = 0; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); +#ifndef NO_CERTS + /* A server WOLFSSL needs a key and certificate set on the context. */ + ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, CERT_FILETYPE), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile, + CERT_FILETYPE), WOLFSSL_SUCCESS); +#endif + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* NULL object or output pointer is rejected. */ + ExpectIntEQ(wolfSSL_get_signature_type_nid(NULL, &nid), WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_get_signature_type_nid(ssl, NULL), WOLFSSL_FAILURE); + + /* Valid object maps the signature algorithm to a NID. */ + ExpectIntEQ(wolfSSL_get_signature_type_nid(ssl, &nid), WOLFSSL_SUCCESS); + + /* Drive every signature-algorithm case (SaToNid). */ + if (EXPECT_SUCCESS()) { + static const byte okAlgos[] = { + anonymous_sa_algo, rsa_sa_algo, dsa_sa_algo, ecc_dsa_sa_algo, + ecc_brainpool_sa_algo, rsa_pss_sa_algo, rsa_pss_pss_algo, + falcon_level1_sa_algo, falcon_level5_sa_algo, mldsa_44_sa_algo, + mldsa_65_sa_algo, mldsa_87_sa_algo, sm2_sa_algo + }; + static const byte failAlgos[] = { invalid_sa_algo, any_sa_algo }; + size_t i; + + for (i = 0; i < sizeof(okAlgos) / sizeof(okAlgos[0]); i++) { + ssl->options.sigAlgo = okAlgos[i]; + ExpectIntEQ(wolfSSL_get_signature_type_nid(ssl, &nid), + WOLFSSL_SUCCESS); + } + /* Ed25519/Ed448 mappings depend on build configuration. */ + ssl->options.sigAlgo = ed25519_sa_algo; + #ifdef HAVE_ED25519 + ExpectIntEQ(wolfSSL_get_signature_type_nid(ssl, &nid), WOLFSSL_SUCCESS); + #else + ExpectIntEQ(wolfSSL_get_signature_type_nid(ssl, &nid), WOLFSSL_FAILURE); + #endif + ssl->options.sigAlgo = ed448_sa_algo; + #ifdef HAVE_ED448 + ExpectIntEQ(wolfSSL_get_signature_type_nid(ssl, &nid), WOLFSSL_SUCCESS); + #else + ExpectIntEQ(wolfSSL_get_signature_type_nid(ssl, &nid), WOLFSSL_FAILURE); + #endif + /* Unknown/placeholder algorithms are rejected. */ + for (i = 0; i < sizeof(failAlgos) / sizeof(failAlgos[0]); i++) { + ssl->options.sigAlgo = failAlgos[i]; + ExpectIntEQ(wolfSSL_get_signature_type_nid(ssl, &nid), + WOLFSSL_FAILURE); + } + } + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_get_peer_signature_nid(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && !defined(NO_WOLFSSL_SERVER) && \ + (defined(NO_CERTS) || !defined(NO_RSA)) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + int nid = 0; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); +#ifndef NO_CERTS + /* A server WOLFSSL needs a key and certificate set on the context. */ + ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, CERT_FILETYPE), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile, + CERT_FILETYPE), WOLFSSL_SUCCESS); +#endif + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* NULL object or output pointer is rejected. */ + ExpectIntEQ(wolfSSL_get_peer_signature_nid(NULL, &nid), WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_get_peer_signature_nid(ssl, NULL), WOLFSSL_FAILURE); + + /* Valid object maps the peer's hash algorithm to a NID. */ + ExpectIntEQ(wolfSSL_get_peer_signature_nid(ssl, &nid), WOLFSSL_SUCCESS); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_get_peer_signature_type_nid(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && !defined(NO_WOLFSSL_SERVER) && \ + (defined(NO_CERTS) || !defined(NO_RSA)) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + int nid = 0; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); +#ifndef NO_CERTS + /* A server WOLFSSL needs a key and certificate set on the context. */ + ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, CERT_FILETYPE), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile, + CERT_FILETYPE), WOLFSSL_SUCCESS); +#endif + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* NULL object or output pointer is rejected. */ + ExpectIntEQ(wolfSSL_get_peer_signature_type_nid(NULL, &nid), + WOLFSSL_FAILURE); + ExpectIntEQ(wolfSSL_get_peer_signature_type_nid(ssl, NULL), + WOLFSSL_FAILURE); + + /* Valid object maps the peer's signature algorithm to a NID. */ + ExpectIntEQ(wolfSSL_get_peer_signature_type_nid(ssl, &nid), + WOLFSSL_SUCCESS); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_SSL_CTX_set_tmp_ecdh(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && defined(HAVE_ECC) && !defined(NO_WOLFSSL_SERVER) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL_EC_KEY* ecdh = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); + ExpectNotNull(ecdh = wolfSSL_EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)); + + /* NULL context or key is rejected. */ + ExpectIntEQ(wolfSSL_SSL_CTX_set_tmp_ecdh(NULL, ecdh), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_SSL_CTX_set_tmp_ecdh(ctx, NULL), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* Valid key sets the curve. */ + ExpectIntEQ(wolfSSL_SSL_CTX_set_tmp_ecdh(ctx, ecdh), WOLFSSL_SUCCESS); + + wolfSSL_EC_KEY_free(ecdh); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +int test_wolfSSL_CTX_set_dh_auto(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && !defined(NO_WOLFSSL_SERVER) + WOLFSSL_CTX* ctx = NULL; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())); + + /* Compatibility stub - always succeeds. */ + ExpectIntEQ(wolfSSL_CTX_set_dh_auto(ctx, 0), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_set_dh_auto(ctx, 1), WOLFSSL_SUCCESS); + + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} diff --git a/tests/api/test_ssl_pk.h b/tests/api/test_ssl_pk.h new file mode 100644 index 0000000000..1a413bc926 --- /dev/null +++ b/tests/api/test_ssl_pk.h @@ -0,0 +1,62 @@ +/* test_ssl_pk.h + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL 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. + * + * wolfSSL 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 TESTS_API_SSL_PK_H +#define TESTS_API_SSL_PK_H + +int test_wolfSSL_CTX_SetMinEccKey_Sz(void); +int test_wolfSSL_SetMinEccKey_Sz(void); +int test_wolfSSL_CTX_SetMinRsaKey_Sz(void); +int test_wolfSSL_SetMinRsaKey_Sz(void); +int test_wolfSSL_SetEnableDhKeyTest(void); +int test_wolfSSL_CTX_SetMinDhKey_Sz(void); +int test_wolfSSL_SetMinDhKey_Sz(void); +int test_wolfSSL_CTX_SetMaxDhKey_Sz(void); +int test_wolfSSL_SetMaxDhKey_Sz(void); +int test_wolfSSL_GetDhKey_Sz(void); +int test_wolfSSL_get_privatekey(void); +int test_wolfSSL_get_signature_nid(void); +int test_wolfSSL_get_signature_type_nid(void); +int test_wolfSSL_get_peer_signature_nid(void); +int test_wolfSSL_get_peer_signature_type_nid(void); +int test_wolfSSL_SSL_CTX_set_tmp_ecdh(void); +int test_wolfSSL_CTX_set_dh_auto(void); + +#define TEST_SSL_PK_DECLS \ + TEST_DECL_GROUP("ssl_pk", test_wolfSSL_CTX_SetMinEccKey_Sz), \ + TEST_DECL_GROUP("ssl_pk", test_wolfSSL_SetMinEccKey_Sz), \ + TEST_DECL_GROUP("ssl_pk", test_wolfSSL_CTX_SetMinRsaKey_Sz), \ + TEST_DECL_GROUP("ssl_pk", test_wolfSSL_SetMinRsaKey_Sz), \ + TEST_DECL_GROUP("ssl_pk", test_wolfSSL_SetEnableDhKeyTest), \ + TEST_DECL_GROUP("ssl_pk", test_wolfSSL_CTX_SetMinDhKey_Sz), \ + TEST_DECL_GROUP("ssl_pk", test_wolfSSL_SetMinDhKey_Sz), \ + TEST_DECL_GROUP("ssl_pk", test_wolfSSL_CTX_SetMaxDhKey_Sz), \ + TEST_DECL_GROUP("ssl_pk", test_wolfSSL_SetMaxDhKey_Sz), \ + TEST_DECL_GROUP("ssl_pk", test_wolfSSL_GetDhKey_Sz), \ + TEST_DECL_GROUP("ssl_pk", test_wolfSSL_get_privatekey), \ + TEST_DECL_GROUP("ssl_pk", test_wolfSSL_get_signature_nid), \ + TEST_DECL_GROUP("ssl_pk", test_wolfSSL_get_signature_type_nid), \ + TEST_DECL_GROUP("ssl_pk", test_wolfSSL_get_peer_signature_nid), \ + TEST_DECL_GROUP("ssl_pk", test_wolfSSL_get_peer_signature_type_nid), \ + TEST_DECL_GROUP("ssl_pk", test_wolfSSL_SSL_CTX_set_tmp_ecdh), \ + TEST_DECL_GROUP("ssl_pk", test_wolfSSL_CTX_set_dh_auto) + +#endif /* TESTS_API_SSL_PK_H */ diff --git a/tests/api/test_tls.c b/tests/api/test_tls.c index ee2e112bfa..a0635675c0 100644 --- a/tests/api/test_tls.c +++ b/tests/api/test_tls.c @@ -54,6 +54,18 @@ int test_utils_memio_move_message(void) /* send server's flight */ ExpectIntEQ(wolfSSL_accept(ssl_s), -1); ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + /* If the server responded with a HelloRetryRequest it is waiting on a new + * ClientHello, so the buffered flight is just the HRR rather than the real + * ServerHello flight. Drive another connect/accept round so the message + * moving below operates on the real flight. */ + if (EXPECT_SUCCESS() && test_memio_msg_is_hello_retry_request(&test_ctx)) { + /* client processes HRR and sends second ClientHello */ + ExpectIntEQ(wolfSSL_connect(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + /* server processes second ClientHello and sends its flight */ + ExpectIntEQ(wolfSSL_accept(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + } /* Move messages around but they should be the same at the end */ ExpectIntEQ(test_memio_move_message(&test_ctx, 1, 1, 2), 0); ExpectIntEQ(test_memio_move_message(&test_ctx, 1, 2, 1), 0); @@ -389,6 +401,110 @@ int test_tls_certreq_order(void) return EXPECT_RESULT(); } +/* A TLS 1.2 CertificateRequest carrying a supported_signature_algorithms + * vector whose length is not a multiple of the 2-byte element size must be + * rejected. We run a real handshake, locate the server's CertificateRequest + * in the memio queue and make the sig-algs length odd before the client parses + * it. The vector is shrunk by one byte and the + * record, handshake and sig-algs length fields are all decremented so the + * message stays self-consistent (only the sig-algs length parity is wrong). + * Without the fix the client would silently ignore the odd trailing byte and + * accept the message; with the fix it is rejected with BUFFER_ERROR. */ +int test_tls12_certreq_odd_sigalgs(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \ + !defined(WOLFSSL_NO_TLS12) && !defined(NO_RSA) && defined(HAVE_ECC) && \ + !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + const char* msg = NULL; + int msgSz = 0; + int i = 0; + int certReqIdx = -1; + int certTypesCnt = 0; + int sigAlgsLenOff = 0; + int sigAlgsLen = 0; + int recAbs = 0; + int removeAbs = 0; + word32 val = 0; + byte* b = NULL; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0); + /* Make the server send a CertificateRequest. */ + wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_PEER, NULL); + /* Send each handshake message in its own record so the CertificateRequest + * can be located and tampered with individually. */ + ExpectIntEQ(wolfSSL_clear_group_messages(ssl_s), 1); + + /* Client sends ClientHello. */ + ExpectIntEQ(wolfSSL_connect(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + /* Server sends ServerHello..CertificateRequest..ServerHelloDone. */ + ExpectIntEQ(wolfSSL_accept(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + + /* Locate the CertificateRequest record in the server->client queue. */ + for (i = 0; test_memio_get_message(&test_ctx, 1, &msg, &msgSz, i) == 0; + i++) { + if (msgSz > 12 && (byte)msg[5] == certificate_request) { + certReqIdx = i; + break; + } + } + ExpectIntGE(certReqIdx, 0); + + if (EXPECT_SUCCESS()) { + /* Layout: record hdr[5] | hs hdr[4] | certTypesCount[1] | certTypes | + * sigAlgsLen[2] | certTypes... The sig-algs length is even; shrink the + * vector by one byte to make it odd while keeping all length fields + * consistent. */ + certTypesCnt = (byte)msg[9]; + sigAlgsLenOff = 10 + certTypesCnt; + ExpectIntLT(sigAlgsLenOff + 2, msgSz); + if (EXPECT_SUCCESS()) { + sigAlgsLen = ((byte)msg[sigAlgsLenOff] << 8) | + (byte)msg[sigAlgsLenOff + 1]; + /* Need at least two pairs so a valid pair remains after shrinking. */ + ExpectIntGE(sigAlgsLen, 2 * HELLO_EXT_SIGALGO_SZ); + } + if (EXPECT_SUCCESS()) { + b = (byte*)msg; + /* Decrement record length (bytes 3..4). */ + val = ((word32)b[3] << 8) | b[4]; + val--; + b[3] = (byte)(val >> 8); b[4] = (byte)val; + /* Decrement handshake length (bytes 6..8). */ + val = ((word32)b[6] << 16) | ((word32)b[7] << 8) | b[8]; + val--; + b[6] = (byte)(val >> 16); b[7] = (byte)(val >> 8); b[8] = (byte)val; + /* Decrement sig-algs length, making it odd. */ + val = (word32)sigAlgsLen - 1; + b[sigAlgsLenOff] = (byte)(val >> 8); + b[sigAlgsLenOff + 1] = (byte)val; + /* Drop the last byte of the sig-algs vector from the buffer. */ + recAbs = (int)((const byte*)msg - test_ctx.c_buff); + removeAbs = recAbs + 12 + certTypesCnt + sigAlgsLen - 1; + ExpectIntEQ(test_memio_remove_from_buffer(&test_ctx, 1, removeAbs, + 1), 0); + } + } + + /* Client must reject the malformed CertificateRequest. */ + ExpectIntEQ(wolfSSL_connect(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WC_NO_ERR_TRACE(BUFFER_ERROR)); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + #if !defined(WOLFSSL_NO_TLS12) && !defined(NO_RSA) && defined(HAVE_ECC) && \ !defined(NO_WOLFSSL_SERVER) && !defined(WOLFSSL_NO_CLIENT_AUTH) && \ !defined(NO_FILESYSTEM) @@ -769,6 +885,109 @@ int test_tls12_no_null_compression(void) return EXPECT_RESULT(); } +/* RFC 8422 Section 5.1.2: a client that sends an ec_point_formats extension + * omitting the uncompressed (0) format while negotiating an ECC suite must be + * rejected by the server with a fatal illegal_parameter alert. This drives a + * real handshake all the way through DoClientHello so the abort path (not just + * the parse-time detection) is exercised. + * + * Rather than hand-craft a ClientHello (which would pin the cipher suite, named + * group and exact byte offsets, making the test fragile as extension handling + * evolves), the client builds its own ClientHello and we only suppress the + * uncompressed point format: TLSX_PopulateExtensions() adds the default + * uncompressed format only when no ec_point_formats extension already exists, + * so pre-seeding the client with a compressed-only list makes it advertise + * exactly that. The curve is negotiated normally, so the test is independent of + * which named groups are enabled. */ +int test_tls12_ec_point_formats_no_uncompressed(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && !defined(WOLFSSL_NO_TLS12) \ + && defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES) \ + && defined(BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) + /* Pin an ECDHE (ECC) suite so the server negotiates an ECC key exchange; + * gating on the BUILD_ macro skips the test in builds where the suite is + * unavailable (e.g. --disable-aescbc) instead of failing with + * MATCH_SUITE_ERROR. */ + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0); + ExpectIntEQ(wolfSSL_set_cipher_list(ssl_c, "ECDHE-RSA-AES128-SHA"), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_cipher_list(ssl_s, "ECDHE-RSA-AES128-SHA"), + WOLFSSL_SUCCESS); + /* Make the client advertise only the compressed point format (1 == + * ansiX962_compressed_prime), i.e. omit the uncompressed (0) format. */ + ExpectIntEQ(TLSX_UsePointFormat(&ssl_c->extensions, 1, ssl_c->heap), + WOLFSSL_SUCCESS); + /* The server must reject the handshake with a fatal illegal_parameter + * alert (surfaced as INVALID_PARAMETER), not complete it. */ + ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(wolfSSL_get_error(ssl_s, WOLFSSL_FATAL_ERROR), + WC_NO_ERR_TRACE(INVALID_PARAMETER)); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + +/* RFC 8422 Section 5.1.2 ties the missing-uncompressed-format abort to the + * server actually negotiating an ECC cipher suite. A client that omits the + * uncompressed point format but negotiates a NON-ECC suite (here DHE_RSA) must + * NOT be rejected - the handshake completes. This is the complement of + * test_tls12_ec_point_formats_no_uncompressed and guards against regressing + * back to an advertised-groups (parse-time) abort. + * + * As in that test the client builds a real ClientHello and we only suppress the + * uncompressed point format (see the comment there); the suite is pinned to a + * DHE (non-ECC) suite. */ +int test_tls12_ec_point_formats_no_uncompressed_non_ecc(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && !defined(WOLFSSL_NO_TLS12) \ + && defined(HAVE_SUPPORTED_CURVES) && !defined(NO_DH) && defined(HAVE_FFDHE) \ + && !defined(NO_RSA) && defined(BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA) + /* The negotiated suite must be non-ECC for the missing format to be + * irrelevant. RFC 9325 / WOLFSSL_HARDEN_TLS disables all TLS_DHE_* suites + * (NO_TLS_DH); gating on the BUILD_ macro skips the test there rather than + * failing with MATCH_SUITE_ERROR. */ + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0); + ExpectIntEQ(wolfSSL_set_cipher_list(ssl_c, "DHE-RSA-AES128-SHA"), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_cipher_list(ssl_s, "DHE-RSA-AES128-SHA"), + WOLFSSL_SUCCESS); + /* Make the client advertise only the compressed point format (1 == + * ansiX962_compressed_prime), i.e. omit the uncompressed (0) format. */ + ExpectIntEQ(TLSX_UsePointFormat(&ssl_c->extensions, 1, ssl_c->heap), + WOLFSSL_SUCCESS); + /* The handshake must complete: the missing uncompressed format is + * irrelevant for a non-ECC (DHE) suite. */ + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + /* Sanity: the server really did observe a point-format list without the + * uncompressed format, yet proceeded. */ + ExpectIntEQ(ssl_s->options.peerNoUncompPF, 1); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + /* Test that set_curves_list correctly resolves ECC curve names that fall * through the kNistCurves table and reach the wc_ecc_get_curve_idx_from_name * fallback path. The kNistCurves lookup uses a case-sensitive XSTRNCMP, so @@ -906,6 +1125,381 @@ int test_tls_set_session_min_downgrade(void) return EXPECT_RESULT(); } +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \ + (!defined(WOLFSSL_NO_TLS12) || defined(WOLFSSL_TLS13)) && \ + defined(HAVE_SNI) && defined(HAVE_SESSION_TICKET) && \ + !defined(NO_SESSION_CACHE) +/* Accept-all SNI callback. */ +static int accept_any_sni_cb(WOLFSSL* ssl, int* ret, void* arg) +{ + (void)ssl; (void)ret; (void)arg; + return 0; /* accept */ +} +#endif + +/* TLS resumption must proceed with full handshake to establish new session if + * SNI/ALPN does not match previously established session. */ +int test_tls12_session_id_resumption_sni_mismatch(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \ + !defined(WOLFSSL_NO_TLS12) && defined(HAVE_SNI) && \ + defined(HAVE_SESSION_TICKET) && !defined(NO_SESSION_CACHE) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + WOLFSSL_SESSION *sess = NULL; + struct test_memio_ctx test_ctx; + const char* sniA = "public.example"; + const char* sniB = "admin.example"; + + /* Step 1: full TLS 1.2 handshake under SNI=public.example, with the + * session ticket path disabled so resumption can only happen via the + * server's session-ID cache. The server-side SNI callback ensures + * ssl->extensions retains the client's SNI in builds that don't + * compile in WOLFSSL_ALWAYS_KEEP_SNI. */ + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0); + wolfSSL_CTX_set_servername_callback(ctx_s, accept_any_sni_cb); + ExpectIntEQ(wolfSSL_NoTicketTLSv12(ssl_c), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_NoTicketTLSv12(ssl_s), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_UseSNI(ssl_c, WOLFSSL_SNI_HOST_NAME, + sniA, (word16)XSTRLEN(sniA)), WOLFSSL_SUCCESS); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + /* Sanity: the first handshake was not a resumption. */ + ExpectIntEQ(wolfSSL_session_reused(ssl_s), 0); + ExpectNotNull(sess = wolfSSL_get1_session(ssl_c)); + + wolfSSL_free(ssl_c); ssl_c = NULL; + wolfSSL_free(ssl_s); ssl_s = NULL; + + /* Step 2: new SSL objects on the SAME WOLFSSL_CTX (so the server's + * session cache still holds the entry from step 1). The client offers + * the saved session but advertises a *different* SNI. The server's + * cache lookup will match by session ID, but per RFC 6066 Section 3 the + * server MUST NOT resume because the SNI differs from the original. */ + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectNotNull(ssl_c = wolfSSL_new(ctx_c)); + wolfSSL_SetIOReadCtx(ssl_c, &test_ctx); + wolfSSL_SetIOWriteCtx(ssl_c, &test_ctx); + ExpectNotNull(ssl_s = wolfSSL_new(ctx_s)); + wolfSSL_SetIOReadCtx(ssl_s, &test_ctx); + wolfSSL_SetIOWriteCtx(ssl_s, &test_ctx); + ExpectIntEQ(wolfSSL_NoTicketTLSv12(ssl_c), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_NoTicketTLSv12(ssl_s), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_UseSNI(ssl_c, WOLFSSL_SNI_HOST_NAME, + sniB, (word16)XSTRLEN(sniB)), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + /* Post-fix expected behavior: server falls back to a full handshake + * because the SNI in the ClientHello does not match the SNI bound to + * the cached session. Pre-fix, the server silently resumes - which is + * the bug. Both sides should report no resumption. */ + ExpectIntEQ(wolfSSL_session_reused(ssl_s), 0); + ExpectIntEQ(wolfSSL_session_reused(ssl_c), 0); + + wolfSSL_SESSION_free(sess); + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + +/* TLS 1.3 PSK resumption must fall back to a full handshake if the SNI in + * the resumed ClientHello does not match the SNI bound to the original + * session (RFC 6066 Section 3 / RFC 8446 Section 4.6.1). */ +int test_tls13_session_resumption_sni_mismatch(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_TLS13) && \ + defined(HAVE_SNI) && defined(HAVE_SESSION_TICKET) && \ + !defined(NO_SESSION_CACHE) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + WOLFSSL_SESSION *sess = NULL; + struct test_memio_ctx test_ctx; + const char* sniA = "public.example"; + const char* sniB = "admin.example"; + byte readBuf[16]; + + /* Step 1: full TLS 1.3 handshake under SNI=public.example to obtain a + * session ticket. The server-side SNI callback ensures ssl->extensions + * retains the client's SNI in builds that don't compile in + * WOLFSSL_ALWAYS_KEEP_SNI. */ + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0); + wolfSSL_CTX_set_servername_callback(ctx_s, accept_any_sni_cb); + ExpectIntEQ(wolfSSL_UseSNI(ssl_c, WOLFSSL_SNI_HOST_NAME, + sniA, (word16)XSTRLEN(sniA)), WOLFSSL_SUCCESS); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + /* Sanity: the first handshake was not a resumption. */ + ExpectIntEQ(wolfSSL_session_reused(ssl_s), 0); + /* Drive the post-handshake NewSessionTicket through to the client so + * the saved session is a real resumption ticket. */ + ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + ExpectNotNull(sess = wolfSSL_get1_session(ssl_c)); + + wolfSSL_free(ssl_c); ssl_c = NULL; + wolfSSL_free(ssl_s); ssl_s = NULL; + + /* Step 2: new SSL objects on the SAME WOLFSSL_CTX (so the server's + * ticket key still matches). The client offers the saved session but + * advertises a *different* SNI. The server MUST NOT resume because the + * SNI differs from the original. */ + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectNotNull(ssl_c = wolfSSL_new(ctx_c)); + wolfSSL_SetIOReadCtx(ssl_c, &test_ctx); + wolfSSL_SetIOWriteCtx(ssl_c, &test_ctx); + ExpectNotNull(ssl_s = wolfSSL_new(ctx_s)); + wolfSSL_SetIOReadCtx(ssl_s, &test_ctx); + wolfSSL_SetIOWriteCtx(ssl_s, &test_ctx); + ExpectIntEQ(wolfSSL_UseSNI(ssl_c, WOLFSSL_SNI_HOST_NAME, + sniB, (word16)XSTRLEN(sniB)), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + /* Desired behavior: server falls back to a full handshake because the + * SNI in the ClientHello does not match the SNI bound to the cached + * ticket. Both sides should report no resumption. */ + ExpectIntEQ(wolfSSL_session_reused(ssl_s), 0); + ExpectIntEQ(wolfSSL_session_reused(ssl_c), 0); + + wolfSSL_SESSION_free(sess); + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + +/* Regression test for the post-ALPN_Select PSK-head check. + * When ALPN_Select runs before CheckPreSharedKeys (so the per-PSK + * binding check has the negotiated ALPN available), TLSX_SetALPN + * prepends a new ALPN entry to ssl->extensions, displacing the PSK + * extension from the head of the list. The "PSK was last in + * ClientHello" check therefore must run right after TLSX_Parse, + * not inside CheckPreSharedKeys. This test exercises that path + * (TLS 1.3 PSK resumption with ALPN, no SNI callback -- the grpc + * server scenario). */ +int test_tls13_resumption_with_alpn(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_TLS13) && \ + defined(HAVE_SNI) && defined(HAVE_ALPN) && defined(HAVE_SESSION_TICKET) && \ + !defined(NO_SESSION_CACHE) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + WOLFSSL_SESSION *sess = NULL; + struct test_memio_ctx test_ctx; + const char* sni = "foo.test.google.fr"; + const char alpn[] = "h2"; + byte readBuf[16]; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0); + ExpectIntEQ(wolfSSL_UseSNI(ssl_c, WOLFSSL_SNI_HOST_NAME, + sni, (word16)XSTRLEN(sni)), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_UseALPN(ssl_c, (char*)alpn, (word32)XSTRLEN(alpn), + WOLFSSL_ALPN_FAILED_ON_MISMATCH), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_UseALPN(ssl_s, (char*)alpn, (word32)XSTRLEN(alpn), + WOLFSSL_ALPN_FAILED_ON_MISMATCH), WOLFSSL_SUCCESS); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(wolfSSL_session_reused(ssl_s), 0); + ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + ExpectNotNull(sess = wolfSSL_get1_session(ssl_c)); + + wolfSSL_free(ssl_c); ssl_c = NULL; + wolfSSL_free(ssl_s); ssl_s = NULL; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectNotNull(ssl_c = wolfSSL_new(ctx_c)); + wolfSSL_SetIOReadCtx(ssl_c, &test_ctx); + wolfSSL_SetIOWriteCtx(ssl_c, &test_ctx); + ExpectNotNull(ssl_s = wolfSSL_new(ctx_s)); + wolfSSL_SetIOReadCtx(ssl_s, &test_ctx); + wolfSSL_SetIOWriteCtx(ssl_s, &test_ctx); + ExpectIntEQ(wolfSSL_UseSNI(ssl_c, WOLFSSL_SNI_HOST_NAME, + sni, (word16)XSTRLEN(sni)), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_UseALPN(ssl_c, (char*)alpn, (word32)XSTRLEN(alpn), + WOLFSSL_ALPN_FAILED_ON_MISMATCH), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_UseALPN(ssl_s, (char*)alpn, (word32)XSTRLEN(alpn), + WOLFSSL_ALPN_FAILED_ON_MISMATCH), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + ExpectIntEQ(wolfSSL_session_reused(ssl_s), 1); + ExpectIntEQ(wolfSSL_session_reused(ssl_c), 1); + + wolfSSL_SESSION_free(sess); + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + +/* TLS 1.2 stateful (session-ID) resumption must fall back to a full + * handshake if the ALPN protocol negotiated for the resumed connection + * does not match the ALPN bound to the original session. Mirrors + * test_tls12_session_id_resumption_sni_mismatch but varies ALPN instead + * of SNI. */ +int test_tls12_session_id_resumption_alpn_mismatch(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \ + !defined(WOLFSSL_NO_TLS12) && defined(HAVE_ALPN) && \ + defined(HAVE_SESSION_TICKET) && !defined(NO_SESSION_CACHE) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + WOLFSSL_SESSION *sess = NULL; + struct test_memio_ctx test_ctx; + const char alpnA[] = "h2"; + const char alpnB[] = "http/1.1"; + + /* Step 1: full TLS 1.2 handshake negotiating ALPN=h2, with the + * session ticket path disabled so resumption can only happen via the + * server's session-ID cache. The negotiated ALPN is retained on + * ssl->extensions by ALPN_Select, so SetupSession binds its hash to + * the cached session. */ + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0); + ExpectIntEQ(wolfSSL_NoTicketTLSv12(ssl_c), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_NoTicketTLSv12(ssl_s), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_UseALPN(ssl_c, (char*)alpnA, (word32)XSTRLEN(alpnA), + WOLFSSL_ALPN_FAILED_ON_MISMATCH), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_UseALPN(ssl_s, (char*)alpnA, (word32)XSTRLEN(alpnA), + WOLFSSL_ALPN_FAILED_ON_MISMATCH), WOLFSSL_SUCCESS); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + /* Sanity: the first handshake was not a resumption. */ + ExpectIntEQ(wolfSSL_session_reused(ssl_s), 0); + ExpectNotNull(sess = wolfSSL_get1_session(ssl_c)); + + wolfSSL_free(ssl_c); ssl_c = NULL; + wolfSSL_free(ssl_s); ssl_s = NULL; + + /* Step 2: new SSL objects on the SAME WOLFSSL_CTX (so the server's + * session cache still holds the entry from step 1). The client offers + * the saved session but both sides now advertise a *different* ALPN + * (http/1.1), so the handshake negotiates http/1.1. The server's cache + * lookup matches by session ID, but the server MUST NOT resume because + * the negotiated ALPN differs from the one bound to the original + * session. */ + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectNotNull(ssl_c = wolfSSL_new(ctx_c)); + wolfSSL_SetIOReadCtx(ssl_c, &test_ctx); + wolfSSL_SetIOWriteCtx(ssl_c, &test_ctx); + ExpectNotNull(ssl_s = wolfSSL_new(ctx_s)); + wolfSSL_SetIOReadCtx(ssl_s, &test_ctx); + wolfSSL_SetIOWriteCtx(ssl_s, &test_ctx); + ExpectIntEQ(wolfSSL_NoTicketTLSv12(ssl_c), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_NoTicketTLSv12(ssl_s), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_UseALPN(ssl_c, (char*)alpnB, (word32)XSTRLEN(alpnB), + WOLFSSL_ALPN_FAILED_ON_MISMATCH), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_UseALPN(ssl_s, (char*)alpnB, (word32)XSTRLEN(alpnB), + WOLFSSL_ALPN_FAILED_ON_MISMATCH), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + /* Expected behavior: server falls back to a full handshake because the + * negotiated ALPN does not match the ALPN bound to the cached session. + * Both sides should report no resumption. */ + ExpectIntEQ(wolfSSL_session_reused(ssl_s), 0); + ExpectIntEQ(wolfSSL_session_reused(ssl_c), 0); + + wolfSSL_SESSION_free(sess); + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + +/* TLS 1.3 PSK resumption must fall back to a full handshake if the ALPN + * protocol negotiated for the resumed connection does not match the ALPN + * bound to the original session. Mirrors + * test_tls13_session_resumption_sni_mismatch but varies ALPN instead of + * SNI. */ +int test_tls13_session_resumption_alpn_mismatch(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_TLS13) && \ + defined(HAVE_ALPN) && defined(HAVE_SESSION_TICKET) && \ + !defined(NO_SESSION_CACHE) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + WOLFSSL_SESSION *sess = NULL; + struct test_memio_ctx test_ctx; + const char alpnA[] = "h2"; + const char alpnB[] = "http/1.1"; + byte readBuf[16]; + + /* Step 1: full TLS 1.3 handshake negotiating ALPN=h2 to obtain a + * session ticket. The negotiated ALPN is retained on ssl->extensions + * by ALPN_Select and bound to the ticket. */ + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0); + ExpectIntEQ(wolfSSL_UseALPN(ssl_c, (char*)alpnA, (word32)XSTRLEN(alpnA), + WOLFSSL_ALPN_FAILED_ON_MISMATCH), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_UseALPN(ssl_s, (char*)alpnA, (word32)XSTRLEN(alpnA), + WOLFSSL_ALPN_FAILED_ON_MISMATCH), WOLFSSL_SUCCESS); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + /* Sanity: the first handshake was not a resumption. */ + ExpectIntEQ(wolfSSL_session_reused(ssl_s), 0); + /* Drive the post-handshake NewSessionTicket through to the client so + * the saved session is a real resumption ticket. */ + ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + ExpectNotNull(sess = wolfSSL_get1_session(ssl_c)); + + wolfSSL_free(ssl_c); ssl_c = NULL; + wolfSSL_free(ssl_s); ssl_s = NULL; + + /* Step 2: new SSL objects on the SAME WOLFSSL_CTX (so the server's + * ticket key still matches). The client offers the saved session but + * both sides now advertise a *different* ALPN (http/1.1). The server + * MUST NOT resume because the negotiated ALPN differs from the one + * bound to the original ticket. */ + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectNotNull(ssl_c = wolfSSL_new(ctx_c)); + wolfSSL_SetIOReadCtx(ssl_c, &test_ctx); + wolfSSL_SetIOWriteCtx(ssl_c, &test_ctx); + ExpectNotNull(ssl_s = wolfSSL_new(ctx_s)); + wolfSSL_SetIOReadCtx(ssl_s, &test_ctx); + wolfSSL_SetIOWriteCtx(ssl_s, &test_ctx); + ExpectIntEQ(wolfSSL_UseALPN(ssl_c, (char*)alpnB, (word32)XSTRLEN(alpnB), + WOLFSSL_ALPN_FAILED_ON_MISMATCH), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_UseALPN(ssl_s, (char*)alpnB, (word32)XSTRLEN(alpnB), + WOLFSSL_ALPN_FAILED_ON_MISMATCH), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + /* Expected behavior: server falls back to a full handshake because the + * negotiated ALPN does not match the ALPN bound to the cached ticket. + * Both sides should report no resumption. */ + ExpectIntEQ(wolfSSL_session_reused(ssl_s), 0); + ExpectIntEQ(wolfSSL_session_reused(ssl_c), 0); + + wolfSSL_SESSION_free(sess); + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + int test_tls_set_curves_list_ecc_fallback(void) { EXPECT_DECLS; @@ -1120,6 +1714,32 @@ int test_wolfSSL_alert_type_string(void) return EXPECT_RESULT(); } +int test_wolfSSL_get_shared_ciphers(void) +{ + EXPECT_DECLS; +#if !defined(NO_TLS) && !defined(NO_WOLFSSL_CLIENT) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + char buf[32]; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + ExpectNull(wolfSSL_get_shared_ciphers(NULL, buf, sizeof(buf))); + ExpectNull(wolfSSL_get_shared_ciphers(ssl, NULL, sizeof(buf))); + ExpectNull(wolfSSL_get_shared_ciphers(ssl, buf, 0)); +#ifndef NO_ERROR_STRINGS + ExpectPtrEq(wolfSSL_get_shared_ciphers(ssl, buf, sizeof(buf)), buf); +#else + ExpectNull(wolfSSL_get_shared_ciphers(ssl, buf, sizeof(buf))); +#endif + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + /* Test the TLS 1.2 peerAuthGood fail-safe checks directly on both sides. * The client branch sets NO_PEER_VERIFY; the server branch returns a generic * fatal error from TICKET_SENT before sending its Finished. */ @@ -1180,6 +1800,116 @@ int test_tls12_peerauth_failsafe(void) return EXPECT_RESULT(); } +/* TLS 1.2 mutual auth: an ECDHE-ECDSA server (ECDSA certificate) accepting an + * RSA client certificate. */ +int test_tls12_ecdhe_ecdsa_rsa_client_cert(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && !defined(WOLFSSL_NO_TLS12) \ + && defined(HAVE_ECC) && !defined(NO_RSA) && !defined(NO_SHA256) \ + && defined(HAVE_AESGCM) && defined(KEEP_PEER_CERT) \ + && !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) \ + && !defined(WOLFSSL_NO_CLIENT_AUTH) \ + && !defined(NO_FILESYSTEM) && !defined(NO_CERTS) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + WOLFSSL_X509* peer = NULL; + const char* cipher = "ECDHE-ECDSA-AES128-GCM-SHA256"; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0); + + /* Server: ECDSA certificate (=> ECDHE-ECDSA suite), require client + * authentication, and trust the (self-signed) RSA client certificate. */ + ExpectIntEQ(wolfSSL_use_certificate_file(ssl_s, eccCertFile, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_use_PrivateKey_file(ssl_s, eccKeyFile, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx_s, cliCertFile, NULL), + WOLFSSL_SUCCESS); + wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_PEER | + WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); + ExpectIntEQ(wolfSSL_set_cipher_list(ssl_s, cipher), WOLFSSL_SUCCESS); + + /* Client: RSA certificate/key, and trust the ECC CA that signed the + * server's ECDSA certificate. */ + ExpectIntEQ(wolfSSL_use_certificate_file(ssl_c, cliCertFile, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_use_PrivateKey_file(ssl_c, cliKeyFile, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx_c, caEccCertFile, NULL), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_cipher_list(ssl_c, cipher), WOLFSSL_SUCCESS); + + /* Mutual authentication completes and the server obtains the client's + * RSA certificate even though the negotiated suite is ECDHE-ECDSA. */ + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectStrEQ(wolfSSL_get_cipher_name(ssl_c), cipher); + ExpectNotNull(peer = wolfSSL_get_peer_certificate(ssl_s)); + wolfSSL_X509_free(peer); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + +/* TLS 1.2 mutual auth: an ECDHE-RSA server (RSA certificate) accepting an + * ECDSA client certificate. */ +int test_tls12_ecdhe_rsa_ecdsa_client_cert(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && !defined(WOLFSSL_NO_TLS12) \ + && defined(HAVE_ECC) && !defined(NO_RSA) && !defined(NO_SHA256) \ + && defined(HAVE_AESGCM) && defined(KEEP_PEER_CERT) \ + && !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) \ + && !defined(WOLFSSL_NO_CLIENT_AUTH) \ + && !defined(NO_FILESYSTEM) && !defined(NO_CERTS) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + WOLFSSL_X509* peer = NULL; + const char* cipher = "ECDHE-RSA-AES128-GCM-SHA256"; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0); + + /* Server: default RSA certificate (=> ECDHE-RSA), require client + * authentication, and trust the (self-signed) ECDSA client certificate. */ + ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx_s, cliEccCertFile, NULL), + WOLFSSL_SUCCESS); + wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_PEER | + WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); + ExpectIntEQ(wolfSSL_set_cipher_list(ssl_s, cipher), WOLFSSL_SUCCESS); + + /* Client: ECDSA certificate/key. The default client CTX already trusts + * the RSA CA that signed the server's certificate. */ + ExpectIntEQ(wolfSSL_use_certificate_file(ssl_c, cliEccCertFile, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_use_PrivateKey_file(ssl_c, cliEccKeyFile, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_cipher_list(ssl_c, cipher), WOLFSSL_SUCCESS); + + /* Mutual authentication completes and the server obtains the client's + * ECDSA certificate even though the negotiated suite is ECDHE-RSA. */ + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectStrEQ(wolfSSL_get_cipher_name(ssl_c), cipher); + ExpectNotNull(peer = wolfSSL_get_peer_certificate(ssl_s)); + wolfSSL_X509_free(peer); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + int test_wolfSSL_alert_desc_string(void) { EXPECT_DECLS; @@ -1219,3 +1949,202 @@ int test_wolfSSL_alert_desc_string(void) #endif return EXPECT_RESULT(); } + +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) +/* Cipher-name substrings that need extra setup (PSK callback, ECDSA cert, + * SRP, etc.) which the default test_memio_setup() doesn't provide. */ +static int record_size_skip_cipher(const char *name) +{ + /* "ECDH-" matches static-ECDH ciphers ("ECDH-RSA-*", "ECDH-ECDSA-*") + * and not ECDHE-* because of the trailing '-'. RENEGOTIATION-INFO is the + * TLS_EMPTY_RENEGOTIATION_INFO_SCSV signaling value, not a real cipher. */ + static const char* const deny[] = { + "PSK", "SRP", "ANON", "NULL", "ECDSA", "ECDH-", "SM", + "RENEGOTIATION-INFO" + }; + size_t i; + for (i = 0; i < XELEM_CNT(deny); i++) { + if (XSTRSTR(name, deny[i]) != NULL) + return 1; + } + return 0; +} + +/* Cross-check wolfssl_local_GetRecordSize() against BuildMessage(sizeOnly=1) + * with the cache cold, then call it a second time and assert both calls + * return the same size - that exercises the cached path for AEAD ciphers + * without duplicating the BuildMessage arithmetic. */ +static int record_size_check_ssl(WOLFSSL *ssl) +{ + EXPECT_DECLS; + static const int payloads[] = { 1, 16, 256, 1300, 4096 }; + size_t k; + + for (k = 0; k < XELEM_CNT(payloads); k++) { + int payloadSz = payloads[k]; + int expectedSz = BuildMessage(ssl, NULL, 0, NULL, payloadSz, + application_data, 0, 1, 0, CUR_ORDER); + int firstSz, secondSz; + + ssl->recordSzOverhead = 0; + firstSz = wolfssl_local_GetRecordSize(ssl, payloadSz, 1); + secondSz = wolfssl_local_GetRecordSize(ssl, payloadSz, 1); + ExpectIntEQ(firstSz, expectedSz); + ExpectIntEQ(secondSz, expectedSz); + } + return EXPECT_RESULT(); +} + +/* Returns 1 if `suite` is selectable for the given client/server method + * pair, 0 otherwise. wolfSSL rejects some ciphers for DTLS at + * set_cipher_list time (e.g. RFC 7465 forbids RC4 in DTLS); skip those + * silently rather than failing the cross-check. */ +static int record_size_cipher_selectable(method_provider client_method, + method_provider server_method, const char *suite) +{ + WOLFSSL_CTX *ctx_c = wolfSSL_CTX_new(client_method()); + WOLFSSL_CTX *ctx_s = wolfSSL_CTX_new(server_method()); + int ok = (ctx_c != NULL && ctx_s != NULL && + wolfSSL_CTX_set_cipher_list(ctx_c, suite) == WOLFSSL_SUCCESS && + wolfSSL_CTX_set_cipher_list(ctx_s, suite) == WOLFSSL_SUCCESS); + if (ctx_c) wolfSSL_CTX_free(ctx_c); + if (ctx_s) wolfSSL_CTX_free(ctx_s); + return ok; +} + +/* Run the cross-check on a memio pair using the given (de)multiplexing + * methods and cipher suite. Optionally enable DTLS-CID with peer CIDs of + * different sizes so the test covers CID-extended record framing. */ +static int record_size_run_pair(method_provider client_method, + method_provider server_method, const char *suite, int useCid) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + + (void)useCid; + if (!record_size_cipher_selectable(client_method, server_method, suite)) + return TEST_SUCCESS; /* not valid for this protocol -- skip */ + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + test_ctx.c_ciphers = test_ctx.s_ciphers = suite; + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + client_method, server_method), 0); +#ifdef WOLFSSL_DTLS_CID + if (useCid) { + /* Different sizes on each side to exercise asymmetric framing. */ + static unsigned char client_cid[] = { 1, 2, 3, 4, 5, 6 }; + static unsigned char server_cid[] = { 7, 8, 9 }; + ExpectIntEQ(wolfSSL_dtls_cid_use(ssl_c), 1); + ExpectIntEQ(wolfSSL_dtls_cid_set(ssl_c, server_cid, + sizeof(server_cid)), 1); + ExpectIntEQ(wolfSSL_dtls_cid_use(ssl_s), 1); + ExpectIntEQ(wolfSSL_dtls_cid_set(ssl_s, client_cid, + sizeof(client_cid)), 1); + } +#endif + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 30, NULL), 0); + ExpectIntEQ(record_size_check_ssl(ssl_c), TEST_SUCCESS); + ExpectIntEQ(record_size_check_ssl(ssl_s), TEST_SUCCESS); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return EXPECT_RESULT(); +} +#endif /* HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES */ + +int test_record_size_matches_build_message(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) + const CipherSuiteInfo *suites = GetCipherNames(); + int n = GetCipherNamesSize(); + int i; + + for (i = 0; i < n; i++) { + const char *name = suites[i].name; + /* Names prefixed "TLS13-" are TLS 1.3 suites regardless of + * cipherSuite0, which may be either TLS13_BYTE or ECC_BYTE (for + * the integrity-only TLS_SHA*_SHA* suites). */ + int isTls13 = (XSTRNCMP(name, "TLS13-", 6) == 0); + if (record_size_skip_cipher(name)) + continue; + + if (isTls13) { +#ifdef WOLFSSL_TLS13 + ExpectIntEQ(record_size_run_pair(wolfTLSv1_3_client_method, + wolfTLSv1_3_server_method, name, 0), TEST_SUCCESS); +#endif +#ifdef WOLFSSL_DTLS13 + ExpectIntEQ(record_size_run_pair(wolfDTLSv1_3_client_method, + wolfDTLSv1_3_server_method, name, 0), TEST_SUCCESS); +#if defined(WOLFSSL_DTLS_CID) + ExpectIntEQ(record_size_run_pair(wolfDTLSv1_3_client_method, + wolfDTLSv1_3_server_method, name, 1), TEST_SUCCESS); +#endif +#endif + } + else { +#ifndef WOLFSSL_NO_TLS12 + ExpectIntEQ(record_size_run_pair(wolfTLSv1_2_client_method, + wolfTLSv1_2_server_method, name, 0), TEST_SUCCESS); +#endif +#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) + ExpectIntEQ(record_size_run_pair(wolfDTLSv1_2_client_method, + wolfDTLSv1_2_server_method, name, 0), TEST_SUCCESS); +#if defined(WOLFSSL_DTLS_CID) + ExpectIntEQ(record_size_run_pair(wolfDTLSv1_2_client_method, + wolfDTLSv1_2_server_method, name, 1), TEST_SUCCESS); +#endif +#endif + } + } +#endif /* HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES */ + return EXPECT_RESULT(); +} + +int test_record_size_cache_invalidated_on_renegotiation(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \ + defined(HAVE_SECURE_RENEGOTIATION) && !defined(WOLFSSL_NO_TLS12) && \ + defined(BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + byte readBuf[16]; + int sz; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0); + ExpectIntEQ(wolfSSL_UseSecureRenegotiation(ssl_c), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_UseSecureRenegotiation(ssl_s), WOLFSSL_SUCCESS); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + sz = wolfssl_local_GetRecordSize(ssl_c, 256, 1); + ExpectIntEQ(sz, BuildMessage(ssl_c, NULL, 0, NULL, 256, + application_data, 0, 1, 0, CUR_ORDER)); + ExpectIntNE(ssl_c->recordSzOverhead, 0); + + ExpectIntEQ(wolfSSL_Rehandshake(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + /* SetKeysSide() during renegotiation must have cleared the cache. */ + sz = wolfssl_local_GetRecordSize(ssl_c, 256, 1); + ExpectIntEQ(sz, BuildMessage(ssl_c, NULL, 0, NULL, 256, + application_data, 0, 1, 0, CUR_ORDER)); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} diff --git a/tests/api/test_tls.h b/tests/api/test_tls.h index fb796244d7..79d6f18dc8 100644 --- a/tests/api/test_tls.h +++ b/tests/api/test_tls.h @@ -29,15 +29,28 @@ int test_tls12_curve_intersection(void); int test_tls12_dhe_rsa_pss_sigalg(void); int test_tls13_curve_intersection(void); int test_tls_certreq_order(void); +int test_tls12_certreq_odd_sigalgs(void); int test_tls12_bad_cv_sig_alg(void); int test_tls12_no_null_compression(void); +int test_tls12_ec_point_formats_no_uncompressed(void); +int test_tls12_ec_point_formats_no_uncompressed_non_ecc(void); int test_tls12_etm_failed_resumption(void); int test_tls_set_session_min_downgrade(void); +int test_tls12_session_id_resumption_sni_mismatch(void); +int test_tls13_session_resumption_sni_mismatch(void); +int test_tls13_resumption_with_alpn(void); +int test_tls12_session_id_resumption_alpn_mismatch(void); +int test_tls13_session_resumption_alpn_mismatch(void); int test_tls_set_curves_list_ecc_fallback(void); int test_tls12_corrupted_finished(void); int test_tls12_peerauth_failsafe(void); +int test_tls12_ecdhe_ecdsa_rsa_client_cert(void); +int test_tls12_ecdhe_rsa_ecdsa_client_cert(void); int test_wolfSSL_alert_type_string(void); int test_wolfSSL_alert_desc_string(void); +int test_record_size_matches_build_message(void); +int test_record_size_cache_invalidated_on_renegotiation(void); +int test_wolfSSL_get_shared_ciphers(void); #define TEST_TLS_DECLS \ TEST_DECL_GROUP("tls", test_utils_memio_move_message), \ @@ -47,14 +60,29 @@ int test_wolfSSL_alert_desc_string(void); TEST_DECL_GROUP("tls", test_tls12_dhe_rsa_pss_sigalg), \ TEST_DECL_GROUP("tls", test_tls13_curve_intersection), \ TEST_DECL_GROUP("tls", test_tls_certreq_order), \ + TEST_DECL_GROUP("tls", test_tls12_certreq_odd_sigalgs), \ TEST_DECL_GROUP("tls", test_tls12_bad_cv_sig_alg), \ TEST_DECL_GROUP("tls", test_tls12_no_null_compression), \ + TEST_DECL_GROUP("tls", test_tls12_ec_point_formats_no_uncompressed), \ + TEST_DECL_GROUP("tls", \ + test_tls12_ec_point_formats_no_uncompressed_non_ecc), \ TEST_DECL_GROUP("tls", test_tls12_etm_failed_resumption), \ TEST_DECL_GROUP("tls", test_tls_set_session_min_downgrade), \ + TEST_DECL_GROUP("tls", test_tls12_session_id_resumption_sni_mismatch), \ + TEST_DECL_GROUP("tls", test_tls13_session_resumption_sni_mismatch), \ + TEST_DECL_GROUP("tls", test_tls13_resumption_with_alpn), \ + TEST_DECL_GROUP("tls", test_tls12_session_id_resumption_alpn_mismatch),\ + TEST_DECL_GROUP("tls", test_tls13_session_resumption_alpn_mismatch), \ TEST_DECL_GROUP("tls", test_tls_set_curves_list_ecc_fallback), \ TEST_DECL_GROUP("tls", test_tls12_corrupted_finished), \ TEST_DECL_GROUP("tls", test_tls12_peerauth_failsafe), \ + TEST_DECL_GROUP("tls", test_tls12_ecdhe_ecdsa_rsa_client_cert), \ + TEST_DECL_GROUP("tls", test_tls12_ecdhe_rsa_ecdsa_client_cert), \ TEST_DECL_GROUP("tls", test_wolfSSL_alert_type_string), \ - TEST_DECL_GROUP("tls", test_wolfSSL_alert_desc_string) + TEST_DECL_GROUP("tls", test_wolfSSL_alert_desc_string), \ + TEST_DECL_GROUP("tls", test_record_size_matches_build_message), \ + TEST_DECL_GROUP("tls", \ + test_record_size_cache_invalidated_on_renegotiation), \ + TEST_DECL_GROUP("tls", test_wolfSSL_get_shared_ciphers) #endif /* TESTS_API_TEST_TLS_H */ diff --git a/tests/api/test_tls13.c b/tests/api/test_tls13.c index ca37fb48cc..24950cb6d5 100644 --- a/tests/api/test_tls13.c +++ b/tests/api/test_tls13.c @@ -93,7 +93,10 @@ int test_tls13_apis(void) #endif #if defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES) int groups[2] = { WOLFSSL_ECC_SECP256R1, -#ifdef WOLFSSL_HAVE_MLKEM +#if defined(WOLFSSL_HAVE_MLKEM) && \ + !defined(WOLFSSL_MLKEM_NO_MAKE_KEY) && \ + !defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) && \ + !defined(WOLFSSL_MLKEM_NO_DECAPSULATE) #ifdef WOLFSSL_MLKEM_KYBER #ifndef WOLFSSL_NO_KYBER512 WOLFSSL_KYBER_LEVEL1 @@ -589,6 +592,9 @@ int test_tls13_apis(void) WOLFSSL_MAX_GROUP_COUNT + 1), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wolfSSL_CTX_set_groups(clientCtx, groups, numGroups), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_set_groups(clientCtx, groups, -1), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(clientCtx->numGroups, numGroups); ExpectIntEQ(wolfSSL_CTX_set_groups(clientCtx, bad_groups, numGroups), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); #endif @@ -616,6 +622,9 @@ int test_tls13_apis(void) WOLFSSL_MAX_GROUP_COUNT + 1), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wolfSSL_set_groups(clientSsl, groups, numGroups), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_groups(clientSsl, groups, -1), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(clientSsl->numGroups, numGroups); ExpectIntEQ(wolfSSL_set_groups(clientSsl, bad_groups, numGroups), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); #endif @@ -645,6 +654,20 @@ int test_tls13_apis(void) WOLFSSL_MAX_GROUP_COUNT + 1), WC_NO_ERR_TRACE(WOLFSSL_FAILURE)); ExpectIntEQ(wolfSSL_set1_groups(clientSsl, too_many_groups, WOLFSSL_MAX_GROUP_COUNT + 1), WC_NO_ERR_TRACE(WOLFSSL_FAILURE)); + ExpectIntEQ(wolfSSL_CTX_set1_groups(clientCtx, NULL, 1), + WC_NO_ERR_TRACE(WOLFSSL_FAILURE)); + ExpectIntEQ(wolfSSL_set1_groups(clientSsl, NULL, 1), + WC_NO_ERR_TRACE(WOLFSSL_FAILURE)); + ExpectIntEQ(wolfSSL_CTX_set1_groups(clientCtx, groups, numGroups), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_set1_groups(clientCtx, groups, -1), + WC_NO_ERR_TRACE(WOLFSSL_FAILURE)); + ExpectIntEQ(clientCtx->numGroups, numGroups); + ExpectIntEQ(wolfSSL_set1_groups(clientSsl, groups, numGroups), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set1_groups(clientSsl, groups, -1), + WC_NO_ERR_TRACE(WOLFSSL_FAILURE)); + ExpectIntEQ(clientSsl->numGroups, numGroups); #endif #ifndef NO_WOLFSSL_CLIENT #ifndef WOLFSSL_NO_TLS12 @@ -1775,6 +1798,162 @@ int test_tls13_bad_psk_binder(void) } +#if defined(WOLFSSL_TLS13) && \ + defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES_BUILD) && \ + !defined(NO_PSK) +static unsigned int test_tls13_psk_no_cert_client_cb(WOLFSSL* ssl, + const char* hint, char* identity, unsigned int id_max_len, + unsigned char* key, unsigned int key_max_len) +{ + (void)ssl; + (void)hint; + (void)key_max_len; + + /* Offer a PSK so the client sends a pre_shared_key extension. */ + XSTRNCPY(identity, "Client_identity", id_max_len); + key[0] = 0x20; + return 1; +} + +static unsigned int test_tls13_psk_no_cert_server_cb(WOLFSSL* ssl, + const char* id, unsigned char* key, unsigned int key_max_len) +{ + (void)ssl; + (void)id; + (void)key; + (void)key_max_len; + + /* Reject every identity so the server finds no matching PSK. */ + return 0; +} +#endif + +/* When no offered PSK matches and the server has no certificate to fall back + * to, the server must abort the handshake with BAD_BINDER rather than silently + * continuing. This covers both configurations: + * - NO_CERTS defined: the certificate fall-back branch is compiled out. + * - certificates compiled in but none loaded: ssl->buffers.certificate is + * NULL, so the runtime check takes the same abort path. + * The contexts are built by hand (no certificate loaded) so the test exercises + * whichever branch the build provides. + * When certificates are compiled in, a second connection sets a certificate + * and key against the server context and verifies the opposite branch: the + * non-matching PSK is ignored and the handshake falls back to a full + * certificate handshake instead of aborting. */ +int test_tls13_psk_no_cert_bad_binder(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_TLS13) && \ + defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES_BUILD) && \ + !defined(NO_PSK) + WOLFSSL_CTX *ctx_c = NULL; + WOLFSSL_CTX *ctx_s = NULL; + WOLFSSL *ssl_c = NULL; + WOLFSSL *ssl_s = NULL; + struct test_memio_ctx test_ctx; + WOLFSSL_ALERT_HISTORY h; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + /* Don't use test_memio_setup(): it loads a default server certificate, + * which would let the server fall back to a certificate handshake. Build + * the contexts by hand so the server has no certificate loaded. */ + ExpectNotNull(ctx_c = wolfSSL_CTX_new(wolfTLSv1_3_client_method())); + ExpectNotNull(ctx_s = wolfSSL_CTX_new(wolfTLSv1_3_server_method())); + if (ctx_c != NULL) { + wolfSSL_SetIORecv(ctx_c, test_memio_read_cb); + wolfSSL_SetIOSend(ctx_c, test_memio_write_cb); + } + if (ctx_s != NULL) { + wolfSSL_SetIORecv(ctx_s, test_memio_read_cb); + wolfSSL_SetIOSend(ctx_s, test_memio_write_cb); + } + + /* Set the PSK callbacks on the contexts, not the SSL objects: with + * certificates compiled in, creating a server-side SSL object without a + * certificate and key fails (NO_PRIVATE_KEY) unless ctx->havePSK is + * already set when wolfSSL_new() is called. */ + wolfSSL_CTX_set_psk_client_callback(ctx_c, + test_tls13_psk_no_cert_client_cb); + wolfSSL_CTX_set_psk_server_callback(ctx_s, + test_tls13_psk_no_cert_server_cb); + + ExpectNotNull(ssl_c = wolfSSL_new(ctx_c)); + ExpectNotNull(ssl_s = wolfSSL_new(ctx_s)); + if (ssl_c != NULL) { + wolfSSL_SetIOWriteCtx(ssl_c, &test_ctx); + wolfSSL_SetIOReadCtx(ssl_c, &test_ctx); + } + if (ssl_s != NULL) { + wolfSSL_SetIOWriteCtx(ssl_s, &test_ctx); + wolfSSL_SetIOReadCtx(ssl_s, &test_ctx); + } + + /* Confirm the precondition: the server really has no certificate. */ +#ifndef NO_CERTS + if (ssl_s != NULL) { + ExpectNull(ssl_s->buffers.certificate); + } +#endif + + /* Client sends ClientHello (with PSK) and waits for the response. */ + ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_get_error(ssl_c, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)), + WOLFSSL_ERROR_WANT_READ); + + /* Server processes ClientHello: no PSK matches and no certificate is + * available, so it must abort with BAD_BINDER. */ + ExpectIntNE(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_get_error(ssl_s, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)), + WC_NO_ERR_TRACE(BAD_BINDER)); + + /* Client reads the server's alert: BAD_BINDER maps to a fatal + * illegal_parameter alert (see TranslateErrorToAlert). */ + ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_get_error(ssl_c, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)), + WC_NO_ERR_TRACE(FATAL_ERROR)); + ExpectIntEQ(wolfSSL_get_alert_history(ssl_c, &h), WOLFSSL_SUCCESS); + ExpectIntEQ(h.last_rx.code, illegal_parameter); + ExpectIntEQ(h.last_rx.level, alert_fatal); + + wolfSSL_free(ssl_c); + ssl_c = NULL; + wolfSSL_CTX_free(ctx_c); + ctx_c = NULL; + wolfSSL_free(ssl_s); + ssl_s = NULL; + wolfSSL_CTX_free(ctx_s); + ctx_s = NULL; + +#ifndef NO_CERTS + /* Conversely, with a certificate and key set against the server context, + * a non-matching PSK must not leak the mismatch: the server ignores the + * PSK and falls back to a full certificate handshake. test_memio_setup() + * loads the default CA, server certificate and key. */ + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0); + + wolfSSL_set_psk_client_callback(ssl_c, test_tls13_psk_no_cert_client_cb); + wolfSSL_set_psk_server_callback(ssl_s, test_tls13_psk_no_cert_server_cb); + + /* Confirm the precondition: the server has a certificate this time. */ + if (ssl_s != NULL) { + ExpectNotNull(ssl_s->buffers.certificate); + } + + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_s); +#endif /* !NO_CERTS */ +#endif + return EXPECT_RESULT(); +} + + #if defined(HAVE_RPK) && !defined(NO_TLS) && !defined(NO_WOLFSSL_CLIENT) && \ !defined(NO_WOLFSSL_SERVER) @@ -4542,6 +4721,129 @@ int test_tls13_plaintext_alert(void) wolfSSL_free(ssl); wolfSSL_CTX_free(ctx); + ssl = NULL; + ctx = NULL; + + /* Negative test: a plaintext alert must NOT be ignored once the peer has + * responded with an encrypted handshake message. Complete a handshake so + * the peer is encrypting, then feed the client a plaintext alert. */ +#if !defined(NO_WOLFSSL_CLIENT) && !defined(NO_FILESYSTEM) + { + WOLFSSL_CTX* ctx_c = NULL; + WOLFSSL_CTX* ctx_s = NULL; + WOLFSSL* ssl_c = NULL; + WOLFSSL* ssl_s = NULL; + struct test_memio_ctx test_ctx; + /* Plaintext alert record: fatal (2), handshake_failure (40). */ + byte ptAlert[] = { 0x15, 0x03, 0x03, 0x00, 0x02, 0x02, 0x28 }; + char data[16]; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + /* Drop any post-handshake data (e.g. session tickets) queued for the + * client and feed it only the plaintext alert. */ + test_memio_clear_buffer(&test_ctx, 1); + ExpectIntEQ(test_memio_inject_message(&test_ctx, 1, (const char*)ptAlert, + (int)sizeof(ptAlert)), 0); + + /* Plaintext alert is rejected as the peer is encrypting. */ + ExpectIntLT(wolfSSL_read(ssl_c, data, (int)sizeof(data)), 0); + ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR), + WC_NO_ERR_TRACE(PARSE_ERROR)); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + } + + /* Negative test (server): a plaintext alert must NOT be ignored once the + * client has sent an encrypted handshake message, even before the + * handshake is complete. Use client authentication so that the client + * sends an encrypted Certificate message before Finished. */ + { + WOLFSSL_CTX* ctx_c = NULL; + WOLFSSL_CTX* ctx_s = NULL; + WOLFSSL* ssl_c = NULL; + WOLFSSL* ssl_s = NULL; + struct test_memio_ctx test_ctx; + /* Plaintext alert record: fatal (2), handshake_failure (40). */ + byte ptAlert[] = { 0x15, 0x03, 0x03, 0x00, 0x02, 0x02, 0x28 }; + int end = 0; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0); + /* Server requires a client certificate. */ + ExpectTrue(wolfSSL_CTX_load_verify_locations(ctx_s, cliCertFile, + NULL) == WOLFSSL_SUCCESS); + if (EXPECT_SUCCESS()) { + wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_PEER | + WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); + } + ExpectTrue(wolfSSL_use_certificate_file(ssl_c, cliCertFile, + CERT_FILETYPE) == WOLFSSL_SUCCESS); + ExpectTrue(wolfSSL_use_PrivateKey_file(ssl_c, cliKeyFile, + CERT_FILETYPE) == WOLFSSL_SUCCESS); + + /* Client Hello. */ + ExpectIntEQ(wolfSSL_connect(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + /* Server flight including CertificateRequest. */ + ExpectIntEQ(wolfSSL_accept(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + /* Client flight: [CCS,] Certificate, CertificateVerify, Finished. */ + ExpectIntEQ(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS); + + /* Find the end of the first encrypted record (outer content type + * application_data) the client sent - the Certificate message. */ + while (end + 5 <= test_ctx.s_len) { + byte recType = test_ctx.s_buff[end]; + end += 5 + ((test_ctx.s_buff[end + 3] << 8) | + test_ctx.s_buff[end + 4]); + if (recType == 0x17) + break; + } + ExpectIntLE(end, test_ctx.s_len); + ExpectIntGT(end, 0); + /* Remove the records after it (CertificateVerify and Finished), + * working backwards a message at a time. */ + while (EXPECT_SUCCESS() && test_ctx.s_len > end) { + int i; + int msgOff = 0; + + for (i = 0; i < test_ctx.s_msg_count - 1; i++) + msgOff += test_ctx.s_msg_sizes[i]; + if (msgOff >= end) { + /* Last message is wholly after the Certificate record. */ + ExpectIntEQ(test_memio_drop_message(&test_ctx, 0, + test_ctx.s_msg_count - 1), 0); + } + else { + /* Last message also holds the records to keep. */ + ExpectIntEQ(test_memio_remove_from_buffer(&test_ctx, 0, end, + test_ctx.s_len - end), 0); + } + } + /* Follow the encrypted Certificate message with a plaintext alert. */ + ExpectIntEQ(test_memio_inject_message(&test_ctx, 0, + (const char*)ptAlert, (int)sizeof(ptAlert)), 0); + + /* Plaintext alert is rejected as the client has sent an encrypted + * handshake message. */ + ExpectIntEQ(wolfSSL_accept(ssl_s), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, WOLFSSL_FATAL_ERROR), + WC_NO_ERR_TRACE(PARSE_ERROR)); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + } +#endif #else /* Fail on plaintext alert when encryption keys on. */ @@ -4847,7 +5149,7 @@ int test_tls13_derive_keys_no_key(void) * heap use-after-free during cleanup. A malicious server sends * SECP256R1MLKEM768 with only 10 bytes of key exchange data (expected: 1120+). * This exercises the error path in TLSX_KeyShare_ProcessPqcHybridClient(). - * Under ASAN the UAF manifests as ForceZero writing to freed KyberKey memory + * Under ASAN the UAF manifests as ForceZero writing to freed MlKemKey memory * during wolfSSL_free -> TLSX_FreeAll -> TLSX_KeyShare_FreeAll. */ #if defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_CLIENT) && \ defined(WOLFSSL_HAVE_MLKEM) && defined(WOLFSSL_PQC_HYBRIDS) && \ @@ -4944,7 +5246,7 @@ int test_tls13_pqc_hybrid_truncated_keyshare(void) WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)); /* The UAF, if present, triggers here: wolfSSL_free -> TLSX_FreeAll -> - * TLSX_KeyShare_FreeAll -> ForceZero on already-freed KyberKey. */ + * TLSX_KeyShare_FreeAll -> ForceZero on already-freed MlKemKey. */ wolfSSL_free(ssl); wolfSSL_CTX_free(ctx); #endif @@ -5348,6 +5650,7 @@ int test_tls13_corrupted_finished(void) WOLFSSL *ssl_c = NULL; WOLFSSL *ssl_s = NULL; struct test_memio_ctx test_ctx; + int ret; XMEMSET(&test_ctx, 0, sizeof(test_ctx)); ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, @@ -5365,7 +5668,29 @@ int test_tls13_corrupted_finished(void) /* Step 3: Client processes server flight, verifies server Finished, * sends client Finished */ - ExpectIntEQ(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS); + ret = wolfSSL_connect(ssl_c); + if (ret == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) { + /* Actually: Server sent HelloRetryRequest */ + ExpectIntEQ(wolfSSL_get_error(ssl_s, WOLFSSL_FATAL_ERROR), + WOLFSSL_ERROR_WANT_READ); + + /* Step 1: Client sends ClientHello */ + ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR), + WOLFSSL_ERROR_WANT_READ); + + /* Step 2: Server processes CH, sends SH + EE + Cert + CV + Finished */ + ExpectIntNE(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_get_error(ssl_s, WOLFSSL_FATAL_ERROR), + WOLFSSL_ERROR_WANT_READ); + + /* Step 3: Client processes server flight, verifies server Finished, + * sends client Finished */ + ExpectIntEQ(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS); + } + else { + ExpectIntEQ(ret, WOLFSSL_SUCCESS); + } /* Corrupt the server's client_write_MAC_secret so that when it computes * the expected Finished HMAC, the result won't match the client's actual @@ -5448,7 +5773,20 @@ int test_tls13_peerauth_failsafe(void) ExpectIntNE(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS); ExpectIntEQ(wolfSSL_get_error(ssl_s, WOLFSSL_FATAL_ERROR), WOLFSSL_ERROR_WANT_READ); - ExpectIntEQ(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS); + ret = wolfSSL_connect(ssl_c); + if (ret == WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)) { + /* HelloRetryRequest sent by server. */ + ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR), + WOLFSSL_ERROR_WANT_READ); + ExpectIntNE(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_get_error(ssl_s, WOLFSSL_FATAL_ERROR), + WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS); + } + else { + ExpectIntEQ(ret, WOLFSSL_SUCCESS); + } ssl_s->options.peerAuthGood = 0; ret = wolfSSL_accept(ssl_s); @@ -6090,6 +6428,16 @@ static int test_tls13_cipher_fuzz_once(WC_RNG* rng, ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); ExpectIntNE(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS); ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + /* The default groups can lead the server to respond with a + * HelloRetryRequest, in which case it is waiting on a new ClientHello and + * has not yet sent any encrypted record. Drive another connect/accept round + * so the buffers hold the real flight before fuzzing. */ + if (EXPECT_SUCCESS() && test_memio_msg_is_hello_retry_request(&test_ctx)) { + ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntNE(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + } if (side == 1) { ExpectIntEQ(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS); buf = test_ctx.s_buff; diff --git a/tests/api/test_tls13.h b/tests/api/test_tls13.h index e01527f0e0..984b89372d 100644 --- a/tests/api/test_tls13.h +++ b/tests/api/test_tls13.h @@ -63,6 +63,7 @@ int test_tls13_post_handshake_auth_no_ext(void); int test_tls13_post_handshake_auth_late_allow(void); int test_tls13_downgrade_sentinel(void); int test_tls13_serverhello_bad_cipher_suites(void); +int test_tls13_psk_no_cert_bad_binder(void); int test_tls13_cert_with_extern_psk_apis(void); int test_tls13_cert_with_extern_psk_handshake(void); int test_tls13_cert_with_extern_psk_requires_key_share(void); @@ -122,6 +123,7 @@ int test_tls13_AEAD_limit_KU_aes128_ccm_8_sha256(void); TEST_DECL_GROUP("tls13", test_tls13_post_handshake_auth_late_allow), \ TEST_DECL_GROUP("tls13", test_tls13_downgrade_sentinel), \ TEST_DECL_GROUP("tls13", test_tls13_serverhello_bad_cipher_suites), \ + TEST_DECL_GROUP("tls13", test_tls13_psk_no_cert_bad_binder), \ TEST_DECL_GROUP("tls13", test_tls13_cert_with_extern_psk_apis), \ TEST_DECL_GROUP("tls13", test_tls13_cert_with_extern_psk_handshake), \ TEST_DECL_GROUP("tls13", test_tls13_cert_with_extern_psk_requires_key_share), \ diff --git a/tests/api/test_tls_ext.c b/tests/api/test_tls_ext.c index 294fa9c903..781042a4ce 100644 --- a/tests/api/test_tls_ext.c +++ b/tests/api/test_tls_ext.c @@ -1033,3 +1033,210 @@ int test_TLSX_SRTP_msg_type_validation(void) #endif return EXPECT_RESULT(); } + +/* RFC 7301 Section 3.1: the server's ProtocolNameList in its ALPN response + * MUST contain exactly one ProtocolName. A ServerHello carrying two entries + * must be rejected rather than silently accepted. */ +int test_TLSX_ALPN_server_response_count(void) +{ + EXPECT_DECLS; +#if defined(HAVE_ALPN) && !defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS) && \ + !defined(WOLFSSL_NO_TLS12) + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + /* ServerHello-style ALPN extension whose ProtocolNameList contains + * two entries ("h2" and "http/1.1"). */ + static const byte extBytes[] = { + 0x00, 0x10, /* extension type = ALPN (16) */ + 0x00, 0x0E, /* extension length = 14 */ + 0x00, 0x0C, /* ProtocolNameList length */ + 0x02, 'h', '2', /* entry 1: "h2" */ + 0x08, 'h', 't', 't', 'p', '/', '1', '.', '1' /* entry 2 */ + }; + static char alpn_h2[] = "h2"; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + ExpectIntEQ(wolfSSL_UseALPN(ssl, alpn_h2, (unsigned int)XSTRLEN(alpn_h2), + WOLFSSL_ALPN_FAILED_ON_MISMATCH), + WOLFSSL_SUCCESS); + + ExpectIntEQ(TLSX_Parse(ssl, extBytes, (word16)sizeof(extBytes), + server_hello, NULL), + WC_NO_ERR_TRACE(BUFFER_ERROR)); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + +/* Regression test for the supported_groups (a.k.a. supported curves) parsing. + * + * A client that explicitly sends a supported_groups extension restricts the + * groups the server may use. An empty list, or a list that contains only + * groups the server does not support, must NOT be silently treated as if the + * extension was absent (which would impose no restriction and let the server + * pick an ECDHE suite/curve the client never advertised). + * + * - An empty named group list is malformed and must be rejected. + * - A list of only-unsupported groups must still leave a supported_groups + * node behind so suite selection sees the restriction. + */ +int test_TLSX_SupportedCurve_empty_or_unsupported(void) +{ + EXPECT_DECLS; +#if !defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS) && \ + defined(HAVE_SUPPORTED_CURVES) && !defined(WOLFSSL_NO_TLS12) && \ + (!defined(NO_WOLFSSL_SERVER) || (defined(WOLFSSL_TLS13) && \ + !defined(WOLFSSL_NO_SERVER_GROUPS_EXT))) + /* This exercises the server's parsing of a received ClientHello: the + * relevant code path (TLSX_SupportedCurve_Parse) is selected by the + * message type passed to TLSX_Parse (client_hello => isRequest), not by + * the side of the WOLFSSL object. A client-side WOLFSSL is used purely as + * the parse vehicle because creating a server-side WOLFSSL would require a + * certificate to be loaded first (NO_PRIVATE_KEY otherwise). */ + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + Suites* suites = NULL; + /* supported_groups (0x000a), ext len 0x0002, named_group_list len 0x0000 */ + const byte emptyList[] = { 0x00, 0x0a, 0x00, 0x02, 0x00, 0x00 }; + /* supported_groups (0x000a), ext len 0x0004, list len 0x0002, + * group 0xeeee (private-use value we do not support) */ + const byte unsupportedOnly[] = { 0x00, 0x0a, 0x00, 0x04, 0x00, 0x02, + 0xee, 0xee }; + + /* An empty named group list is malformed and must be rejected. */ + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + if (ssl != NULL) + suites = (Suites*)WOLFSSL_SUITES(ssl); + ExpectIntEQ(TLSX_Parse(ssl, emptyList, (word16)sizeof(emptyList), + client_hello, suites), + WC_NO_ERR_TRACE(BUFFER_ERROR)); + wolfSSL_free(ssl); + ssl = NULL; + + /* A list with only unsupported groups must still record a supported_groups + * node so that ECC/ECDHE suite selection sees the (now empty) restriction + * instead of treating the extension as absent. */ + ExpectNotNull(ssl = wolfSSL_new(ctx)); + if (ssl != NULL) + suites = (Suites*)WOLFSSL_SUITES(ssl); + /* Precondition: server has not preconfigured supported groups. */ + ExpectNull(TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS)); + ExpectIntEQ(TLSX_Parse(ssl, unsupportedOnly, (word16)sizeof(unsupportedOnly), + client_hello, suites), 0); + /* The fix records an (empty) supported_groups node. */ + ExpectNotNull(TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS)); + wolfSSL_free(ssl); + ssl = NULL; + + wolfSSL_CTX_free(ctx); + +#if defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_CLIENT) + /* An empty named group list is equally malformed in a TLS 1.3 + * EncryptedExtensions message (named_group_list<2..2^16-1>) and must be + * rejected with the same decode_error (BUFFER_ERROR), not silently + * accepted as the server advertising no groups. */ + { + WOLFSSL_CTX* ctx13 = NULL; + WOLFSSL* ssl13 = NULL; + const byte emptyListEE[] = { 0x00, 0x0a, 0x00, 0x02, 0x00, 0x00 }; + + ExpectNotNull(ctx13 = wolfSSL_CTX_new(wolfTLSv1_3_client_method())); + ExpectNotNull(ssl13 = wolfSSL_new(ctx13)); + /* Ensure the connection is treated as TLS 1.3 so EncryptedExtensions + * is a valid context for the extension. */ + if (ssl13 != NULL) { + ssl13->version.major = SSLv3_MAJOR; + ssl13->version.minor = TLSv1_3_MINOR; + } + ExpectIntEQ(TLSX_Parse(ssl13, emptyListEE, (word16)sizeof(emptyListEE), + encrypted_extensions, NULL), + WC_NO_ERR_TRACE(BUFFER_ERROR)); + wolfSSL_free(ssl13); + wolfSSL_CTX_free(ctx13); + } +#endif +#endif + return EXPECT_RESULT(); +} + +/* RFC 8422 Section 5.1.2: a client that sends the ec_point_formats extension + * MUST include the uncompressed (0) point format. When the uncompressed format + * is omitted the server records this (ssl->options.peerNoUncompPF) during + * parsing so the handshake can be aborted with an illegal_parameter alert if + * the client also advertised ECC named groups. + * + * - A list that contains the uncompressed format must clear the flag. + * - A list that omits the uncompressed format must set the flag. + */ +int test_TLSX_PointFormat_uncompressed_required(void) +{ + EXPECT_DECLS; +#if !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \ + !defined(NO_TLS) && defined(HAVE_SUPPORTED_CURVES) && \ + defined(HAVE_TLS_EXTENSIONS) && !defined(WOLFSSL_NO_TLS12) + /* This exercises the server's parsing of a received ClientHello: the + * relevant code path (TLSX_PointFormat_Parse) is selected by the message + * type passed to TLSX_Parse (client_hello => isRequest), not by the side + * of the WOLFSSL object. A client-side WOLFSSL is used purely as the parse + * vehicle because creating a server-side WOLFSSL would require a + * certificate to be loaded first (NO_PRIVATE_KEY otherwise). The server + * build is required because TLSX_PointFormat_Parse (the PF_PARSE dispatch + * macro) is compiled to a no-op when NO_WOLFSSL_SERVER is defined. */ + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + Suites* suites = NULL; + /* ec_point_formats (0x000b), ext len 0x0002, list len 0x01, + * format 0x00 (uncompressed) */ + const byte withUncomp[] = { 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00 }; + /* ec_point_formats (0x000b), ext len 0x0002, list len 0x01, + * format 0x01 (ansiX962_compressed_prime, uncompressed omitted) */ + const byte noUncomp[] = { 0x00, 0x0b, 0x00, 0x02, 0x01, 0x01 }; + /* As above but with two compressed formats and no uncompressed. */ + const byte noUncomp2[] = { 0x00, 0x0b, 0x00, 0x03, 0x02, 0x01, 0x02 }; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method())); + + /* A list containing the uncompressed format leaves the flag clear and + * still adds the uncompressed format to the response. */ + ExpectNotNull(ssl = wolfSSL_new(ctx)); + if (ssl != NULL) + suites = (Suites*)WOLFSSL_SUITES(ssl); + ExpectIntEQ(TLSX_Parse(ssl, withUncomp, (word16)sizeof(withUncomp), + client_hello, suites), 0); + if (ssl != NULL) + ExpectIntEQ(ssl->options.peerNoUncompPF, 0); + ExpectNotNull(TLSX_Find(ssl->extensions, TLSX_EC_POINT_FORMATS)); + wolfSSL_free(ssl); + ssl = NULL; + + /* A single-entry list that omits the uncompressed format sets the flag. */ + ExpectNotNull(ssl = wolfSSL_new(ctx)); + if (ssl != NULL) + suites = (Suites*)WOLFSSL_SUITES(ssl); + ExpectIntEQ(TLSX_Parse(ssl, noUncomp, (word16)sizeof(noUncomp), + client_hello, suites), 0); + if (ssl != NULL) + ExpectIntEQ(ssl->options.peerNoUncompPF, 1); + wolfSSL_free(ssl); + ssl = NULL; + + /* A multi-entry list that omits the uncompressed format sets the flag. */ + ExpectNotNull(ssl = wolfSSL_new(ctx)); + if (ssl != NULL) + suites = (Suites*)WOLFSSL_SUITES(ssl); + ExpectIntEQ(TLSX_Parse(ssl, noUncomp2, (word16)sizeof(noUncomp2), + client_hello, suites), 0); + if (ssl != NULL) + ExpectIntEQ(ssl->options.peerNoUncompPF, 1); + wolfSSL_free(ssl); + ssl = NULL; + + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} diff --git a/tests/api/test_tls_ext.h b/tests/api/test_tls_ext.h index e9d07d81ec..00499de3b0 100644 --- a/tests/api/test_tls_ext.h +++ b/tests/api/test_tls_ext.h @@ -36,5 +36,8 @@ int test_TLSX_TCA_Find(void); int test_TLSX_SNI_GetSize_overflow(void); int test_TLSX_ECH_msg_type_validation(void); int test_TLSX_SRTP_msg_type_validation(void); +int test_TLSX_ALPN_server_response_count(void); +int test_TLSX_SupportedCurve_empty_or_unsupported(void); +int test_TLSX_PointFormat_uncompressed_required(void); #endif /* TESTS_API_TEST_TLS_EMS_H */ diff --git a/tests/api/test_x509.c b/tests/api/test_x509.c index 7a16b9616b..61ae6b705c 100644 --- a/tests/api/test_x509.c +++ b/tests/api/test_x509.c @@ -647,7 +647,7 @@ int test_x509_CertFromX509_akid_overflow(void) EXPECT_DECLS; #if defined(WOLFSSL_AKID_NAME) && defined(WOLFSSL_CERT_GEN) && \ defined(WOLFSSL_CERT_EXT) && !defined(NO_BIO) && \ - (defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL)) + (defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL)) && defined(HAVE_ECC) /* DER builder helpers -- write into a flat buffer */ #ifdef WOLFSSL_SMALL_STACK unsigned char* buf = NULL; diff --git a/tests/suites.c b/tests/suites.c index 337c169e0f..d6dd4fa44b 100644 --- a/tests/suites.c +++ b/tests/suites.c @@ -214,7 +214,8 @@ static int IsKyberLevelAvailable(const char* line) #endif #endif /* WOLFSSL_TLS_NO_MLKEM_STANDALONE */ #ifdef WOLFSSL_PQC_HYBRIDS - #if !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_ECC) + #if !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_ECC) && \ + (!defined(WOLFSSL_SP_MATH) || !defined(WOLFSSL_SP_NO_256)) if (MATCH_PQC(begin, "SecP256r1MLKEM768", len)) { available = 1; } @@ -224,7 +225,8 @@ static int IsKyberLevelAvailable(const char* line) available = 1; } #endif - #if !defined(WOLFSSL_NO_ML_KEM_1024) && defined(HAVE_ECC) + #if !defined(WOLFSSL_NO_ML_KEM_1024) && defined(HAVE_ECC) && \ + (!defined(WOLFSSL_SP_MATH) || defined(WOLFSSL_SP_384)) if (MATCH_PQC(begin, "SecP384r1MLKEM1024", len)) { available = 1; } @@ -246,7 +248,8 @@ static int IsKyberLevelAvailable(const char* line) available = 1; } #endif - #if !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_ECC) + #if !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_ECC) && \ + (!defined(WOLFSSL_SP_MATH) || defined(WOLFSSL_SP_384)) if (MATCH_PQC(begin, "SecP384r1MLKEM768", len)) { available = 1; } @@ -261,7 +264,8 @@ static int IsKyberLevelAvailable(const char* line) available = 1; } #endif - #if !defined(WOLFSSL_NO_ML_KEM_1024) && defined(HAVE_ECC) + #if !defined(WOLFSSL_NO_ML_KEM_1024) && defined(HAVE_ECC) && \ + (!defined(WOLFSSL_SP_MATH) || defined(WOLFSSL_SP_521)) if (MATCH_PQC(begin, "SecP521r1MLKEM1024", len)) { available = 1; } @@ -290,9 +294,11 @@ static int IsKyberLevelAvailable(const char* line) available = 1; } #ifdef HAVE_ECC + #if !defined(WOLFSSL_SP_MATH) || defined(WOLFSSL_SP_384) if (MATCH_PQC(begin, "P384_KYBER_LEVEL3", len)) { available = 1; } + #endif if (MATCH_PQC(begin, "P256_KYBER_LEVEL3", len)) { available = 1; } @@ -303,9 +309,11 @@ static int IsKyberLevelAvailable(const char* line) available = 1; } #ifdef HAVE_ECC + #if !defined(WOLFSSL_SP_MATH) || defined(WOLFSSL_SP_521) if (MATCH_PQC(begin, "P521_KYBER_LEVEL5", len)) { available = 1; } + #endif #endif #endif #if !defined(WOLFSSL_NO_KYBER512) && defined(HAVE_CURVE25519) @@ -476,6 +484,28 @@ static int IsEcdsaCipherSuiteDefRsaCert(const char* line) } #endif +#ifdef WOLFSSL_STATIC_PSK +/* Check whether the command line forces ephemeral (EC)DHE PSK key exchange. + * + * @param [in] argc Number of arguments. + * @param [in] argv Argument list. + * @return 1 when "--onlyPskDheKe" is present. + * @return 0 otherwise. + */ +static int IsOnlyPskDheKe(int argc, char** argv) +{ + int i; + + for (i = 0; i < argc; i++) { + if (argv[i] != NULL && XSTRCMP(argv[i], "--onlyPskDheKe") == 0) { + return 1; + } + } + + return 0; +} +#endif /* WOLFSSL_STATIC_PSK */ + static int execute_test_case(int svr_argc, char** svr_argv, int cli_argc, char** cli_argv, int addNoVerify, int addNonBlocking, @@ -588,6 +618,18 @@ static int execute_test_case(int svr_argc, char** svr_argv, return NOT_BUILT_IN; } #endif +#ifdef WOLFSSL_STATIC_PSK + /* --onlyPskDheKe forces the psk_dhe_ke key exchange mode, which requires + * ephemeral (EC)DHE. A static PSK build provides only the psk_ke mode, so + * skip these tests. */ + if (IsOnlyPskDheKe(svrArgs.argc, svr_argv) || + IsOnlyPskDheKe(cliArgs.argc, cli_argv)) { + #ifdef DEBUG_SUITE_TESTS + printf("--onlyPskDheKe not supported with WOLFSSL_STATIC_PSK\n"); + #endif + return NOT_BUILT_IN; + } +#endif /* Build Server Command */ if (addNoVerify) { diff --git a/tests/swdev/swdev.c b/tests/swdev/swdev.c index db06f20409..24271eda1e 100644 --- a/tests/swdev/swdev.c +++ b/tests/swdev/swdev.c @@ -249,6 +249,177 @@ out: #endif /* WOLFSSL_SHA224 */ #endif /* !NO_SHA256 */ +#if defined(WOLFSSL_SHA512) || defined(WOLFSSL_SHA384) +/* Copy hash state between caller's wc_Sha512 and swdev's shadow, leaving + * admin fields (heap, devId, devCtx, W, async, HW ctx) per-side. The same + * helper works for SHA-384, SHA-512/224, SHA-512/256 since they all typedef + * to wc_Sha512. */ +static void swdev_sha512_copy_state(wc_Sha512* dst, const wc_Sha512* src) +{ + XMEMCPY(dst->digest, src->digest, sizeof(dst->digest)); + XMEMCPY(dst->buffer, src->buffer, sizeof(dst->buffer)); + dst->buffLen = src->buffLen; + dst->loLen = src->loLen; + dst->hiLen = src->hiLen; +#ifdef WC_C_DYNAMIC_FALLBACK + dst->sha_method = src->sha_method; +#endif +#ifdef WOLFSSL_HASH_FLAGS + dst->flags = src->flags; +#endif +#if defined(WOLFSSL_SHA512_HASHTYPE) + dst->hashType = src->hashType; +#endif +} +#endif /* WOLFSSL_SHA512 || WOLFSSL_SHA384 */ + +#ifdef WOLFSSL_SHA512 +static int swdev_sha512(wc_CryptoInfo* info) +{ + wc_Sha512* sha512 = info->hash.sha512; + wc_Sha512 shadow; + int ret; + + if (sha512 == NULL) + return BAD_FUNC_ARG; + + ret = wc_InitSha512(&shadow); + if (ret != 0) + return ret; + + swdev_sha512_copy_state(&shadow, sha512); + + if (info->hash.in != NULL) { + ret = wc_Sha512Update(&shadow, info->hash.in, info->hash.inSz); + if (ret != 0) + goto out; + } + + if (info->hash.digest != NULL) { + ret = wc_Sha512Final(&shadow, info->hash.digest); + if (ret != 0) + goto out; + } + + swdev_sha512_copy_state(sha512, &shadow); + +out: + wc_Sha512Free(&shadow); + return ret; +} + +#if !defined(WOLFSSL_NOSHA512_224) && \ + !defined(WOLFSSL_SWDEV_SHA512_GENERAL_ONLY) +static int swdev_sha512_224(wc_CryptoInfo* info) +{ + wc_Sha512 shadow; + wc_Sha512* sha = info->hash.sha512; + int ret; + + if (sha == NULL) + return BAD_FUNC_ARG; + + ret = wc_InitSha512_224(&shadow); + if (ret != 0) + return ret; + + swdev_sha512_copy_state(&shadow, sha); + + if (info->hash.in != NULL) { + ret = wc_Sha512_224Update(&shadow, info->hash.in, info->hash.inSz); + if (ret != 0) + goto out; + } + if (info->hash.digest != NULL) { + ret = wc_Sha512_224Final(&shadow, info->hash.digest); + if (ret != 0) + goto out; + } + + swdev_sha512_copy_state(sha, &shadow); + +out: + wc_Sha512_224Free(&shadow); + return ret; +} +#endif + +#if !defined(WOLFSSL_NOSHA512_256) && \ + !defined(WOLFSSL_SWDEV_SHA512_GENERAL_ONLY) +static int swdev_sha512_256(wc_CryptoInfo* info) +{ + wc_Sha512 shadow; + wc_Sha512* sha = info->hash.sha512; + int ret; + + if (sha == NULL) + return BAD_FUNC_ARG; + + ret = wc_InitSha512_256(&shadow); + if (ret != 0) + return ret; + + swdev_sha512_copy_state(&shadow, sha); + + if (info->hash.in != NULL) { + ret = wc_Sha512_256Update(&shadow, info->hash.in, info->hash.inSz); + if (ret != 0) + goto out; + } + if (info->hash.digest != NULL) { + ret = wc_Sha512_256Final(&shadow, info->hash.digest); + if (ret != 0) + goto out; + } + + swdev_sha512_copy_state(sha, &shadow); + +out: + wc_Sha512_256Free(&shadow); + return ret; +} +#endif +#endif /* WOLFSSL_SHA512 */ + +#if defined(WOLFSSL_SHA384) && !defined(WOLFSSL_SWDEV_SHA512_GENERAL_ONLY) +/* SHA-384 is SHA-512 with a different IV/truncation; wc_Sha384 is a typedef + * of wc_Sha512, so the shadow/copy-state dance is identical to swdev_sha512. + * When WOLFSSL_SWDEV_SHA512_GENERAL_ONLY is set this is omitted so swdev declines + * SHA-384 and the cryptocb dispatcher's SHA-512 fallback path is exercised. */ +static int swdev_sha384(wc_CryptoInfo* info) +{ + wc_Sha384* sha384 = info->hash.sha384; + wc_Sha384 shadow; + int ret; + + if (sha384 == NULL) + return BAD_FUNC_ARG; + + ret = wc_InitSha384(&shadow); + if (ret != 0) + return ret; + + swdev_sha512_copy_state(&shadow, sha384); + + if (info->hash.in != NULL) { + ret = wc_Sha384Update(&shadow, info->hash.in, info->hash.inSz); + if (ret != 0) + goto out; + } + if (info->hash.digest != NULL) { + ret = wc_Sha384Final(&shadow, info->hash.digest); + if (ret != 0) + goto out; + } + + swdev_sha512_copy_state(sha384, &shadow); + +out: + wc_Sha384Free(&shadow); + return ret; +} +#endif /* WOLFSSL_SHA384 && !WOLFSSL_SWDEV_SHA512_GENERAL_ONLY */ + #ifndef NO_AES /* Rebuild a software AES shadow from the caller's raw devKey, since the * caller's Aes has no software round-key schedule under CB_ONLY_AES. */ @@ -546,14 +717,35 @@ WC_SWDEV_EXPORT int wc_SwDev_Callback(int devId, wc_CryptoInfo* info, return CRYPTOCB_UNAVAILABLE; } #endif -#ifndef NO_SHA256 +#if !defined(NO_SHA256) || defined(WOLFSSL_SHA512) || defined(WOLFSSL_SHA384) case WC_ALGO_TYPE_HASH: switch (info->hash.type) { + #ifndef NO_SHA256 case WC_HASH_TYPE_SHA256: return swdev_sha256(info); + #endif #ifdef WOLFSSL_SHA224 case WC_HASH_TYPE_SHA224: return swdev_sha224(info); + #endif + #ifdef WOLFSSL_SHA512 + case WC_HASH_TYPE_SHA512: + return swdev_sha512(info); + #if !defined(WOLFSSL_NOSHA512_224) && \ + !defined(WOLFSSL_SWDEV_SHA512_GENERAL_ONLY) + case WC_HASH_TYPE_SHA512_224: + return swdev_sha512_224(info); + #endif + #if !defined(WOLFSSL_NOSHA512_256) && \ + !defined(WOLFSSL_SWDEV_SHA512_GENERAL_ONLY) + case WC_HASH_TYPE_SHA512_256: + return swdev_sha512_256(info); + #endif + #endif + #if defined(WOLFSSL_SHA384) && \ + !defined(WOLFSSL_SWDEV_SHA512_GENERAL_ONLY) + case WC_HASH_TYPE_SHA384: + return swdev_sha384(info); #endif default: return CRYPTOCB_UNAVAILABLE; diff --git a/tests/swdev/user_settings.h b/tests/swdev/user_settings.h index 09073ea2b9..c04f056b02 100644 --- a/tests/swdev/user_settings.h +++ b/tests/swdev/user_settings.h @@ -25,6 +25,7 @@ #undef WOLF_CRYPTO_CB_ONLY_RSA #undef WOLF_CRYPTO_CB_ONLY_ECC #undef WOLF_CRYPTO_CB_ONLY_SHA256 +#undef WOLF_CRYPTO_CB_ONLY_SHA512 #undef WOLF_CRYPTO_CB_ONLY_AES #ifndef WOLF_CRYPTO_CB diff --git a/tests/test-fails.conf b/tests/test-fails.conf index 74530e3e0e..e8f2772276 100644 --- a/tests/test-fails.conf +++ b/tests/test-fails.conf @@ -161,24 +161,6 @@ -l ECDHE-ECDSA-AES128-GCM-SHA256 -H verifyFail -# Client is using RSA certificate with ECDSA cipher suite. Server will fail. -# server --v 3 --l ECDHE-ECDSA-AES128-GCM-SHA256 --c ./certs/server-ecc.pem --k ./certs/ecc-key.pem --A ./certs/client-cert.pem --H verifyFail --H exitWithRet - -# client --v 3 --l ECDHE-ECDSA-AES128-GCM-SHA256 --c ./certs/client-cert.pem --k ./certs/client-key.pem --A ./certs/ca-ecc-cert.pem --H exitWithRet - # server send alert on no mutual authentication -v 3 -F diff --git a/tests/unit.c b/tests/unit.c index 1734f7abbe..5f788fe051 100644 --- a/tests/unit.c +++ b/tests/unit.c @@ -43,6 +43,7 @@ int allTesting = 1; int apiTesting = 1; +int wolfCryptTesting = 1; int myoptind = 0; char* myoptarg = NULL; int unit_test(int argc, char** argv); @@ -202,6 +203,9 @@ int unit_test(int argc, char** argv) ApiTest_PrintTestCases(); goto exit; } + else if (XSTRCMP(argv[1], "--no-wc") == 0) { + wolfCryptTesting = 0; + } else if (XSTRCMP(argv[1], "--api") == 0) { allTesting = 0; } @@ -257,7 +261,7 @@ int unit_test(int argc, char** argv) #ifndef NO_CRYPT_TEST /* wc_ test */ - if (allTesting) { + if (allTesting && wolfCryptTesting) { func_args wc_args; printf("\nwolfCrypt unit test:\n"); diff --git a/tests/utils.c b/tests/utils.c index a6d37b89d5..447746d277 100644 --- a/tests/utils.c +++ b/tests/utils.c @@ -23,7 +23,7 @@ #include #include -#ifdef HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES +#ifdef HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES_BUILD /* This set of memio functions allows for more fine tuned control of the TLS * connection operations. For new tests, try to use ssl_memio first. */ @@ -513,6 +513,40 @@ int test_memio_get_message(const struct test_memio_ctx *ctx, int client, return 0; } +/* The random value placed in a ServerHello to mark it as a HelloRetryRequest. + * See RFC 8446 Section 4.1.3. */ +static const byte test_hello_retry_request_random[32] = { + 0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11, + 0xBE, 0x1D, 0x8C, 0x02, 0x1E, 0x65, 0xB8, 0x91, + 0xC2, 0xA2, 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E, + 0x07, 0x9E, 0x09, 0xE2, 0xC8, 0xA8, 0x33, 0x9C +}; + +/* Returns 1 if the first server->client record buffered in ctx is a + * HelloRetryRequest, 0 otherwise. A HelloRetryRequest is sent as a ServerHello + * (handshake type server_hello) carrying the special random above. */ +int test_memio_msg_is_hello_retry_request(const struct test_memio_ctx *ctx) +{ + const char* msg = NULL; + int msg_sz = 0; + /* TLS record header (5) + handshake header (4) + legacy_version (2) is the + * offset of the 32-byte ServerHello random within the record. */ + const int random_off = 5 + 4 + 2; + + /* The server's flight is buffered for the client (client = 1). */ + if (test_memio_get_message(ctx, 1, &msg, &msg_sz, 0) != 0) + return 0; + /* Need a handshake record (0x16) holding a server_hello (0x02) with a full + * random. */ + if (msg_sz < random_off + (int)sizeof(test_hello_retry_request_random)) + return 0; + if ((byte)msg[0] != 0x16 || (byte)msg[5] != 0x02) + return 0; + + return XMEMCMP(msg + random_off, test_hello_retry_request_random, + sizeof(test_hello_retry_request_random)) == 0; +} + int test_memio_move_message(struct test_memio_ctx *ctx, int client, int msg_pos_in, int msg_pos_out) { @@ -784,7 +818,7 @@ int test_memio_setup(struct test_memio_ctx *ctx, method_s, NULL, 0, NULL, 0, NULL, 0); } -#endif /* HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES */ +#endif /* HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES_BUILD */ #if !defined(NO_FILESYSTEM) && defined(OPENSSL_EXTRA) && \ defined(DEBUG_UNIT_TEST_CERTS) diff --git a/tests/utils.h b/tests/utils.h index bd9a150e01..e201ebdec1 100644 --- a/tests/utils.h +++ b/tests/utils.h @@ -32,11 +32,26 @@ extern char tmpDirName[16]; extern const char* currentTestName; #endif -#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && \ - (!defined(NO_RSA) || defined(HAVE_RPK)) && \ - !defined(NO_WOLFSSL_SERVER) && !defined(NO_WOLFSSL_CLIENT) && \ - (!defined(WOLFSSL_NO_TLS12) || defined(WOLFSSL_TLS13)) +/* Base dependencies for the manual memio test harness. The harness itself does + * not require certificate support, so cert-less tests (e.g. PSK-only) can use + * it through this narrower macro. */ +#if !defined(NO_WOLFSSL_SERVER) && !defined(NO_WOLFSSL_CLIENT) && \ + (!defined(WOLFSSL_NO_TLS12) || defined(WOLFSSL_TLS13)) && defined(NO_CERTS) +#define HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES_NO_CERTS +#define HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES_BUILD +#endif + +/* Full dependencies: the base harness plus certificate support. Most memio + * tests set up a certificate-based handshake and must use this macro. */ +#if !defined(NO_WOLFSSL_SERVER) && !defined(NO_WOLFSSL_CLIENT) && \ + (!defined(WOLFSSL_NO_TLS12) || defined(WOLFSSL_TLS13)) && \ + !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && \ + (!defined(NO_RSA) || defined(HAVE_RPK)) #define HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES +#define HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES_BUILD +#endif + +#ifdef HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES_BUILD #define TEST_MEMIO_BUF_SZ (64 * 1024) #define TEST_MEMIO_MAX_MSGS 32 @@ -80,12 +95,13 @@ int test_memio_copy_message(const struct test_memio_ctx *ctx, int client, char *out, int *out_sz, int msg_pos); int test_memio_get_message(const struct test_memio_ctx *ctx, int client, const char **out, int *out_sz, int msg_pos); +int test_memio_msg_is_hello_retry_request(const struct test_memio_ctx *ctx); int test_memio_move_message(struct test_memio_ctx *ctx, int client, int msg_pos_in, int msg_pos_out); int test_memio_drop_message(struct test_memio_ctx *ctx, int client, int msg_pos); int test_memio_modify_message_len(struct test_memio_ctx *ctx, int client, int msg_pos, int new_len); int test_memio_remove_from_buffer(struct test_memio_ctx *ctx, int client, int off, int sz); -#endif +#endif /* HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES_BUILD */ /* Shared TLS server/client thread bodies, defined in tests/api.c. The * definitions are gated on ENABLE_TLS_CALLBACK_TEST (a composite condition diff --git a/wolfcrypt/benchmark/benchmark.c b/wolfcrypt/benchmark/benchmark.c index 1f05e157de..214d873bc2 100644 --- a/wolfcrypt/benchmark/benchmark.c +++ b/wolfcrypt/benchmark/benchmark.c @@ -11089,7 +11089,7 @@ exit: #ifdef WOLFSSL_HAVE_MLKEM static void bench_mlkem_keygen(int type, const char* name, int keySize, - KyberKey* key) + MlKemKey* key) { #ifndef WOLFSSL_MLKEM_NO_MAKE_KEY int ret = 0, times, count, pending = 0; @@ -11104,17 +11104,17 @@ static void bench_mlkem_keygen(int type, const char* name, int keySize, do { /* while free pending slots in queue, submit ops */ for (times = 0; times < agreeTimes || pending > 0; times++) { - wc_KyberKey_Free(key); - ret = wc_KyberKey_Init(type, key, HEAP_HINT, INVALID_DEVID); + wc_MlKemKey_Free(key); + ret = wc_MlKemKey_Init(key, type, HEAP_HINT, INVALID_DEVID); if (ret != 0) goto exit; #ifdef MLKEM_NONDETERMINISTIC - ret = wc_KyberKey_MakeKey(key, &gRng); + ret = wc_MlKemKey_MakeKey(key, &gRng); #else { unsigned char rand[WC_ML_KEM_MAKEKEY_RAND_SZ] = {0,}; - ret = wc_KyberKey_MakeKeyWithRandom(key, rand, sizeof(rand)); + ret = wc_MlKemKey_MakeKeyWithRandom(key, rand, sizeof(rand)); } #endif if (ret != 0) @@ -11144,7 +11144,7 @@ exit: #if !defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) || \ !defined(WOLFSSL_MLKEM_NO_DECAPSULATE) static void bench_mlkem_encap(int type, const char* name, int keySize, - KyberKey* key1, KyberKey* key2) + MlKemKey* key1, MlKemKey* key2) { int ret = 0, times, count, pending = 0; double start; @@ -11162,24 +11162,24 @@ static void bench_mlkem_encap(int type, const char* name, int keySize, WC_ALLOC_VAR(ss, byte, WC_ML_KEM_SS_SZ, HEAP_HINT); WC_ALLOC_VAR(pub, byte, WC_ML_KEM_MAX_PUBLIC_KEY_SIZE, HEAP_HINT); - ret = wc_KyberKey_PublicKeySize(key1, &pubLen); + ret = wc_MlKemKey_PublicKeySize(key1, &pubLen); if (ret != 0) { goto exit; } - ret = wc_KyberKey_EncodePublicKey(key1, pub, pubLen); + ret = wc_MlKemKey_EncodePublicKey(key1, pub, pubLen); if (ret != 0) { goto exit; } - ret = wc_KyberKey_Init(type, key2, HEAP_HINT, INVALID_DEVID); + ret = wc_MlKemKey_Init(key2, type, HEAP_HINT, INVALID_DEVID); if (ret != 0) { goto exit; } - ret = wc_KyberKey_DecodePublicKey(key2, pub, pubLen); + ret = wc_MlKemKey_DecodePublicKey(key2, pub, pubLen); if (ret != 0) { goto exit; } - ret = wc_KyberKey_CipherTextSize(key2, &ctSz); + ret = wc_MlKemKey_CipherTextSize(key2, &ctSz); if (ret != 0) { goto exit; } @@ -11191,10 +11191,10 @@ static void bench_mlkem_encap(int type, const char* name, int keySize, /* while free pending slots in queue, submit ops */ for (times = 0; times < agreeTimes || pending > 0; times++) { #ifdef MLKEM_NONDETERMINISTIC - ret = wc_KyberKey_Encapsulate(key2, ct, ss, &gRng); + ret = wc_MlKemKey_Encapsulate(key2, ct, ss, &gRng); #else unsigned char rand[WC_ML_KEM_ENC_RAND_SZ] = {0,}; - ret = wc_KyberKey_EncapsulateWithRandom(key2, ct, ss, rand, + ret = wc_MlKemKey_EncapsulateWithRandom(key2, ct, ss, rand, sizeof(rand)); #endif if (ret != 0) @@ -11224,7 +11224,7 @@ exit_encap: do { /* while free pending slots in queue, submit ops */ for (times = 0; times < agreeTimes || pending > 0; times++) { - ret = wc_KyberKey_Decapsulate(key1, ss, ct, ctSz); + ret = wc_MlKemKey_Decapsulate(key1, ss, ct, ctSz); if (ret != 0) goto exit_decap; RECORD_MULTI_VALUE_STATS(); @@ -11261,11 +11261,11 @@ exit: void bench_mlkem(int type) { #ifdef WOLFSSL_SMALL_STACK - KyberKey *key1 = NULL; - KyberKey *key2 = NULL; + MlKemKey *key1 = NULL; + MlKemKey *key2 = NULL; #else - KyberKey key1[1]; - KyberKey key2[1]; + MlKemKey key1[1]; + MlKemKey key2[1]; #endif const char* name = NULL; int keySize = 0; @@ -11316,10 +11316,10 @@ void bench_mlkem(int type) } #ifdef WOLFSSL_SMALL_STACK - key1 = (KyberKey *)XMALLOC(sizeof(*key1), HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + key1 = (MlKemKey *)XMALLOC(sizeof(*key1), HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); if (key1 == NULL) return; - key2 = (KyberKey *)XMALLOC(sizeof(*key2), HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + key2 = (MlKemKey *)XMALLOC(sizeof(*key2), HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); if (key2 == NULL) { XFREE(key1, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); return; @@ -11332,8 +11332,8 @@ void bench_mlkem(int type) bench_mlkem_encap(type, name, keySize, key1, key2); #endif - wc_KyberKey_Free(key2); - wc_KyberKey_Free(key1); + wc_MlKemKey_Free(key2); + wc_MlKemKey_Free(key1); WC_FREE_VAR_EX(key1, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); WC_FREE_VAR_EX(key2, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); diff --git a/wolfcrypt/src/aes.c b/wolfcrypt/src/aes.c index dccab8ff78..021b5f84c3 100644 --- a/wolfcrypt/src/aes.c +++ b/wolfcrypt/src/aes.c @@ -17556,7 +17556,7 @@ int wc_AesEaxEncryptFinal(AesEax* eax, byte* authTag, word32 authTagSz) word32 i; if (eax == NULL || authTag == NULL || authTagSz == 0 || - authTagSz > WC_AES_BLOCK_SIZE) { + authTagSz > WC_AES_BLOCK_SIZE || authTagSz < WOLFSSL_MIN_AUTH_TAG_SZ) { return BAD_FUNC_ARG; } diff --git a/wolfcrypt/src/arc4.c b/wolfcrypt/src/arc4.c index 6d83ed2569..dc37014335 100644 --- a/wolfcrypt/src/arc4.c +++ b/wolfcrypt/src/arc4.c @@ -67,6 +67,8 @@ int wc_Arc4SetKey(Arc4* arc4, const byte* key, word32 length) keyIndex = 0; } + arc4->keySet = 1; + return ret; } @@ -102,6 +104,10 @@ int wc_Arc4Process(Arc4* arc4, byte* out, const byte* in, word32 length) } #endif + if (!arc4->keySet) { + return MISSING_KEY; + } + x = arc4->x; y = arc4->y; @@ -123,6 +129,7 @@ int wc_Arc4Init(Arc4* arc4, void* heap, int devId) return BAD_FUNC_ARG; arc4->heap = heap; + arc4->keySet = 0; #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ARC4) ret = wolfAsync_DevCtxInit(&arc4->asyncDev, WOLFSSL_ASYNC_MARKER_ARC4, @@ -148,6 +155,7 @@ void wc_Arc4Free(Arc4* arc4) ForceZero(arc4->state, sizeof(arc4->state)); arc4->x = 0; arc4->y = 0; + arc4->keySet = 0; } #endif /* NO_RC4 */ diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 9c76e4d5ee..1e97e72fe3 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -4418,9 +4418,9 @@ static int EncodeName(EncodedName* name, const char* nameStr, byte nameTag, byte #endif #ifdef WOLFSSL_CERT_GEN static int SetValidity(byte* output, int daysValid); -static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey, ecc_key* eccKey, WC_RNG* rng, DsaKey* dsaKey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, wc_MlDsaKey* mldsaKey, SlhDsaKey* slhDsaKey); +static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey, ecc_key* eccKey, WC_RNG* rng, DsaKey* dsaKey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, wc_MlDsaKey* mldsaKey, SlhDsaKey* slhDsaKey, LmsKey* lmsKey, XmssKey* xmssKey); #ifdef WOLFSSL_CERT_REQ -static int MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey, DsaKey* dsaKey, ecc_key* eccKey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, wc_MlDsaKey* mldsaKey, SlhDsaKey* slhDsaKey); +static int MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey, DsaKey* dsaKey, ecc_key* eccKey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, wc_MlDsaKey* mldsaKey, SlhDsaKey* slhDsaKey, LmsKey* lmsKey, XmssKey* xmssKey); #endif #endif #endif @@ -8074,6 +8074,9 @@ static int DecodeRsaPssParams(const byte* params, word32 sz, { DECL_ASNGETDATA(dataASN, rsaPssParamsASN_Length); int ret = 0; +#ifndef WOLFSSL_NO_ASN_STRICT + word16 trailerVal = 1; +#endif word16 sLen = 20; /* Default values. */ @@ -8089,6 +8092,10 @@ static int DecodeRsaPssParams(const byte* params, word32 sz, GetASN_OID(&dataASN[RSAPSSPARAMSASN_IDX_MGFHOID], oidHashType); /* Place the salt length into 16-bit var sLen. */ GetASN_Int16Bit(&dataASN[RSAPSSPARAMSASN_IDX_SALTLENINT], &sLen); +#ifndef WOLFSSL_NO_ASN_STRICT + /* Capture trailerField value for RFC 8017 A.2.3 validation. */ + GetASN_Int16Bit(&dataASN[RSAPSSPARAMSASN_IDX_TRAILERINT], &trailerVal); +#endif /* Decode the algorithm identifier. */ ret = GetASN_Items(rsaPssParamsASN, dataASN, rsaPssParamsASN_Length, 1, params, &inOutIdx, sz); @@ -8105,6 +8112,15 @@ static int DecodeRsaPssParams(const byte* params, word32 sz, word32 oid = dataASN[RSAPSSPARAMSASN_IDX_MGFHOID].data.oid.sum; ret = RsaPssHashOidToMgf1(oid, mgf); } +#ifndef WOLFSSL_NO_ASN_STRICT + /* RFC 8017 A.2.3: trailerField SHALL be trailerFieldBC(1). */ + if ((ret == 0) && (dataASN[RSAPSSPARAMSASN_IDX_TRAILERINT].tag != 0)) { + if (trailerVal != 1) { + WOLFSSL_MSG("DecodeRsaPssParams: trailerField must be 1"); + ret = ASN_PARSE_E; + } + } +#endif if (ret == 0) { *saltLen = sLen; } @@ -8251,12 +8267,26 @@ static int DecodeRsaPssParams(const byte* params, word32 sz, } if (ret == 0) { ret = GetInteger16Bit(params, &idx, sz); +#ifndef WOLFSSL_NO_ASN_STRICT + /* RFC 8017 A.2.3: trailerField SHALL be trailerFieldBC(1). */ + if (ret == 1) { + ret = 0; + } + else if (ret >= 0) { + WOLFSSL_MSG("DecodeRsaPssParams: trailerField must be 1"); + ret = ASN_PARSE_E; + } + else { + WOLFSSL_MSG("DecodeRsaPssParams: fail at trailer_value"); + } +#else if (ret > 0) { ret = 0; } else if (ret != 0) { WOLFSSL_MSG("DecodeRsaPssParams: fail at trailer_value"); } +#endif } } } @@ -13065,6 +13095,82 @@ int wc_Ed448PublicKeyToDer(const ed448_key* key, byte* output, word32 inLen, return ret; } #endif /* HAVE_ED448 && HAVE_ED448_KEY_EXPORT */ + +#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) +/* Encode the public part of an LMS/HSS key in DER. + * + * Per RFC 9802, the SubjectPublicKeyInfo for HSS/LMS uses the + * id-alg-hss-lms-hashsig OID and carries the raw HSS public key in the + * BIT STRING with no additional wrapping. + * + * Pass NULL for output to get the size of the encoding. + * + * @param [in] key LMS key object. + * @param [out] output Buffer to put encoded data in. + * @param [in] inLen Size of buffer in bytes. + * @param [in] withAlg Whether to use SubjectPublicKeyInfo format. + * @return Size of encoded data in bytes on success. + * @return BAD_FUNC_ARG when key is NULL. + */ +int wc_LmsKey_PublicKeyToDer(const LmsKey* key, byte* output, word32 inLen, + int withAlg) +{ + int ret; + byte pubKey[HSS_MAX_PUBLIC_KEY_LEN]; + word32 pubKeyLen = (word32)sizeof(pubKey); + + if (key == NULL) { + return BAD_FUNC_ARG; + } + + ret = wc_LmsKey_ExportPubRaw(key, pubKey, &pubKeyLen); + if (ret == 0) { + ret = SetAsymKeyDerPublic(pubKey, pubKeyLen, output, inLen, + HSS_LMSk, withAlg); + } + return ret; +} +#endif /* WOLFSSL_HAVE_LMS && !WOLFSSL_LMS_VERIFY_ONLY */ + +#if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY) +/* Encode the public part of an XMSS/XMSS^MT key in DER. + * + * Per RFC 9802, the SubjectPublicKeyInfo for XMSS/XMSS^MT uses the + * id-alg-xmss-hashsig / id-alg-xmssmt-hashsig OID and carries the raw + * public key in the BIT STRING with no additional wrapping. + * + * Pass NULL for output to get the size of the encoding. + * + * @param [in] key XMSS key object. + * @param [out] output Buffer to put encoded data in. + * @param [in] inLen Size of buffer in bytes. + * @param [in] withAlg Whether to use SubjectPublicKeyInfo format. + * @return Size of encoded data in bytes on success. + * @return BAD_FUNC_ARG when key is NULL. + */ +int wc_XmssKey_PublicKeyToDer(const XmssKey* key, byte* output, word32 inLen, + int withAlg) +{ + int ret; + byte pubKey[2 * WC_XMSS_MAX_N + XMSS_OID_LEN]; + word32 pubKeyLen = (word32)sizeof(pubKey); + int keyType; + + if (key == NULL) { + return BAD_FUNC_ARG; + } + + keyType = key->is_xmssmt ? XMSSMTk : XMSSk; + + ret = wc_XmssKey_ExportPubRaw(key, pubKey, &pubKeyLen); + if (ret == 0) { + ret = SetAsymKeyDerPublic(pubKey, pubKeyLen, output, inLen, + keyType, withAlg); + } + return ret; +} +#endif /* WOLFSSL_HAVE_XMSS && !WOLFSSL_XMSS_VERIFY_ONLY */ + #if !defined(NO_RSA) && !defined(NO_CERTS) #ifdef WOLFSSL_ASN_TEMPLATE /* ASN.1 template for header before RSA key in certificate. */ @@ -16954,7 +17060,9 @@ int ConfirmSignature(SignatureCtx* sigCtx, ERROR_OUT(MEMORY_E, exit_cs); } #endif - if (sigSz > MAX_ENCODED_SIG_SZ) { + /* RSA signature copied into sigCpy, which under + * WOLFSSL_NO_MALLOC is sized to MAX_ENCODED_CLASSIC_SIG_SZ. */ + if (sigSz > MAX_ENCODED_CLASSIC_SIG_SZ) { WOLFSSL_MSG("Verify Signature is too big"); ERROR_OUT(BUFFER_E, exit_cs); } @@ -16982,7 +17090,7 @@ int ConfirmSignature(SignatureCtx* sigCtx, WOLFSSL_MSG("Verify Signature is too small"); ERROR_OUT(BUFFER_E, exit_cs); } - else if (sigSz > MAX_ENCODED_SIG_SZ) { + else if (sigSz > MAX_ENCODED_CLASSIC_SIG_SZ) { WOLFSSL_MSG("Verify Signature is too big"); ERROR_OUT(BUFFER_E, exit_cs); } @@ -17671,13 +17779,15 @@ int ConfirmSignature(SignatureCtx* sigCtx, if (sigCtx->CertAtt.verifyByTSIP_SCE == 1) break; #endif #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) - byte* encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, + /* Holds a PKCS#1 DigestInfo encoding for RSA verification, + * never a PQC signature -- size to the classic tier. */ + byte* encodedSig = (byte*)XMALLOC(MAX_ENCODED_CLASSIC_SIG_SZ, sigCtx->heap, DYNAMIC_TYPE_TMP_BUFFER); if (encodedSig == NULL) { ERROR_OUT(MEMORY_E, exit_cs); } #else - byte encodedSig[MAX_ENCODED_SIG_SZ]; + byte encodedSig[MAX_ENCODED_CLASSIC_SIG_SZ]; #endif verifySz = ret; @@ -24955,10 +25065,10 @@ int PemToDer(const unsigned char* buff, long longSz, int type, const char* headerEnd = NULL; const char* footerEnd = NULL; const char* consumedEnd = NULL; - const char* bufferEnd = (const char*)(buff + longSz); + const char* bufferEnd = NULL; long neededSz; int ret = 0; - word32 sz = (word32)longSz; + word32 sz = 0; int encrypted_key = 0; DerBuffer* der; word32 algId = 0; @@ -24979,6 +25089,14 @@ int PemToDer(const unsigned char* buff, long longSz, int type, WOLFSSL_ENTER("PemToDer"); + /* Reject negative size - would wrap word32 and corrupt pointer arithmetic. */ + if (longSz < 0) { + return BAD_FUNC_ARG; + } + + bufferEnd = (const char*)(buff + longSz); + sz = (word32)longSz; + /* get PEM header and footer based on type */ ret = wc_PemGetHeaderFooter(type, &header, &footer); if (ret != 0) @@ -27385,7 +27503,8 @@ static int EncodePublicKey(int keyType, byte* output, int outLen, RsaKey* rsaKey, ecc_key* eccKey, ed25519_key* ed25519Key, ed448_key* ed448Key, DsaKey* dsaKey, falcon_key* falconKey, - wc_MlDsaKey* mldsaKey, SlhDsaKey* slhDsaKey) + wc_MlDsaKey* mldsaKey, SlhDsaKey* slhDsaKey, + LmsKey* lmsKey, XmssKey* xmssKey) { int ret = 0; @@ -27398,6 +27517,8 @@ static int EncodePublicKey(int keyType, byte* output, int outLen, (void)falconKey; (void)mldsaKey; (void)slhDsaKey; + (void)lmsKey; + (void)xmssKey; switch (keyType) { #ifndef NO_RSA @@ -27481,6 +27602,23 @@ static int EncodePublicKey(int keyType, byte* output, int outLen, } break; #endif /* WOLFSSL_HAVE_SLHDSA */ + #if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) + case LMS_KEY: + ret = wc_LmsKey_PublicKeyToDer(lmsKey, output, (word32)outLen, 1); + if (ret <= 0) { + ret = PUBLIC_KEY_E; + } + break; + #endif /* WOLFSSL_HAVE_LMS && !WOLFSSL_LMS_VERIFY_ONLY */ + #if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY) + case XMSS_KEY: + case XMSSMT_KEY: + ret = wc_XmssKey_PublicKeyToDer(xmssKey, output, (word32)outLen, 1); + if (ret <= 0) { + ret = PUBLIC_KEY_E; + } + break; + #endif /* WOLFSSL_HAVE_XMSS && !WOLFSSL_XMSS_VERIFY_ONLY */ default: ret = PUBLIC_KEY_E; break; @@ -28276,6 +28414,270 @@ static int InternalSignCb(const byte* in, word32 inLen, #endif /* WOLFSSL_CERT_GEN || WOLFSSL_CERT_REQ */ +/* Return the buffer size needed to hold the raw signature that + * MakeSignature() will produce for the provided key, or a negative error code + * if it cannot be determined. The per-algorithm branches mirror the dispatch + * in MakeSignature() so the two stay in agreement; exactly one key pointer is + * expected to be non-NULL. + * + * Sizing the signature buffer from the key (rather than the worst-case + * MAX_ENCODED_SIG_SZ) avoids allocating tens of KB for classic keys in builds + * that merely enable a PQC algorithm, and is required for LMS/XMSS whose + * parameter-dependent signatures can exceed MAX_ENCODED_SIG_SZ. */ +static int GetSignatureBufferSz(RsaKey* rsaKey, ecc_key* eccKey, + ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, + wc_MlDsaKey* mldsaKey, SlhDsaKey* slhDsaKey, LmsKey* lmsKey, + XmssKey* xmssKey) +{ + int sigSz = ALGO_ID_E; + + (void)rsaKey; (void)eccKey; (void)ed25519Key; (void)ed448Key; + (void)falconKey; (void)mldsaKey; (void)slhDsaKey; (void)lmsKey; + (void)xmssKey; + +#ifndef NO_RSA + if (rsaKey != NULL) + sigSz = wc_RsaEncryptSize(rsaKey); +#endif +#ifdef HAVE_ECC + if (eccKey != NULL) + sigSz = wc_ecc_sig_size(eccKey); +#endif +#if defined(HAVE_ED25519) + if (ed25519Key != NULL) + sigSz = wc_ed25519_sig_size(ed25519Key); +#endif +#if defined(HAVE_ED448) + if (ed448Key != NULL) + sigSz = wc_ed448_sig_size(ed448Key); +#endif +#if defined(HAVE_FALCON) + if (falconKey != NULL) + sigSz = wc_falcon_sig_size(falconKey); +#endif +#if defined(WOLFSSL_HAVE_MLDSA) + if (mldsaKey != NULL) { + int len = 0; + int rc = wc_MlDsaKey_GetSigLen(mldsaKey, &len); + sigSz = (rc == 0) ? len : rc; + } +#endif +#if defined(WOLFSSL_HAVE_SLHDSA) + if (slhDsaKey != NULL) + sigSz = wc_SlhDsaKey_SigSize(slhDsaKey); +#endif +#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) + if (lmsKey != NULL) { + word32 len = 0; + int rc = wc_LmsKey_GetSigLen(lmsKey, &len); + sigSz = (rc == 0) ? (int)len : rc; + } +#endif +#if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY) + if (xmssKey != NULL) { + word32 len = 0; + int rc = wc_XmssKey_GetSigLen(xmssKey, &len); + sigSz = (rc == 0) ? (int)len : rc; + } +#endif + + /* sigSz still ALGO_ID_E means no (compiled-in) key matched; a getter + * returning 0 means the matched key was not usable. */ + if (sigSz == 0) + sigSz = BAD_FUNC_ARG; + return sigSz; +} + +#ifndef NO_RSA +/* True if sType is an RSA signature-algorithm OID (any hash, incl. PSS). */ +static int IsRsaSigType(int sType) +{ + switch (sType) { + case CTC_MD2wRSA: + case CTC_MD5wRSA: + case CTC_SHAwRSA: + case CTC_SHA224wRSA: + case CTC_SHA256wRSA: + case CTC_SHA384wRSA: + case CTC_SHA512wRSA: + case CTC_SHA3_224wRSA: + case CTC_SHA3_256wRSA: + case CTC_SHA3_384wRSA: + case CTC_SHA3_512wRSA: + case CTC_RSASSAPSS: + return 1; + default: + return 0; + } +} +#endif /* !NO_RSA */ +#ifdef HAVE_ECC +/* True if sType is an ECDSA (or SM2) signature-algorithm OID (any hash). */ +static int IsEccSigType(int sType) +{ + switch (sType) { + case CTC_SHAwECDSA: + case CTC_SHA224wECDSA: + case CTC_SHA256wECDSA: + case CTC_SHA384wECDSA: + case CTC_SHA512wECDSA: + case CTC_SHA3_224wECDSA: + case CTC_SHA3_256wECDSA: + case CTC_SHA3_384wECDSA: + case CTC_SHA3_512wECDSA: + #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) + case CTC_SM3wSM2: + #endif + return 1; + default: + return 0; + } +} +#endif /* HAVE_ECC */ + +/* Return the heap hint of whichever signing key is set, or NULL if none does + * (falcon_key has no heap member). Centralizes the lookup shared by the + * certificate/CSR signing entry points. */ +static void* GetSigningKeyHeap(RsaKey* rsaKey, ecc_key* eccKey, + ed25519_key* ed25519Key, ed448_key* ed448Key, wc_MlDsaKey* mldsaKey, + SlhDsaKey* slhDsaKey, LmsKey* lmsKey, XmssKey* xmssKey) +{ + (void)rsaKey; (void)eccKey; (void)ed25519Key; (void)ed448Key; + (void)mldsaKey; (void)slhDsaKey; (void)lmsKey; (void)xmssKey; +#ifndef NO_RSA + if (rsaKey != NULL) + return rsaKey->heap; +#endif +#ifdef HAVE_ECC + if (eccKey != NULL) + return eccKey->heap; +#endif +#ifdef HAVE_ED25519 + if (ed25519Key != NULL) + return ed25519Key->heap; +#endif +#ifdef HAVE_ED448 + if (ed448Key != NULL) + return ed448Key->heap; +#endif +#ifdef WOLFSSL_HAVE_MLDSA + if (mldsaKey != NULL) + return mldsaKey->heap; +#endif +#ifdef WOLFSSL_HAVE_SLHDSA + if (slhDsaKey != NULL) + return slhDsaKey->heap; +#endif +#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) + if (lmsKey != NULL) + return lmsKey->heap; +#endif +#if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY) + if (xmssKey != NULL) + return xmssKey->heap; +#endif + return NULL; +} + +/* Verify that the requested signature type -- which becomes the certificate's + * signatureAlgorithm OID -- is consistent with the signing key. The signature + * is produced by dispatching on the key while the OID is written from sType, + * so a mismatch would emit a certificate whose advertised algorithm + * contradicts the key that signed it (e.g. leaving the wc_InitCert default of + * CTC_SHA256wRSA on a non-RSA key). For RSA/ECC the hash is free to vary, so + * the whole signature-algorithm family is accepted; the remaining algorithms + * have a single (level/parameter-determined) OID. Returns 0 if consistent or + * if there is no key to check, ALGO_ID_E on a mismatch. */ +static int CheckSigTypeForKey(int sType, RsaKey* rsaKey, ecc_key* eccKey, + ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, + wc_MlDsaKey* mldsaKey, SlhDsaKey* slhDsaKey, LmsKey* lmsKey, + XmssKey* xmssKey) +{ + (void)sType; + (void)rsaKey; (void)eccKey; (void)ed25519Key; (void)ed448Key; + (void)falconKey; (void)mldsaKey; (void)slhDsaKey; (void)lmsKey; + (void)xmssKey; + +#ifdef WOLFSSL_DUAL_ALG_CERTS + /* sigType 0 indicates preTBS encoding: no signatureAlgorithm to validate. */ + if (sType == 0) + return 0; +#endif + +#ifndef NO_RSA + if (rsaKey != NULL) + return IsRsaSigType(sType) ? 0 : ALGO_ID_E; +#endif +#ifdef HAVE_ECC + if (eccKey != NULL) + return IsEccSigType(sType) ? 0 : ALGO_ID_E; +#endif +#ifdef HAVE_ED25519 + if (ed25519Key != NULL) + return (sType == CTC_ED25519) ? 0 : ALGO_ID_E; +#endif +#ifdef HAVE_ED448 + if (ed448Key != NULL) + return (sType == CTC_ED448) ? 0 : ALGO_ID_E; +#endif +#ifdef HAVE_FALCON + if (falconKey != NULL) { + if (falconKey->level == 1) + return (sType == CTC_FALCON_LEVEL1) ? 0 : ALGO_ID_E; + if (falconKey->level == 5) + return (sType == CTC_FALCON_LEVEL5) ? 0 : ALGO_ID_E; + return ALGO_ID_E; + } +#endif +#ifdef WOLFSSL_HAVE_MLDSA + if (mldsaKey != NULL) { + if (mldsaKey->params == NULL) + return ALGO_ID_E; + #ifdef WOLFSSL_MLDSA_FIPS204_DRAFT + if (mldsaKey->params->level == WC_ML_DSA_44_DRAFT) + return (sType == CTC_DILITHIUM_LEVEL2) ? 0 : ALGO_ID_E; + if (mldsaKey->params->level == WC_ML_DSA_65_DRAFT) + return (sType == CTC_DILITHIUM_LEVEL3) ? 0 : ALGO_ID_E; + if (mldsaKey->params->level == WC_ML_DSA_87_DRAFT) + return (sType == CTC_DILITHIUM_LEVEL5) ? 0 : ALGO_ID_E; + #endif + if (mldsaKey->level == WC_ML_DSA_44) + return (sType == CTC_ML_DSA_44) ? 0 : ALGO_ID_E; + if (mldsaKey->level == WC_ML_DSA_65) + return (sType == CTC_ML_DSA_65) ? 0 : ALGO_ID_E; + if (mldsaKey->level == WC_ML_DSA_87) + return (sType == CTC_ML_DSA_87) ? 0 : ALGO_ID_E; + return ALGO_ID_E; + } +#endif +#ifdef WOLFSSL_HAVE_SLHDSA + if (slhDsaKey != NULL) { + /* SLH-DSA uses one OID per parameter set for both the key and the + * signature, so the key OID sum equals the CTC signature value. */ + int oid; + if (slhDsaKey->params == NULL) + return ALGO_ID_E; + oid = wc_SlhDsaParamToOid(slhDsaKey->params->param); + if (oid < 0) + return ALGO_ID_E; + return (sType == oid) ? 0 : ALGO_ID_E; + } +#endif +#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) + if (lmsKey != NULL) + return (sType == CTC_HSS_LMS) ? 0 : ALGO_ID_E; +#endif +#if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY) + if (xmssKey != NULL) { + if (xmssKey->is_xmssmt) + return (sType == CTC_XMSSMT) ? 0 : ALGO_ID_E; + return (sType == CTC_XMSS) ? 0 : ALGO_ID_E; + } +#endif + + return 0; +} + /* Make signature from buffer (sz), write to sig (sigSz) * This function now uses MakeSignatureCb internally for RSA and ECC, * eliminating code duplication. Ed25519, Ed448, and post-quantum algorithms @@ -28283,8 +28685,8 @@ static int InternalSignCb(const byte* in, word32 inLen, static int MakeSignature(CertSignCtx* certSignCtx, const byte* buf, word32 sz, byte* sig, word32 sigSz, RsaKey* rsaKey, ecc_key* eccKey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, - wc_MlDsaKey* mldsaKey, SlhDsaKey* slhDsaKey, WC_RNG* rng, - word32 sigAlgoType, void* heap) + wc_MlDsaKey* mldsaKey, SlhDsaKey* slhDsaKey, LmsKey* lmsKey, + XmssKey* xmssKey, WC_RNG* rng, word32 sigAlgoType, void* heap) { int ret = 0; @@ -28297,6 +28699,8 @@ static int MakeSignature(CertSignCtx* certSignCtx, const byte* buf, word32 sz, (void)falconKey; (void)mldsaKey; (void)slhDsaKey; + (void)lmsKey; + (void)xmssKey; (void)rng; (void)heap; @@ -28390,6 +28794,26 @@ static int MakeSignature(CertSignCtx* certSignCtx, const byte* buf, word32 sz, } #endif /* WOLFSSL_HAVE_SLHDSA && !WOLFSSL_SLHDSA_VERIFY_ONLY */ +#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) + if (lmsKey) { + word32 outSz = sigSz; + /* RFC 9802: the TBS is signed directly with no pre-hash. */ + ret = wc_LmsKey_Sign(lmsKey, sig, &outSz, buf, (int)sz); + if (ret == 0) + ret = (int)outSz; + } +#endif /* WOLFSSL_HAVE_LMS && !WOLFSSL_LMS_VERIFY_ONLY */ + +#if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY) + if (xmssKey) { + word32 outSz = sigSz; + /* RFC 9802: the TBS is signed directly with no pre-hash. */ + ret = wc_XmssKey_Sign(xmssKey, sig, &outSz, buf, (int)sz); + if (ret == 0) + ret = (int)outSz; + } +#endif /* WOLFSSL_HAVE_XMSS && !WOLFSSL_XMSS_VERIFY_ONLY */ + if (ret == -1) ret = ALGO_ID_E; @@ -28537,7 +28961,8 @@ static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey, ecc_key* eccKey, WC_RNG* rng, DsaKey* dsaKey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, - wc_MlDsaKey* mldsaKey, SlhDsaKey* slhDsaKey) + wc_MlDsaKey* mldsaKey, SlhDsaKey* slhDsaKey, + LmsKey* lmsKey, XmssKey* xmssKey) { /* TODO: issRaw and sbjRaw should be NUL terminated. */ DECL_ASNSETDATA(dataASN, x509CertASN_Length); @@ -28554,6 +28979,8 @@ static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz, (void)falconKey; (void)mldsaKey; (void)slhDsaKey; + (void)lmsKey; + (void)xmssKey; CALLOC_ASNSETDATA(dataASN, x509CertASN_Length, ret, cert->heap); @@ -28621,6 +29048,16 @@ static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz, } } #endif /* WOLFSSL_HAVE_SLHDSA */ +#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) + else if (lmsKey != NULL) { + cert->keyType = LMS_KEY; + } +#endif /* WOLFSSL_HAVE_LMS && !WOLFSSL_LMS_VERIFY_ONLY */ +#if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY) + else if (xmssKey != NULL) { + cert->keyType = xmssKey->is_xmssmt ? XMSSMT_KEY : XMSS_KEY; + } +#endif /* WOLFSSL_HAVE_XMSS && !WOLFSSL_XMSS_VERIFY_ONLY */ else { ret = BAD_FUNC_ARG; } @@ -28669,7 +29106,7 @@ static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz, /* Calculate public key encoding size. */ ret = EncodePublicKey(cert->keyType, NULL, 0, rsaKey, eccKey, ed25519Key, ed448Key, dsaKey, falconKey, - mldsaKey, slhDsaKey); + mldsaKey, slhDsaKey, lmsKey, xmssKey); publicKeySz = (word32)ret; } if (ret >= 0) { @@ -28856,7 +29293,7 @@ static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz, (int)dataASN[X509CERTASN_IDX_TBS_SPUBKEYINFO_SEQ] .data.buffer.length, rsaKey, eccKey, ed25519Key, ed448Key, dsaKey, - falconKey, mldsaKey, slhDsaKey); + falconKey, mldsaKey, slhDsaKey, lmsKey, xmssKey); } if ((ret >= 0) && (!dataASN[X509CERTASN_IDX_TBS_EXT_SEQ].noOut)) { /* Encode extensions into buffer. */ @@ -28901,6 +29338,8 @@ int wc_MakeCert_ex(Cert* cert, byte* derBuffer, word32 derSz, int keyType, falcon_key* falconKey = NULL; wc_MlDsaKey* mldsaKey = NULL; SlhDsaKey* slhDsaKey = NULL; + LmsKey* lmsKey = NULL; + XmssKey* xmssKey = NULL; if (keyType == RSA_TYPE) rsaKey = (RsaKey*)key; @@ -28934,10 +29373,28 @@ int wc_MakeCert_ex(Cert* cert, byte* derBuffer, word32 derSz, int keyType, else if (IsSlhDsaKeyType(keyType)) slhDsaKey = (SlhDsaKey*)key; #endif +#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) + else if (keyType == LMS_TYPE) + lmsKey = (LmsKey*)key; +#endif +#if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY) + /* The selector must match the key's actual tree variant so XMSS_TYPE and + * XMSSMT_TYPE are not silently interchangeable. */ + else if (keyType == XMSS_TYPE) { + xmssKey = (XmssKey*)key; + if (xmssKey != NULL && xmssKey->is_xmssmt) + return BAD_FUNC_ARG; + } + else if (keyType == XMSSMT_TYPE) { + xmssKey = (XmssKey*)key; + if (xmssKey != NULL && !xmssKey->is_xmssmt) + return BAD_FUNC_ARG; + } +#endif return MakeAnyCert(cert, derBuffer, derSz, rsaKey, eccKey, rng, dsaKey, ed25519Key, ed448Key, falconKey, mldsaKey, - slhDsaKey); + slhDsaKey, lmsKey, xmssKey); } /* Make an x509 Certificate v3 RSA or ECC from cert input, write to buffer */ @@ -28946,7 +29403,7 @@ int wc_MakeCert(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey, ecc_key* eccKey, WC_RNG* rng) { return MakeAnyCert(cert, derBuffer, derSz, rsaKey, eccKey, rng, NULL, NULL, - NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, NULL, NULL); } @@ -29014,7 +29471,7 @@ static int MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey, DsaKey* dsaKey, ecc_key* eccKey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, wc_MlDsaKey* mldsaKey, - SlhDsaKey* slhDsaKey) + SlhDsaKey* slhDsaKey, LmsKey* lmsKey, XmssKey* xmssKey) { DECL_ASNSETDATA(dataASN, certReqBodyASN_Length); word32 publicKeySz = 0; @@ -29030,6 +29487,8 @@ static int MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, (void)falconKey; (void)mldsaKey; (void)slhDsaKey; + (void)lmsKey; + (void)xmssKey; CALLOC_ASNSETDATA(dataASN, certReqBodyASN_Length, ret, cert->heap); @@ -29097,6 +29556,16 @@ static int MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, } } #endif /* WOLFSSL_HAVE_SLHDSA */ +#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) + else if (lmsKey != NULL) { + cert->keyType = LMS_KEY; + } +#endif /* WOLFSSL_HAVE_LMS && !WOLFSSL_LMS_VERIFY_ONLY */ +#if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY) + else if (xmssKey != NULL) { + cert->keyType = xmssKey->is_xmssmt ? XMSSMT_KEY : XMSS_KEY; + } +#endif /* WOLFSSL_HAVE_XMSS && !WOLFSSL_XMSS_VERIFY_ONLY */ else { ret = BAD_FUNC_ARG; } @@ -29119,7 +29588,7 @@ static int MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, /* Determine encode public key size. */ ret = EncodePublicKey(cert->keyType, NULL, 0, rsaKey, eccKey, ed25519Key, ed448Key, dsaKey, falconKey, - mldsaKey, slhDsaKey); + mldsaKey, slhDsaKey, lmsKey, xmssKey); publicKeySz = (word32)ret; } if (ret >= 0) { @@ -29239,7 +29708,7 @@ static int MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, dataASN[CERTREQBODYASN_IDX_SPUBKEYINFO_SEQ].data.buffer.data, (int)dataASN[CERTREQBODYASN_IDX_SPUBKEYINFO_SEQ].data.buffer.length, rsaKey, eccKey, ed25519Key, ed448Key, dsaKey, falconKey, - mldsaKey, slhDsaKey); + mldsaKey, slhDsaKey, lmsKey, xmssKey); } if ((ret >= 0 && derBuffer != NULL) && (!dataASN[CERTREQBODYASN_IDX_EXT_BODY].noOut)) { @@ -29273,6 +29742,8 @@ int wc_MakeCertReq_ex(Cert* cert, byte* derBuffer, word32 derSz, int keyType, falcon_key* falconKey = NULL; wc_MlDsaKey* mldsaKey = NULL; SlhDsaKey* slhDsaKey = NULL; + LmsKey* lmsKey = NULL; + XmssKey* xmssKey = NULL; if (keyType == RSA_TYPE) rsaKey = (RsaKey*)key; @@ -29306,10 +29777,28 @@ int wc_MakeCertReq_ex(Cert* cert, byte* derBuffer, word32 derSz, int keyType, else if (IsSlhDsaKeyType(keyType)) slhDsaKey = (SlhDsaKey*)key; #endif +#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) + else if (keyType == LMS_TYPE) + lmsKey = (LmsKey*)key; +#endif +#if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY) + /* The selector must match the key's actual tree variant so XMSS_TYPE and + * XMSSMT_TYPE are not silently interchangeable. */ + else if (keyType == XMSS_TYPE) { + xmssKey = (XmssKey*)key; + if (xmssKey != NULL && xmssKey->is_xmssmt) + return BAD_FUNC_ARG; + } + else if (keyType == XMSSMT_TYPE) { + xmssKey = (XmssKey*)key; + if (xmssKey != NULL && !xmssKey->is_xmssmt) + return BAD_FUNC_ARG; + } +#endif return MakeCertReq(cert, derBuffer, derSz, rsaKey, dsaKey, eccKey, ed25519Key, ed448Key, falconKey, mldsaKey, - slhDsaKey); + slhDsaKey, lmsKey, xmssKey); } WOLFSSL_ABI @@ -29317,7 +29806,7 @@ int wc_MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey, ecc_key* eccKey) { return MakeCertReq(cert, derBuffer, derSz, rsaKey, NULL, eccKey, NULL, - NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, NULL, NULL); } #endif /* WOLFSSL_CERT_REQ */ @@ -29464,10 +29953,13 @@ static int SignCert(int requestSz, int sType, byte* buf, word32 buffSz, RsaKey* rsaKey, ecc_key* eccKey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, wc_MlDsaKey* mldsaKey, SlhDsaKey* slhDsaKey, - WC_RNG* rng) + LmsKey* lmsKey, XmssKey* xmssKey, WC_RNG* rng) { int sigSz = 0; + int ret; void* heap = NULL; + /* The signature buffer is sized from the key at runtime. */ + int maxSigSz; CertSignCtx certSignCtx_lcl; CertSignCtx* certSignCtx = &certSignCtx_lcl; @@ -29476,13 +29968,13 @@ static int SignCert(int requestSz, int sType, byte* buf, word32 buffSz, if (requestSz < 0) return requestSz; - /* locate ctx */ + /* Async crypto reuses the signing key's embedded CertSignCtx; only RSA and + * ECC keys carry one. */ if (rsaKey) { #ifndef NO_RSA #ifdef WOLFSSL_ASYNC_CRYPT certSignCtx = &rsaKey->certSignCtx; #endif - heap = rsaKey->heap; #else return NOT_COMPILED_IN; #endif /* NO_RSA */ @@ -29492,24 +29984,51 @@ static int SignCert(int requestSz, int sType, byte* buf, word32 buffSz, #ifdef WOLFSSL_ASYNC_CRYPT certSignCtx = &eccKey->certSignCtx; #endif - heap = eccKey->heap; #else return NOT_COMPILED_IN; #endif /* HAVE_ECC */ } + heap = GetSigningKeyHeap(rsaKey, eccKey, ed25519Key, ed448Key, mldsaKey, + slhDsaKey, lmsKey, xmssKey); + + /* The signatureAlgorithm OID is written from sType while the signature is + * produced from the key, so reject a mismatch rather than emit a cert + * whose advertised algorithm contradicts the signing key. */ + ret = CheckSigTypeForKey(sType, rsaKey, eccKey, ed25519Key, ed448Key, + falconKey, mldsaKey, slhDsaKey, lmsKey, xmssKey); + if (ret != 0) { + WOLFSSL_MSG("Signature type does not match signing key"); + return ret; + } + + /* Size the signature buffer from the key in use. */ + maxSigSz = GetSignatureBufferSz(rsaKey, eccKey, ed25519Key, ed448Key, + falconKey, mldsaKey, slhDsaKey, lmsKey, xmssKey); + if (maxSigSz <= 0) + return (maxSigSz < 0) ? maxSigSz : ALGO_ID_E; #ifndef WOLFSSL_NO_MALLOC if (certSignCtx->sig == NULL) { - certSignCtx->sig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, heap, + certSignCtx->sig = (byte*)XMALLOC((word32)maxSigSz, heap, DYNAMIC_TYPE_TMP_BUFFER); if (certSignCtx->sig == NULL) return MEMORY_E; } +#else + /* Without dynamic memory the signature buffer is a fixed + * WOLFSSL_MAX_SIG_SZ array in CertSignCtx. LMS/XMSS signatures are + * parameter-dependent and can be larger, so reject rather than overflow + * the fixed buffer. */ + if ((word32)maxSigSz > WOLFSSL_MAX_SIG_SZ) { + WOLFSSL_MSG("Signature larger than fixed CertSignCtx buffer"); + return BUFFER_E; + } #endif sigSz = MakeSignature(certSignCtx, buf, (word32)requestSz, certSignCtx->sig, - MAX_ENCODED_SIG_SZ, rsaKey, eccKey, ed25519Key, ed448Key, - falconKey, mldsaKey, slhDsaKey, rng, (word32)sType, heap); + (word32)maxSigSz, rsaKey, eccKey, ed25519Key, ed448Key, + falconKey, mldsaKey, slhDsaKey, lmsKey, xmssKey, rng, (word32)sType, + heap); #ifdef WOLFSSL_ASYNC_CRYPT if (sigSz == WC_NO_ERR_TRACE(WC_PENDING_E)) { /* Not free'ing certSignCtx->sig here because it could still be in use @@ -29562,6 +30081,7 @@ int wc_MakeSigWithBitStr(byte *sig, int sigSz, int sType, byte* buf, SlhDsaKey* slhDsaKey = NULL; int ret = 0; int headerSz; + int maxSigSz; void* heap = NULL; CertSignCtx certSignCtx_lcl; CertSignCtx* certSignCtx = &certSignCtx_lcl; @@ -29622,13 +30142,13 @@ int wc_MakeSigWithBitStr(byte *sig, int sigSz, int sType, byte* buf, return BAD_FUNC_ARG; } - /* locate ctx */ + /* Async crypto reuses the signing key's embedded CertSignCtx; only RSA and + * ECC keys carry one. */ if (rsaKey) { #ifndef NO_RSA #ifdef WOLFSSL_ASYNC_CRYPT certSignCtx = &rsaKey->certSignCtx; #endif - heap = rsaKey->heap; #else return NOT_COMPILED_IN; #endif /* NO_RSA */ @@ -29638,24 +30158,46 @@ int wc_MakeSigWithBitStr(byte *sig, int sigSz, int sType, byte* buf, #ifdef WOLFSSL_ASYNC_CRYPT certSignCtx = &eccKey->certSignCtx; #endif - heap = eccKey->heap; #else return NOT_COMPILED_IN; #endif /* HAVE_ECC */ } + heap = GetSigningKeyHeap(rsaKey, eccKey, ed25519Key, ed448Key, mldsaKey, + slhDsaKey, NULL, NULL); + + /* The signatureAlgorithm OID is written from sType while the signature is + * produced from the key, so reject a mismatch rather than emit a cert + * whose advertised algorithm contradicts the signing key. */ + ret = CheckSigTypeForKey(sType, rsaKey, eccKey, ed25519Key, ed448Key, + falconKey, mldsaKey, slhDsaKey, NULL, NULL); + if (ret != 0) { + WOLFSSL_MSG("Signature type does not match signing key"); + return ret; + } + + /* Size the signature buffer from the key in use. */ + maxSigSz = GetSignatureBufferSz(rsaKey, eccKey, ed25519Key, ed448Key, + falconKey, mldsaKey, slhDsaKey, NULL, NULL); + if (maxSigSz <= 0) + return (maxSigSz < 0) ? maxSigSz : ALGO_ID_E; #ifndef WOLFSSL_NO_MALLOC if (certSignCtx->sig == NULL) { - certSignCtx->sig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, heap, + certSignCtx->sig = (byte*)XMALLOC((word32)maxSigSz, heap, DYNAMIC_TYPE_TMP_BUFFER); if (certSignCtx->sig == NULL) return MEMORY_E; } +#else + if ((word32)maxSigSz > WOLFSSL_MAX_SIG_SZ) { + WOLFSSL_MSG("Signature larger than fixed CertSignCtx buffer"); + return BUFFER_E; + } #endif ret = MakeSignature(certSignCtx, buf, (word32)bufSz, certSignCtx->sig, - MAX_ENCODED_SIG_SZ, rsaKey, eccKey, ed25519Key, ed448Key, - falconKey, mldsaKey, slhDsaKey, rng, (word32)sType, heap); + (word32)maxSigSz, rsaKey, eccKey, ed25519Key, ed448Key, + falconKey, mldsaKey, slhDsaKey, NULL, NULL, rng, (word32)sType, heap); #ifdef WOLFSSL_ASYNC_CRYPT if (ret == WC_NO_ERR_TRACE(WC_PENDING_E)) { /* Not free'ing certSignCtx->sig here because it could still be in use @@ -29715,6 +30257,8 @@ int wc_SignCert_ex(int requestSz, int sType, byte* buf, word32 buffSz, falcon_key* falconKey = NULL; wc_MlDsaKey* mldsaKey = NULL; SlhDsaKey* slhDsaKey = NULL; + LmsKey* lmsKey = NULL; + XmssKey* xmssKey = NULL; if (keyType == RSA_TYPE) rsaKey = (RsaKey*)key; @@ -29746,16 +30290,35 @@ int wc_SignCert_ex(int requestSz, int sType, byte* buf, word32 buffSz, else if (IsSlhDsaKeyType(keyType)) slhDsaKey = (SlhDsaKey*)key; #endif +#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) + else if (keyType == LMS_TYPE) + lmsKey = (LmsKey*)key; +#endif +#if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY) + /* The selector must match the key's actual tree variant so XMSS_TYPE and + * XMSSMT_TYPE are not silently interchangeable. */ + else if (keyType == XMSS_TYPE) { + xmssKey = (XmssKey*)key; + if (xmssKey != NULL && xmssKey->is_xmssmt) + return BAD_FUNC_ARG; + } + else if (keyType == XMSSMT_TYPE) { + xmssKey = (XmssKey*)key; + if (xmssKey != NULL && !xmssKey->is_xmssmt) + return BAD_FUNC_ARG; + } +#endif return SignCert(requestSz, sType, buf, buffSz, rsaKey, eccKey, ed25519Key, - ed448Key, falconKey, mldsaKey, slhDsaKey, rng); + ed448Key, falconKey, mldsaKey, slhDsaKey, lmsKey, xmssKey, + rng); } int wc_SignCert(int requestSz, int sType, byte* buf, word32 buffSz, RsaKey* rsaKey, ecc_key* eccKey, WC_RNG* rng) { return SignCert(requestSz, sType, buf, buffSz, rsaKey, eccKey, NULL, NULL, - NULL, NULL, NULL, rng); + NULL, NULL, NULL, NULL, NULL, rng); } /* Sign certificate/CSR using a callback function @@ -29786,6 +30349,7 @@ int wc_SignCert_cb(int requestSz, int sType, byte* buf, word32 buffSz, WC_RNG* rng) { int sigSz = 0; + word32 sigCap = MAX_ENCODED_CLASSIC_SIG_SZ; CertSignCtx certSignCtx_lcl; CertSignCtx* certSignCtx = &certSignCtx_lcl; @@ -29812,22 +30376,40 @@ int wc_SignCert_cb(int requestSz, int sType, byte* buf, word32 buffSz, return NOT_COMPILED_IN; #endif + /* The callback produces the signature for keyType while the cert's + * signatureAlgorithm OID is written from sType, so reject a family + * mismatch (e.g. an ECDSA OID with an RSA key). */ +#ifndef NO_RSA + if (keyType == RSA_TYPE && !IsRsaSigType(sType)) + return ALGO_ID_E; +#endif +#ifdef HAVE_ECC + if (keyType == ECC_TYPE && !IsEccSigType(sType)) + return ALGO_ID_E; +#endif + XMEMSET(certSignCtx, 0, sizeof(*certSignCtx)); if (requestSz < 0) { return requestSz; } + /* keyType is restricted to RSA_TYPE/ECC_TYPE above, so the signature is + * a classic (non-PQC) one and fits MAX_ENCODED_CLASSIC_SIG_SZ. */ #ifndef WOLFSSL_NO_MALLOC - certSignCtx->sig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, NULL, + certSignCtx->sig = (byte*)XMALLOC(MAX_ENCODED_CLASSIC_SIG_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (certSignCtx->sig == NULL) { return MEMORY_E; } +#else + /* Don't claim more capacity than the fixed sig buffer really has. */ + if (sigCap > (word32)sizeof(certSignCtx->sig)) + sigCap = (word32)sizeof(certSignCtx->sig); #endif sigSz = MakeSignatureCb(certSignCtx, buf, (word32)requestSz, - certSignCtx->sig, MAX_ENCODED_SIG_SZ, sType, keyType, + certSignCtx->sig, sigCap, sType, keyType, signCb, signCtx, rng, NULL); #ifdef WOLFSSL_ASYNC_CRYPT @@ -30242,6 +30824,9 @@ int wc_SetAuthKeyIdFromCert(Cert *cert, const byte *der, int derSz) if (cert == NULL) { ret = BAD_FUNC_ARG; } + else if (derSz < 0) { + ret = BAD_FUNC_ARG; + } else { /* Check if decodedCert is cached */ if (cert->der != der) { @@ -30746,6 +31331,9 @@ int wc_SetIssuerBuffer(Cert* cert, const byte* der, int derSz) if (cert == NULL) { ret = BAD_FUNC_ARG; } + else if (derSz < 0) { + ret = BAD_FUNC_ARG; + } else { cert->selfSigned = 0; @@ -30775,6 +31363,9 @@ int wc_SetSubjectBuffer(Cert* cert, const byte* der, int derSz) if (cert == NULL) { ret = BAD_FUNC_ARG; } + else if (derSz < 0) { + ret = BAD_FUNC_ARG; + } else { /* Check if decodedCert is cached */ if (cert->der != der) { @@ -30802,6 +31393,9 @@ int wc_SetSubjectRaw(Cert* cert, const byte* der, int derSz) if (cert == NULL) { ret = BAD_FUNC_ARG; } + else if (derSz < 0) { + ret = BAD_FUNC_ARG; + } else { /* Check if decodedCert is cached */ if (cert->der != der) { @@ -30836,6 +31430,9 @@ int wc_SetIssuerRaw(Cert* cert, const byte* der, int derSz) if (cert == NULL) { ret = BAD_FUNC_ARG; } + else if (derSz < 0) { + ret = BAD_FUNC_ARG; + } else { /* Check if decodedCert is cached */ if (cert->der != der) { @@ -30873,6 +31470,9 @@ int wc_SetAltNamesBuffer(Cert* cert, const byte* der, int derSz) if (cert == NULL) { ret = BAD_FUNC_ARG; } + else if (derSz < 0) { + ret = BAD_FUNC_ARG; + } else { /* Check if decodedCert is cached */ if (cert->der != der) { @@ -30900,6 +31500,9 @@ int wc_SetDatesBuffer(Cert* cert, const byte* der, int derSz) if (cert == NULL) { ret = BAD_FUNC_ARG; } + else if (derSz < 0) { + ret = BAD_FUNC_ARG; + } else { /* Check if decodedCert is cached */ if (cert->der != der) { @@ -31944,10 +32547,7 @@ static int eccToPKCS8(ecc_key* key, byte* output, word32* outLen, ret = wc_BuildEccKeyDer(key, tmpDer, &sz, includePublic, 0); if (ret < 0) { - #ifndef WOLFSSL_NO_MALLOC - XFREE(tmpDer, key->heap, DYNAMIC_TYPE_TMP_BUFFER); - #endif - return ret; + goto exit; } tmpDerSz = (word32)ret; @@ -31955,42 +32555,36 @@ static int eccToPKCS8(ecc_key* key, byte* output, word32* outLen, ret = wc_CreatePKCS8Key(NULL, &pkcs8Sz, tmpDer, tmpDerSz, algoID, curveOID, oidSz); if (ret != WC_NO_ERR_TRACE(LENGTH_ONLY_E)) { - #ifndef WOLFSSL_NO_MALLOC - XFREE(tmpDer, key->heap, DYNAMIC_TYPE_TMP_BUFFER); - #endif - return ret; + goto exit; } if (output == NULL) { - #ifndef WOLFSSL_NO_MALLOC - XFREE(tmpDer, key->heap, DYNAMIC_TYPE_TMP_BUFFER); - #endif *outLen = pkcs8Sz; - return WC_NO_ERR_TRACE(LENGTH_ONLY_E); - + ret = WC_NO_ERR_TRACE(LENGTH_ONLY_E); + goto exit; } else if (*outLen < pkcs8Sz) { - #ifndef WOLFSSL_NO_MALLOC - XFREE(tmpDer, key->heap, DYNAMIC_TYPE_TMP_BUFFER); - #endif WOLFSSL_MSG("Input buffer too small for ECC PKCS#8 key"); - return BUFFER_E; + ret = BUFFER_E; + goto exit; } ret = wc_CreatePKCS8Key(output, &pkcs8Sz, tmpDer, tmpDerSz, algoID, curveOID, oidSz); if (ret < 0) { - #ifndef WOLFSSL_NO_MALLOC - XFREE(tmpDer, key->heap, DYNAMIC_TYPE_TMP_BUFFER); - #endif - return ret; + goto exit; } + *outLen = (word32)ret; + +exit: + /* tmpDer holds a plaintext copy of the ECC private key - always zeroize + * it before releasing (or before the stack buffer goes out of scope). */ + ForceZero(tmpDer, ECC_BUFSIZE); #ifndef WOLFSSL_NO_MALLOC XFREE(tmpDer, key->heap, DYNAMIC_TYPE_TMP_BUFFER); #endif - *outLen = (word32)ret; return ret; } @@ -33933,7 +34527,7 @@ static int OcspRespIdMatch(OcspResponse *resp, const byte *NameHash, } #ifndef WOLFSSL_NO_OCSP_ISSUER_CHECK -static int OcspRespCheck(OcspResponse *resp, Signer *responder, void* vp) +static int OcspRespCheck(OcspResponse *resp, Signer *responder) { OcspEntry *s; int ret; @@ -33948,7 +34542,7 @@ static int OcspRespCheck(OcspResponse *resp, Signer *responder, void* vp) ret = CheckOcspResponder(resp, responder->subjectNameHash, responder->subjectKeyHash, responder->extKeyUsage, - responder->issuerNameHash, responder->issuerKeyHash, vp); + responder->issuerNameHash, responder->issuerKeyHash); if (ret != 0) return -1; @@ -34038,7 +34632,7 @@ static int OcspCheckCert(OcspResponse *resp, int noVerify, if (ret == 0 && !noVerify) { ret = CheckOcspResponder(resp, cert->subjectHash, cert->subjectKeyHash, cert->extExtKeyUsage, cert->issuerHash, - (cert->ca != NULL) ? cert->ca->subjectKeyHash : NULL, cm); + (cert->ca != NULL) ? cert->ca->subjectKeyHash : NULL); if (ret != 0) { WOLFSSL_MSG("\tOCSP Responder certificate issuer check failed"); goto err; @@ -34150,7 +34744,7 @@ WC_MAYBE_UNUSED static int EncodeBasicOcspResponse(OcspResponse* resp, XMEMSET(&certSignCtx, 0, sizeof(CertSignCtx)); ret = MakeSignature(&certSignCtx, respData, respDataSz, sigData, sigSz, rsaKey, eccKey, NULL, NULL, NULL, NULL, - NULL, rng, resp->sigOID, resp->heap); + NULL, NULL, NULL, rng, resp->sigOID, resp->heap); if (ret > 0) { sigSz = (word32)ret; ret = 0; @@ -34259,7 +34853,7 @@ static int DecodeBasicOcspResponse(const byte* source, word32* ioIndex, } #ifndef WOLFSSL_NO_OCSP_ISSUER_CHECK if (ret == 0 && !noVerifySignature && !sigValid) { - if (OcspRespCheck(resp, ca, cm) != 0) { + if (OcspRespCheck(resp, ca) != 0) { ret = BAD_OCSP_RESPONDER; } } @@ -36326,6 +36920,7 @@ int wc_SignCRL_ex(const byte* tbsBuf, int tbsSz, int sType, { int ret; int sigSz; + word32 sigCap = MAX_ENCODED_CLASSIC_SIG_SZ; CertSignCtx certSignCtx_lcl; CertSignCtx* certSignCtx = &certSignCtx_lcl; void* heap = NULL; @@ -36337,38 +36932,44 @@ int wc_SignCRL_ex(const byte* tbsBuf, int tbsSz, int sType, if (rsaKey != NULL && eccKey != NULL) return BAD_FUNC_ARG; + /* The CRL's signatureAlgorithm OID is written from sType while the + * signature is produced from the key, so reject a mismatch. */ + ret = CheckSigTypeForKey(sType, rsaKey, eccKey, NULL, NULL, NULL, NULL, + NULL, NULL, NULL); + if (ret != 0) { + WOLFSSL_MSG("Signature type does not match signing key"); + return ret; + } + XMEMSET(certSignCtx, 0, sizeof(*certSignCtx)); -#ifndef NO_RSA - if (rsaKey != NULL) { - heap = rsaKey->heap; - } -#endif -#ifdef HAVE_ECC - if (eccKey != NULL) { - heap = eccKey->heap; - } -#endif + heap = GetSigningKeyHeap(rsaKey, eccKey, NULL, NULL, NULL, NULL, NULL, NULL); /* Copy TBS to output buffer first */ if ((word32)tbsSz > bufSz) return BUFFER_E; XMEMCPY(buf, tbsBuf, (size_t)tbsSz); + /* Only RSA/ECC keys are accepted above, so the signature is a classic + * (non-PQC) one and fits MAX_ENCODED_CLASSIC_SIG_SZ. */ #ifndef WOLFSSL_NO_MALLOC - certSignCtx->sig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, heap, + certSignCtx->sig = (byte*)XMALLOC(MAX_ENCODED_CLASSIC_SIG_SZ, heap, DYNAMIC_TYPE_TMP_BUFFER); if (certSignCtx->sig == NULL) return MEMORY_E; /* Initialize first byte to avoid static analysis warnings about using * uninitialized memory if MakeSignature fails before writing sig. */ certSignCtx->sig[0] = 0; +#else + /* Don't claim more capacity than the fixed sig buffer really has. */ + if (sigCap > (word32)sizeof(certSignCtx->sig)) + sigCap = (word32)sizeof(certSignCtx->sig); #endif /* Create signature */ sigSz = MakeSignature(certSignCtx, buf, (word32)tbsSz, certSignCtx->sig, - MAX_ENCODED_SIG_SZ, rsaKey, eccKey, NULL, NULL, NULL, - NULL, NULL, rng, (word32)sType, heap); + sigCap, rsaKey, eccKey, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, rng, (word32)sType, heap); if (sigSz < 0) { #ifndef WOLFSSL_NO_MALLOC XFREE(certSignCtx->sig, heap, DYNAMIC_TYPE_TMP_BUFFER); diff --git a/wolfcrypt/src/asn_orig.c b/wolfcrypt/src/asn_orig.c index f1e67ff4f5..375da8eaf0 100644 --- a/wolfcrypt/src/asn_orig.c +++ b/wolfcrypt/src/asn_orig.c @@ -6594,11 +6594,23 @@ static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey, ecc_key* eccKey, WC_RNG* rng, DsaKey* dsaKey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, - wc_MlDsaKey* mldsaKey, SlhDsaKey* slhDsaKey) + wc_MlDsaKey* mldsaKey, SlhDsaKey* slhDsaKey, + LmsKey* lmsKey, XmssKey* xmssKey) { int ret; WC_DECLARE_VAR(der, DerCert, 1, 0); + /* RFC 9802 LMS/XMSS support (both verification and generation) lives only + * in the ASN.1 template encoder; this original/non-template path has no + * LMS/XMSS code at all. Rather than duplicate the encoding here for a + * legacy path that could not verify such certs anyway, generation is + * template-only and rejected here with a clear diagnostic. */ + if ((lmsKey != NULL) || (xmssKey != NULL)) { + WOLFSSL_MSG("LMS/XMSS certificate generation requires " + "WOLFSSL_ASN_TEMPLATE"); + return ALGO_ID_E; + } + if (derBuffer == NULL) return BAD_FUNC_ARG; @@ -7227,11 +7239,19 @@ static int MakeCertReq(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey, DsaKey* dsaKey, ecc_key* eccKey, ed25519_key* ed25519Key, ed448_key* ed448Key, falcon_key* falconKey, wc_MlDsaKey* mldsaKey, - SlhDsaKey* slhDsaKey) + SlhDsaKey* slhDsaKey, LmsKey* lmsKey, XmssKey* xmssKey) { int ret; WC_DECLARE_VAR(der, DerCert, 1, 0); + /* LMS/XMSS certificate request generation is only supported with + * WOLFSSL_ASN_TEMPLATE. */ + if ((lmsKey != NULL) || (xmssKey != NULL)) { + WOLFSSL_MSG("LMS/XMSS certificate request generation requires " + "WOLFSSL_ASN_TEMPLATE"); + return ALGO_ID_E; + } + if (eccKey) cert->keyType = ECC_KEY; else if (rsaKey) @@ -8830,7 +8850,7 @@ static int DecodeBasicOcspResponse(byte* source, word32* ioIndex, return ASN_NO_SIGNER_E; #ifndef WOLFSSL_NO_OCSP_ISSUER_CHECK - if (OcspRespCheck(resp, ca, cm) != 0) + if (OcspRespCheck(resp, ca) != 0) return BAD_OCSP_RESPONDER; #endif InitSignatureCtx(&sigCtx, heap, INVALID_DEVID); diff --git a/wolfcrypt/src/chacha20_poly1305.c b/wolfcrypt/src/chacha20_poly1305.c index 75b9b094d1..e9e5bb80c4 100644 --- a/wolfcrypt/src/chacha20_poly1305.c +++ b/wolfcrypt/src/chacha20_poly1305.c @@ -465,7 +465,9 @@ static WC_INLINE int wc_XChaCha20Poly1305_crypt_oneshot( if ((ret = wc_Poly1305Final(&aead->poly, outAuthTag)) < 0) goto out; - if (ConstantCompare(outAuthTag, src + dst_len, POLY1305_DIGEST_SIZE) != 0) { + if (ConstantCompare(outAuthTag, src + dst_len, POLY1305_DIGEST_SIZE) + != 0) { + ForceZero(dst, dst_space); ret = MAC_CMP_FAILED_E; goto out; } diff --git a/wolfcrypt/src/cryptocb.c b/wolfcrypt/src/cryptocb.c index c3af7ed608..3218e6efb2 100644 --- a/wolfcrypt/src/cryptocb.c +++ b/wolfcrypt/src/cryptocb.c @@ -50,9 +50,19 @@ Crypto Callback Build Options: * Algorithm-specific callback options: * NO_SHA2_CRYPTO_CB: Disable crypto callbacks for SHA-384 default: off * and SHA-512 operations. + * WOLF_CRYPTO_CB_NO_SHA512_FALLBACK: default: off + * Do not fall back to the generic SHA-512 + * callback for SHA-384, SHA-512/224 and + * SHA-512/256 when no variant-specific + * callback is registered. Required for + * backends whose hash context has no + * digest[] state field or that keep the + * hash state on the device (auto-enabled + * for Renesas FSPSM). * WOLF_CRYPTO_CB_ONLY_ECC: Use only callbacks for ECC default: off * WOLF_CRYPTO_CB_ONLY_RSA: Use only callbacks for RSA default: off * WOLF_CRYPTO_CB_ONLY_SHA256: Use only callbacks for SHA-256 default: off + * WOLF_CRYPTO_CB_ONLY_SHA512: Use only callbacks for SHA-512 default: off * WOLF_CRYPTO_CB_ONLY_AES: Use only callbacks for AES default: off */ @@ -1177,7 +1187,7 @@ int wc_CryptoCb_PqcKemGetDevId(int type, void* key) /* get devId */ if (type == WC_PQC_KEM_TYPE_MLKEM) { - devId = ((KyberKey*) key)->devId; + devId = ((MlKemKey*) key)->devId; } return devId; @@ -2015,16 +2025,52 @@ int wc_CryptoCb_Sha384Hash(wc_Sha384* sha384, const byte* in, } if (dev && dev->cb) { + #if defined(WOLFSSL_SHA512) && !defined(WOLF_CRYPTO_CB_NO_SHA512_FALLBACK) + byte localHash[WC_SHA512_DIGEST_SIZE]; + #endif wc_CryptoInfo cryptoInfo; XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo)); cryptoInfo.algo_type = WC_ALGO_TYPE_HASH; - cryptoInfo.hash.type = WC_HASH_TYPE_SHA384; - cryptoInfo.hash.sha384 = sha384; cryptoInfo.hash.in = in; cryptoInfo.hash.inSz = inSz; - cryptoInfo.hash.digest = digest; + /* try the SHA-384 callback first */ + cryptoInfo.hash.type = WC_HASH_TYPE_SHA384; + cryptoInfo.hash.sha384 = sha384; + cryptoInfo.hash.digest = digest; ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx); + ret = wc_CryptoCb_TranslateErrorCode(ret); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) + return ret; + + #if defined(WOLFSSL_SHA512) && !defined(WOLF_CRYPTO_CB_NO_SHA512_FALLBACK) + /* fall back to the SHA-512 core: SHA-384 is the SHA-512 core with a + * different IV (in the caller-supplied state) and a 48-byte + * truncation done here */ + cryptoInfo.hash.type = WC_HASH_TYPE_SHA512; + cryptoInfo.hash.sha512 = (wc_Sha512*)sha384; + /* use local buffer for the final digest so we can truncate */ + if (digest != NULL) + cryptoInfo.hash.digest = localHash; + ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx); + ret = wc_CryptoCb_TranslateErrorCode(ret); + if (ret == 0 && digest != NULL) { + XMEMCPY(digest, localHash, WC_SHA384_DIGEST_SIZE); + /* the SHA-512 callback left the SHA-512 IV in the state; write + * the SHA-384 IV back so the struct is ready for reuse */ + if (sha384 != NULL) { + sha384->digest[0] = W64LIT(0xcbbb9d5dc1059ed8); + sha384->digest[1] = W64LIT(0x629a292a367cd507); + sha384->digest[2] = W64LIT(0x9159015a3070dd17); + sha384->digest[3] = W64LIT(0x152fecd8f70e5939); + sha384->digest[4] = W64LIT(0x67332667ffc00b31); + sha384->digest[5] = W64LIT(0x8eb44a8768581511); + sha384->digest[6] = W64LIT(0xdb0c2e0d64f98fa7); + sha384->digest[7] = W64LIT(0x47b5481dbefa4fa4); + } + } + return ret; + #endif /* WOLFSSL_SHA512 && !WOLF_CRYPTO_CB_NO_SHA512_FALLBACK */ } return wc_CryptoCb_TranslateErrorCode(ret); @@ -2061,7 +2107,9 @@ int wc_CryptoCb_Sha512Hash(wc_Sha512* sha512, const byte* in, } if (dev && dev->cb) { + #ifndef WOLF_CRYPTO_CB_NO_SHA512_FALLBACK byte localHash[WC_SHA512_DIGEST_SIZE]; + #endif wc_CryptoInfo cryptoInfo; XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo)); cryptoInfo.algo_type = WC_ALGO_TYPE_HASH; @@ -2078,6 +2126,9 @@ int wc_CryptoCb_Sha512Hash(wc_Sha512* sha512, const byte* in, ret = wc_CryptoCb_TranslateErrorCode(ret); if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) return ret; + #ifdef WOLF_CRYPTO_CB_NO_SHA512_FALLBACK + return ret; + #endif } #endif #if !defined(WOLFSSL_NOSHA512_256) @@ -2087,16 +2138,48 @@ int wc_CryptoCb_Sha512Hash(wc_Sha512* sha512, const byte* in, ret = wc_CryptoCb_TranslateErrorCode(ret); if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) return ret; + #ifdef WOLF_CRYPTO_CB_NO_SHA512_FALLBACK + return ret; + #endif } #endif cryptoInfo.hash.type = WC_HASH_TYPE_SHA512; + #ifndef WOLF_CRYPTO_CB_NO_SHA512_FALLBACK /* use local buffer if not full size */ if (digest != NULL && digestSz != WC_SHA512_DIGEST_SIZE) cryptoInfo.hash.digest = localHash; + #endif ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx); ret = wc_CryptoCb_TranslateErrorCode(ret); - if (ret == 0 && digest != NULL && digestSz != WC_SHA512_DIGEST_SIZE) + #ifndef WOLF_CRYPTO_CB_NO_SHA512_FALLBACK + if (ret == 0 && digest != NULL && digestSz != WC_SHA512_DIGEST_SIZE) { XMEMCPY(digest, localHash, digestSz); +#if !defined(WOLFSSL_NOSHA512_224) + if (sha512 != NULL && digestSz == WC_SHA512_224_DIGEST_SIZE) { + sha512->digest[0] = W64LIT(0x8c3d37c819544da2); + sha512->digest[1] = W64LIT(0x73e1996689dcd4d6); + sha512->digest[2] = W64LIT(0x1dfab7ae32ff9c82); + sha512->digest[3] = W64LIT(0x679dd514582f9fcf); + sha512->digest[4] = W64LIT(0x0f6d2b697bd44da8); + sha512->digest[5] = W64LIT(0x77e36f7304c48942); + sha512->digest[6] = W64LIT(0x3f9d85a86a1d36c8); + sha512->digest[7] = W64LIT(0x1112e6ad91d692a1); + } +#endif +#if !defined(WOLFSSL_NOSHA512_256) + if (sha512 != NULL && digestSz == WC_SHA512_256_DIGEST_SIZE) { + sha512->digest[0] = W64LIT(0x22312194fc2bf72c); + sha512->digest[1] = W64LIT(0x9f555fa3c84c64c2); + sha512->digest[2] = W64LIT(0x2393b86b6f53b151); + sha512->digest[3] = W64LIT(0x963877195940eabd); + sha512->digest[4] = W64LIT(0x96283ee2a88effe3); + sha512->digest[5] = W64LIT(0xbe5e1e2553863992); + sha512->digest[6] = W64LIT(0x2b0199fc2c85b8aa); + sha512->digest[7] = W64LIT(0x0eb72ddc81c52ca2); + } +#endif + } + #endif /* !WOLF_CRYPTO_CB_NO_SHA512_FALLBACK */ return ret; } diff --git a/wolfcrypt/src/des3.c b/wolfcrypt/src/des3.c index 12f884e0a5..f1beae1b60 100644 --- a/wolfcrypt/src/des3.c +++ b/wolfcrypt/src/des3.c @@ -1649,6 +1649,8 @@ if (ret != 0) return ret; + des->keySet = 1; + return wc_Des3_SetIV(des, iv); } @@ -1793,6 +1795,10 @@ return BAD_LENGTH_E; } + if (!des->keySet) { + return MISSING_KEY; + } + #ifdef WOLF_CRYPTO_CB if (des->devId != INVALID_DEVID) { int ret = wc_CryptoCb_Des3Encrypt(des, out, in, sz); @@ -1848,6 +1854,10 @@ return BAD_LENGTH_E; } + if (!des->keySet) { + return MISSING_KEY; + } + #ifdef WOLF_CRYPTO_CB if (des->devId != INVALID_DEVID) { int ret = wc_CryptoCb_Des3Decrypt(des, out, in, sz); @@ -1969,6 +1979,7 @@ int wc_Des3Init(Des3* des3, void* heap, int devId) return BAD_FUNC_ARG; des3->heap = heap; + des3->keySet = 0; #ifdef WOLF_CRYPTO_CB des3->devId = devId; diff --git a/wolfcrypt/src/dh.c b/wolfcrypt/src/dh.c index c7560d185c..3e9abe3d86 100644 --- a/wolfcrypt/src/dh.c +++ b/wolfcrypt/src/dh.c @@ -1612,7 +1612,7 @@ static int _ffc_validate_public_key(DhKey* key, const byte* pub, word32 pubSz, } /* SP 800-56Ar3, section 5.6.2.3.1, process step 2 */ - if (ret == 0 && prime != NULL) { + if (ret == 0 && mp_iszero(q) == MP_NO) { #ifdef WOLFSSL_HAVE_SP_DH #ifndef WOLFSSL_SP_NO_2048 if (mp_count_bits(&key->p) == 2048) { @@ -2053,7 +2053,7 @@ static int wc_DhAgree_Sync(DhKey* key, byte* agree, word32* agreeSz, } #endif /* Always validate peer public key (2 <= y <= p-2) per SP 800-56A */ - if (wc_DhCheckPubKey(key, otherPub, pubSz) != 0) { + if (wc_DhCheckPubKey_ex(key, otherPub, pubSz, NULL, 0) != 0) { WOLFSSL_MSG("wc_DhAgree wc_DhCheckPubKey failed"); return DH_CHECK_PUB_E; } diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 11276ce6e9..a3476d4e14 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -2004,6 +2004,10 @@ static int _ecc_projective_add_point(ecc_point* P, ecc_point* Q, ecc_point* R, mp_int *x, *y, *z; int err; + if (MP_BITS_OVER_MAX(mp_bitsused(modulus), MAX_ECC_BITS_USE)) { + return WC_KEY_SIZE_E; + } + /* if Q == R then swap P and Q, so we don't require a local x,y,z */ if (Q == R) { ecc_point* tPt = P; @@ -2404,6 +2408,10 @@ static int _ecc_projective_dbl_point(ecc_point *P, ecc_point *R, mp_int* a, mp_int *x, *y, *z; int err; + if (MP_BITS_OVER_MAX(mp_bitsused(modulus), MAX_ECC_BITS_USE)) { + return WC_KEY_SIZE_E; + } + #ifdef WOLFSSL_SMALL_STACK #ifdef WOLFSSL_SMALL_STACK_CACHE if (R->key != NULL) { @@ -2754,6 +2762,10 @@ int ecc_map_ex(ecc_point* P, mp_int* modulus, mp_digit mp, int ct) #endif mp_int *x, *y, *z; + if (MP_BITS_OVER_MAX(mp_bitsused(modulus), MAX_ECC_BITS_USE)) { + return WC_KEY_SIZE_E; + } + /* special case for point at infinity */ if (mp_cmp_d(P->z, 0) == MP_EQ) { err = mp_set(P->x, 0); @@ -3572,8 +3584,13 @@ static int ecc_point_to_mont(ecc_point* p, ecc_point* r, mp_int* modulus, void* heap) { int err = MP_OKAY; + DECL_MP_INT_SIZE_DYN(mu, mp_bitsused(modulus), MAX_ECC_BITS_USE); + if (MP_BITS_OVER_MAX(mp_bitsused(modulus), MAX_ECC_BITS_USE)) { + return WC_KEY_SIZE_E; + } + (void)heap; NEW_MP_INT_SIZE(mu, mp_bitsused(modulus), heap, DYNAMIC_TYPE_ECC); @@ -3878,6 +3895,11 @@ static int ecc_check_order_minus_1(const mp_int* k, ecc_point* tG, ecc_point* R, int err; DECL_MP_INT_SIZE_DYN(t, mp_bitsused(order), MAX_ECC_BITS_USE); + if (MP_BITS_OVER_MAX(mp_bitsused(order), MAX_ECC_BITS_USE) || + MP_BITS_OVER_MAX(mp_bitsused(modulus), MAX_ECC_BITS_USE)) { + return WC_KEY_SIZE_E; + } + NEW_MP_INT_SIZE(t, mp_bitsused(modulus), NULL, DYNAMIC_TYPE_ECC); #ifdef MP_INT_SIZE_CHECK_NULL if (t == NULL) { @@ -6812,6 +6834,10 @@ int wc_ecc_sign_hash(const byte* in, word32 inlen, byte* out, word32 *outlen, word32 keySz; #endif + if (MP_BITS_OVER_MAX(ECC_KEY_MAX_BITS(key), MAX_ECC_BITS_USE)) { + return WC_KEY_SIZE_E; + } + if (in == NULL || out == NULL || outlen == NULL || key == NULL) { return ECC_BAD_ARG_E; } @@ -7010,8 +7036,13 @@ static int ecc_sign_hash_sw(ecc_key* key, ecc_key* pubkey, WC_RNG* rng, { int err = MP_OKAY; int loop_check = 0; + DECL_MP_INT_SIZE_DYN(b, ECC_KEY_MAX_BITS_NONULLCHECK(key), MAX_ECC_BITS_USE); + if (MP_BITS_OVER_MAX(ECC_KEY_MAX_BITS_NONULLCHECK(key), MAX_ECC_BITS_USE)) { + return WC_KEY_SIZE_E; + } + NEW_MP_INT_SIZE(b, ECC_KEY_MAX_BITS_NONULLCHECK(key), key->heap, DYNAMIC_TYPE_ECC); #ifdef MP_INT_SIZE_CHECK_NULL if (b == NULL) @@ -7336,6 +7367,9 @@ int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng, #else DECLARE_CURVE_SPECS(1); #endif + if (MP_BITS_OVER_MAX(ECC_KEY_MAX_BITS(key), MAX_ECC_BITS_USE)) { + return WC_KEY_SIZE_E; + } #endif /* !WOLFSSL_SP_MATH */ if (in == NULL || r == NULL || s == NULL || key == NULL || rng == NULL) { @@ -8253,8 +8287,13 @@ static int ecc_mont_norm_points(ecc_point* A, ecc_point* Am, ecc_point* B, ecc_point* Bm, mp_int* modulus, void* heap) { int err = MP_OKAY; + DECL_MP_INT_SIZE_DYN(mu, mp_bitsused(modulus), MAX_ECC_BITS_USE); + if (MP_BITS_OVER_MAX(mp_bitsused(modulus), MAX_ECC_BITS_USE)) { + return WC_KEY_SIZE_E; + } + (void)heap; NEW_MP_INT_SIZE(mu, mp_bitsused(modulus), heap, DYNAMIC_TYPE_ECC); @@ -8641,6 +8680,10 @@ int wc_ecc_verify_hash(const byte* sig, word32 siglen, const byte* hash, word32 keySz; #endif + if (MP_BITS_OVER_MAX(ECC_KEY_MAX_BITS(key), MAX_ECC_BITS_USE)) { + return WC_KEY_SIZE_E; + } + if (sig == NULL || hash == NULL || res == NULL || key == NULL) { return ECC_BAD_ARG_E; } @@ -9005,6 +9048,7 @@ static int ecc_verify_hash(mp_int *r, mp_int *s, const byte* hash, ecc_point lcl_mG; ecc_point lcl_mQ; #endif + DECL_MP_INT_SIZE_DYN(w, ECC_KEY_MAX_BITS_NONULLCHECK(key), MAX_ECC_BITS_USE); #if !defined(WOLFSSL_ASYNC_CRYPT) || !defined(HAVE_CAVIUM_V) DECL_MP_INT_SIZE_DYN(e_lcl, ECC_KEY_MAX_BITS_NONULLCHECK(key), MAX_ECC_BITS_USE); @@ -9017,6 +9061,11 @@ static int ecc_verify_hash(mp_int *r, mp_int *s, const byte* hash, #endif mp_int* u1 = NULL; /* Will be e. */ mp_int* u2 = NULL; /* Will be w. */ + + if (MP_BITS_OVER_MAX(ECC_KEY_MAX_BITS_NONULLCHECK(key), MAX_ECC_BITS_USE)) { + return WC_KEY_SIZE_E; + } + #if defined(WOLFSSL_ASYNC_CRYPT) && defined(HAVE_CAVIUM_V) err = wc_ecc_alloc_mpint(key, &key->e); if (err != 0) { diff --git a/wolfcrypt/src/ed25519.c b/wolfcrypt/src/ed25519.c index b84d7e9b15..0b51638df5 100644 --- a/wolfcrypt/src/ed25519.c +++ b/wolfcrypt/src/ed25519.c @@ -1588,7 +1588,7 @@ int wc_ed25519_check_key(ed25519_key* key) #endif /* HAVE_ED25519_MAKE_KEY */ /* No private key (or ability to make a public key), check Y is valid. */ - if ((ret == 0) + if (ret == 0 #ifdef HAVE_ED25519_MAKE_KEY && (!key->privKeySet) #endif diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index c7e1e4c885..7dfa159227 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -4188,24 +4188,65 @@ int wolfSSL_EVP_PKEY_cmp(const WOLFSSL_EVP_PKEY *a, const WOLFSSL_EVP_PKEY *b) #endif /* !NO_RSA */ #ifdef HAVE_ECC case WC_EVP_PKEY_EC: - if (a->ecc == NULL || a->ecc->internal == NULL || - b->ecc == NULL || b->ecc->internal == NULL || - wc_ecc_size((ecc_key*)a->ecc->internal) <= 0 || - wc_ecc_size((ecc_key*)b->ecc->internal) <= 0 || + { + ecc_key* ecc_key_a; + ecc_key* ecc_key_b; + + if (a->ecc == NULL || b->ecc == NULL || a->ecc->group == NULL || b->ecc->group == NULL) { return ret; } + /* Ensure internal ecc_key is synced from external representation. + * After d2i_PrivateKey, the external BIGNUMs may be set but the + * internal ecc_key.pubkey may not be populated. */ + if (a->ecc->inSet == 0) { + if (SetECKeyInternal((WOLFSSL_EC_KEY*)a->ecc) != 1) { + return ret; + } + } + if (b->ecc->inSet == 0) { + if (SetECKeyInternal((WOLFSSL_EC_KEY*)b->ecc) != 1) { + return ret; + } + } + + if (a->ecc->internal == NULL || b->ecc->internal == NULL || + wc_ecc_size((ecc_key*)a->ecc->internal) <= 0 || + wc_ecc_size((ecc_key*)b->ecc->internal) <= 0) { + return ret; + } + + ecc_key_a = (ecc_key*)a->ecc->internal; + ecc_key_b = (ecc_key*)b->ecc->internal; + + /* If a key was imported as private-only (e.g. RFC 5915 without the + * optional public key), the pubkey point will not be populated. + * Derive it from the private key so the comparison can succeed. */ + if (ecc_key_a->type == ECC_PRIVATEKEY_ONLY) { + if (wc_ecc_make_pub(ecc_key_a, NULL) != MP_OKAY) { + return ret; + } + ecc_key_a->type = ECC_PRIVATEKEY; + } + if (ecc_key_b->type == ECC_PRIVATEKEY_ONLY) { + if (wc_ecc_make_pub(ecc_key_b, NULL) != MP_OKAY) { + return ret; + } + ecc_key_b->type = ECC_PRIVATEKEY; + } + /* check curve */ if (a->ecc->group->curve_idx != b->ecc->group->curve_idx) { return WS_RETURN_CODE(ret, WOLFSSL_FAILURE); } - if (wc_ecc_cmp_point(&((ecc_key*)a->ecc->internal)->pubkey, - &((ecc_key*)b->ecc->internal)->pubkey) != 0) { + if (wc_ecc_cmp_point(&ecc_key_a->pubkey, + &ecc_key_b->pubkey) != 0) { return WS_RETURN_CODE(ret, WOLFSSL_FAILURE); } break; + } #endif /* HAVE_ECC */ default: return WS_RETURN_CODE(ret, -2); @@ -5838,6 +5879,34 @@ const WOLFSSL_EVP_CIPHER *wolfSSL_EVP_get_cipherbynid(int id) return wolfSSL_EVP_aes_256_ccm(); #endif #endif + #ifdef WOLFSSL_AES_OFB + #ifdef WOLFSSL_AES_128 + case WC_NID_aes_128_ofb: + return wolfSSL_EVP_aes_128_ofb(); + #endif + #ifdef WOLFSSL_AES_192 + case WC_NID_aes_192_ofb: + return wolfSSL_EVP_aes_192_ofb(); + #endif + #ifdef WOLFSSL_AES_256 + case WC_NID_aes_256_ofb: + return wolfSSL_EVP_aes_256_ofb(); + #endif + #endif /* WOLFSSL_AES_OFB */ + #ifdef WOLFSSL_AES_CFB + #ifdef WOLFSSL_AES_128 + case WC_NID_aes_128_cfb128: + return wolfSSL_EVP_aes_128_cfb128(); + #endif + #ifdef WOLFSSL_AES_192 + case WC_NID_aes_192_cfb128: + return wolfSSL_EVP_aes_192_cfb128(); + #endif + #ifdef WOLFSSL_AES_256 + case WC_NID_aes_256_cfb128: + return wolfSSL_EVP_aes_256_cfb128(); + #endif + #endif /* WOLFSSL_AES_CFB */ #endif #ifdef HAVE_ARIA @@ -10130,6 +10199,61 @@ int wolfSSL_EVP_CIPHER_iv_length(const WOLFSSL_EVP_CIPHER* cipher) #endif /* WOLFSSL_AES_256 */ #endif /* WOLFSSL_AES_XTS && (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5,3)) */ +#ifdef WOLFSSL_AES_OFB + #ifdef WOLFSSL_AES_128 + if (XSTRCMP(name, EVP_AES_128_OFB) == 0) + return WC_AES_BLOCK_SIZE; + #endif + #ifdef WOLFSSL_AES_192 + if (XSTRCMP(name, EVP_AES_192_OFB) == 0) + return WC_AES_BLOCK_SIZE; + #endif + #ifdef WOLFSSL_AES_256 + if (XSTRCMP(name, EVP_AES_256_OFB) == 0) + return WC_AES_BLOCK_SIZE; + #endif +#endif /* WOLFSSL_AES_OFB */ +#ifdef WOLFSSL_AES_CFB +#ifndef WOLFSSL_NO_AES_CFB_1_8 + #ifdef WOLFSSL_AES_128 + if (XSTRCMP(name, EVP_AES_128_CFB1) == 0) + return WC_AES_BLOCK_SIZE; + #endif + #ifdef WOLFSSL_AES_192 + if (XSTRCMP(name, EVP_AES_192_CFB1) == 0) + return WC_AES_BLOCK_SIZE; + #endif + #ifdef WOLFSSL_AES_256 + if (XSTRCMP(name, EVP_AES_256_CFB1) == 0) + return WC_AES_BLOCK_SIZE; + #endif + #ifdef WOLFSSL_AES_128 + if (XSTRCMP(name, EVP_AES_128_CFB8) == 0) + return WC_AES_BLOCK_SIZE; + #endif + #ifdef WOLFSSL_AES_192 + if (XSTRCMP(name, EVP_AES_192_CFB8) == 0) + return WC_AES_BLOCK_SIZE; + #endif + #ifdef WOLFSSL_AES_256 + if (XSTRCMP(name, EVP_AES_256_CFB8) == 0) + return WC_AES_BLOCK_SIZE; + #endif +#endif /* !WOLFSSL_NO_AES_CFB_1_8 */ + #ifdef WOLFSSL_AES_128 + if (XSTRCMP(name, EVP_AES_128_CFB128) == 0) + return WC_AES_BLOCK_SIZE; + #endif + #ifdef WOLFSSL_AES_192 + if (XSTRCMP(name, EVP_AES_192_CFB128) == 0) + return WC_AES_BLOCK_SIZE; + #endif + #ifdef WOLFSSL_AES_256 + if (XSTRCMP(name, EVP_AES_256_CFB128) == 0) + return WC_AES_BLOCK_SIZE; + #endif +#endif /* WOLFSSL_AES_CFB */ + #endif #ifdef HAVE_ARIA if (XSTRCMP(name, EVP_ARIA_128_GCM) == 0) diff --git a/wolfcrypt/src/evp_pk.c b/wolfcrypt/src/evp_pk.c index 9ef4d459bd..f719bb5264 100644 --- a/wolfcrypt/src/evp_pk.c +++ b/wolfcrypt/src/evp_pk.c @@ -235,7 +235,7 @@ static int d2iTryEccKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, } #endif /* HAVE_ECC && OPENSSL_EXTRA */ -#ifdef HAVE_ED25519 +#if defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_IMPORT) /** * Try to make an Ed25519 EVP PKEY from data. * @@ -299,9 +299,9 @@ static int d2iTryEd25519Key(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, return ret; } -#endif /* HAVE_ED25519 */ +#endif /* HAVE_ED25519i && HAVE_ED25519_KEY_IMPORT */ -#ifdef HAVE_ED448 +#if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_IMPORT) /** * Try to make an Ed448 EVP PKEY from data. * @@ -398,7 +398,7 @@ WOLFSSL_EVP_PKEY* wolfSSL_EVP_PKEY_new_raw_public_key(int type, } switch (type) { - #ifdef HAVE_ED25519 + #if defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_IMPORT) case WC_EVP_PKEY_ED25519: { ed25519_key* edKey; if (len != ED25519_PUB_KEY_SIZE) { @@ -419,7 +419,7 @@ WOLFSSL_EVP_PKEY* wolfSSL_EVP_PKEY_new_raw_public_key(int type, break; } #endif - #ifdef HAVE_ED448 + #if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_IMPORT) case WC_EVP_PKEY_ED448: { ed448_key* edKey; if (len != ED448_PUB_KEY_SIZE) { @@ -542,7 +542,7 @@ WOLFSSL_EVP_PKEY* wolfSSL_EVP_PKEY_new_raw_private_key(int type, } switch (type) { - #ifdef HAVE_ED25519 + #if defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_IMPORT) case WC_EVP_PKEY_ED25519: { ed25519_key* edKey; if (len != ED25519_KEY_SIZE) { @@ -564,7 +564,7 @@ WOLFSSL_EVP_PKEY* wolfSSL_EVP_PKEY_new_raw_private_key(int type, break; } #endif - #ifdef HAVE_ED448 + #if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_IMPORT) case WC_EVP_PKEY_ED448: { ed448_key* edKey; if (len != ED448_KEY_SIZE) { @@ -1133,18 +1133,18 @@ static WOLFSSL_EVP_PKEY* d2i_evp_pkey_try(WOLFSSL_EVP_PKEY** out, #endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */ #endif /* !NO_DH && OPENSSL_EXTRA && WOLFSSL_DH_EXTRA */ -#ifdef HAVE_ED25519 +#if defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_IMPORT) if (d2iTryEd25519Key(&pkey, *in, inSz, priv) >= 0) { found = 1; } else -#endif /* HAVE_ED25519 */ -#ifdef HAVE_ED448 +#endif /* HAVE_ED25519 && HAVE_ED25519_KEY_IMPORT */ +#if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_IMPORT) if (d2iTryEd448Key(&pkey, *in, inSz, priv) >= 0) { found = 1; } else -#endif /* HAVE_ED448 */ +#endif /* HAVE_ED448 && HAVE_ED448_KEY_IMPORT */ #ifdef HAVE_FALCON if (d2iTryFalconKey(&pkey, *in, inSz, priv) >= 0) { found = 1; @@ -1361,7 +1361,7 @@ static WOLFSSL_EVP_PKEY* d2i_evp_pkey(int type, WOLFSSL_EVP_PKEY** out, (void)opt; /* Validate parameters. */ - if (in == NULL || inSz < 0) { + if (in == NULL || *in == NULL || inSz <= 0) { WOLFSSL_MSG("Bad argument"); return NULL; } @@ -1494,7 +1494,7 @@ static WOLFSSL_EVP_PKEY* d2i_evp_pkey(int type, WOLFSSL_EVP_PKEY** out, #endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */ #endif /* HAVE_DH */ #endif /* WOLFSSL_QT || OPENSSL_ALL || WOLFSSL_OPENSSH */ -#ifdef HAVE_ED25519 +#if defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_IMPORT) case WC_EVP_PKEY_ED25519: /* local->pkey.ptr already holds the input bytes, so * d2iTryEd25519Key will skip the d2i_make_pkey allocate/copy @@ -1505,7 +1505,7 @@ static WOLFSSL_EVP_PKEY* d2i_evp_pkey(int type, WOLFSSL_EVP_PKEY** out, } break; #endif /* HAVE_ED25519 */ -#ifdef HAVE_ED448 +#if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_IMPORT) case WC_EVP_PKEY_ED448: /* See WC_EVP_PKEY_ED25519 case above. */ if (d2iTryEd448Key(&local, p, local->pkey_sz, priv) != 1) { @@ -1585,12 +1585,18 @@ WOLFSSL_EVP_PKEY* wolfSSL_d2i_AutoPrivateKey(WOLFSSL_EVP_PKEY** pkey, { int ret; WOLFSSL_EVP_PKEY* key = NULL; - const byte* der = *pp; + const byte* der; word32 idx = 0; int len = 0; int cnt = 0; word32 algId; - word32 keyLen = (word32)length; + word32 keyLen; + + if (pp == NULL || *pp == NULL || length <= 0) + return NULL; + + der = *pp; + keyLen = (word32)length; /* Take off PKCS#8 wrapper if found. */ if ((len = ToTraditionalInline_ex(der, &idx, keyLen, &algId)) >= 0) { diff --git a/wolfcrypt/src/ge_operations.c b/wolfcrypt/src/ge_operations.c index 7556594f4b..5d3157628d 100644 --- a/wolfcrypt/src/ge_operations.c +++ b/wolfcrypt/src/ge_operations.c @@ -960,6 +960,8 @@ static WC_INLINE void ge_add(ge_p1p1 *r,const ge_p3 *p,const ge_cached *q) #ifndef CURVED25519_ASM +#if defined(HAVE_ED25519_SIGN) || defined(HAVE_ED25519_MAKE_KEY) || \ + defined(WOLFSSL_CURVE25519_USE_ED25519) /* ge_scalar mult base */ static unsigned char equal(unsigned char b,unsigned char c) { @@ -970,14 +972,10 @@ static unsigned char equal(unsigned char b,unsigned char c) return (unsigned char)y; } -#if defined(HAVE_ED25519_SIGN) || defined(HAVE_ED25519_MAKE_KEY) || \ - defined(WOLFSSL_CURVE25519_USE_ED25519) static unsigned char negative(signed char b) { return ((unsigned char)b) >> 7; } -#endif - static WC_INLINE void cmov(ge_precomp *t,const ge_precomp *u,unsigned char b, unsigned char n) @@ -988,6 +986,7 @@ static WC_INLINE void cmov(ge_precomp *t,const ge_precomp *u,unsigned char b, fe_cmov(t->xy2d,u->xy2d,b); } #endif +#endif #if defined(HAVE_ED25519_SIGN) || defined(HAVE_ED25519_MAKE_KEY) || \ defined(WOLFSSL_CURVE25519_USE_ED25519) diff --git a/wolfcrypt/src/hpke.c b/wolfcrypt/src/hpke.c index b490dea695..e117e9e813 100644 --- a/wolfcrypt/src/hpke.c +++ b/wolfcrypt/src/hpke.c @@ -906,6 +906,11 @@ static int wc_HpkeSetupBaseSender(Hpke* hpke, HpkeBaseContext* context, infoSz); } +#if defined(HAVE_SECRET_CALLBACK) && defined(HAVE_ECH) + if (ret == 0 && hpke->echSecret != NULL) { + XMEMCPY(hpke->echSecret, sharedSecret, hpke->Nsecret); + } +#endif ForceZero(sharedSecret, hpke->Nsecret); WC_FREE_VAR_EX(sharedSecret, hpke->heap, DYNAMIC_TYPE_TMP_BUFFER); @@ -1148,6 +1153,11 @@ static int wc_HpkeSetupBaseReceiver(Hpke* hpke, HpkeBaseContext* context, infoSz); } +#if defined(HAVE_SECRET_CALLBACK) && defined(HAVE_ECH) + if (ret == 0 && hpke->echSecret != NULL) { + XMEMCPY(hpke->echSecret, sharedSecret, hpke->Nsecret); + } +#endif ForceZero(sharedSecret, hpke->Nsecret); WC_FREE_VAR_EX(sharedSecret, hpke->heap, DYNAMIC_TYPE_TMP_BUFFER); @@ -1345,4 +1355,26 @@ WOLFSSL_LOCAL int wc_HpkeAeadIsSupported(word16 aeadId) } } +#if defined(HAVE_SECRET_CALLBACK) && defined(HAVE_ECH) +WOLFSSL_LOCAL int wc_HpkeInitEchSecret(Hpke* hpke) +{ + if (hpke == NULL) + return BAD_FUNC_ARG; + hpke->echSecret = (byte*)XMALLOC(hpke->Nsecret, hpke->heap, + DYNAMIC_TYPE_SECRET); + if (hpke->echSecret == NULL) + return MEMORY_E; + return 0; +} + +WOLFSSL_LOCAL void wc_HpkeFreeEchSecret(Hpke* hpke) +{ + if (hpke == NULL || hpke->echSecret == NULL) + return; + ForceZero(hpke->echSecret, hpke->Nsecret); + XFREE(hpke->echSecret, hpke->heap, DYNAMIC_TYPE_SECRET); + hpke->echSecret = NULL; +} +#endif /* HAVE_SECRET_CALLBACK && HAVE_ECH */ + #endif /* HAVE_HPKE && (HAVE_ECC || HAVE_CURVE25519) && HAVE_AESGCM */ diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index df6ede4296..aaafb74259 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -1641,9 +1641,25 @@ static int EncodeAttributes(EncodedAttrib* ea, int eaSz, for (i = 0; i < maxSz; i++) { word32 attribSz = 0; + word32 boundSz = 0; ea[i].value = attribs[i].value; ea[i].valueSz = attribs[i].valueSz; + + /* The valueSz and oidSz fields are application supplied and unbounded. + * Reject any attribute whose encoded size would overflow a word32 + * before performing the size arithmetic below. Otherwise a large + * valueSz wraps the running total, producing an undersized allocation + * and a heap buffer overflow in FlattenEncodedAttribs(). The encoded + * SET and SEQUENCE headers add at most MAX_SET_SZ and MAX_SEQ_SZ bytes, + * so checking against those upper bounds bounds the real total. */ + if (!WC_SAFE_SUM_WORD32(ea[i].valueSz, attribs[i].oidSz, boundSz) || + !WC_SAFE_SUM_WORD32(boundSz, (word32)MAX_SET_SZ, boundSz) || + !WC_SAFE_SUM_WORD32(boundSz, (word32)MAX_SEQ_SZ, boundSz)) { + WOLFSSL_MSG("PKCS7 attribute size overflow"); + return BUFFER_E; + } + attribSz += ea[i].valueSz; ea[i].valueSetSz = SetSet(attribSz, ea[i].valueSet); attribSz += ea[i].valueSetSz; @@ -1654,6 +1670,15 @@ static int EncodeAttributes(EncodedAttrib* ea, int eaSz, attribSz += ea[i].valueSeqSz; ea[i].totalSz = attribSz; + /* Keep the running total within positive int range so callers can + * distinguish a valid size (>= 0) from a negative error return. Bound + * against the build's actual int maximum rather than assuming 32-bit + * int, so the (int) cast below cannot overflow on narrow-int targets. */ + if (attribSz > (word32)WC_MAX_SINT_OF(int) || + (word32)allAttribsSz > (word32)WC_MAX_SINT_OF(int) - attribSz) { + WOLFSSL_MSG("PKCS7 attributes total size overflow"); + return BUFFER_E; + } allAttribsSz += (int)attribSz; } return allAttribsSz; @@ -1759,7 +1784,16 @@ static int FlattenEncodedAttribs(wc_PKCS7* pkcs7, FlatAttrib** derArr, int rows, } for (i = 0; i < eaSz; i++) { - sz = ea[i].valueSeqSz + ea[i].oidSz + ea[i].valueSetSz + ea[i].valueSz; + /* Defense in depth: guard the size sum against word32 overflow so the + * allocation below can never be smaller than the XMEMCPY lengths. + * EncodeAttributes() rejects oversized attributes up front, but this + * keeps the allocation safe if reached with unchecked input. */ + if (!WC_SAFE_SUM_WORD32(ea[i].valueSeqSz, ea[i].oidSz, sz) || + !WC_SAFE_SUM_WORD32(sz, ea[i].valueSetSz, sz) || + !WC_SAFE_SUM_WORD32(sz, ea[i].valueSz, sz)) { + WOLFSSL_MSG("PKCS7 attribute size overflow"); + return BUFFER_E; + } output = (byte*)XMALLOC(sz, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); if (output == NULL) { @@ -2218,6 +2252,7 @@ static int wc_PKCS7_BuildSignedAttributes(wc_PKCS7* pkcs7, ESD* esd, byte* signingTime, word32 signingTimeSz) { int hashSz; + int encAttribsSz; #ifdef NO_ASN_TIME PKCS7Attrib cannedAttribs[2]; #else @@ -2281,9 +2316,11 @@ static int wc_PKCS7_BuildSignedAttributes(wc_PKCS7* pkcs7, ESD* esd, } esd->signedAttribsCount += idx; - esd->signedAttribsSz += (word32)EncodeAttributes( - &esd->signedAttribs[atrIdx], (int)idx, cannedAttribs, - (int)idx); + encAttribsSz = EncodeAttributes(&esd->signedAttribs[atrIdx], + (int)idx, cannedAttribs, (int)idx); + if (encAttribsSz < 0) + return encAttribsSz; + esd->signedAttribsSz += (word32)encAttribsSz; atrIdx += idx; } else { esd->signedAttribsCount = 0; @@ -2298,9 +2335,12 @@ static int wc_PKCS7_BuildSignedAttributes(wc_PKCS7* pkcs7, ESD* esd, return BUFFER_E; esd->signedAttribsCount += pkcs7->signedAttribsSz; - esd->signedAttribsSz += (word32)EncodeAttributes( - &esd->signedAttribs[atrIdx], (int)esd->signedAttribsCount, - pkcs7->signedAttribs, (int)pkcs7->signedAttribsSz); + encAttribsSz = EncodeAttributes(&esd->signedAttribs[atrIdx], + (int)esd->signedAttribsCount, pkcs7->signedAttribs, + (int)pkcs7->signedAttribsSz); + if (encAttribsSz < 0) + return encAttribsSz; + esd->signedAttribsSz += (word32)encAttribsSz; } #ifdef NO_ASN_TIME @@ -14335,18 +14375,26 @@ int wc_PKCS7_EncodeAuthEnvelopedData(wc_PKCS7* pkcs7, byte* output, contentTypeAttrib.valueSz = pkcs7->contentTypeSz; } - authAttribsSz += (word32)EncodeAttributes(authAttribs, 1, - &contentTypeAttrib, 1); + ret = EncodeAttributes(authAttribs, 1, &contentTypeAttrib, 1); + if (ret < 0) { + wc_PKCS7_FreeEncodedRecipientSet(pkcs7); + return ret; + } + authAttribsSz += (word32)ret; authAttribsCount += 1; } /* authAttribs: add in user authenticated attributes */ if (pkcs7->authAttribs != NULL && pkcs7->authAttribsSz > 0) { - authAttribsSz += (word32)EncodeAttributes( - authAttribs + authAttribsCount, + ret = EncodeAttributes(authAttribs + authAttribsCount, (int)(MAX_AUTH_ATTRIBS_SZ - authAttribsCount), pkcs7->authAttribs, (int)pkcs7->authAttribsSz); + if (ret < 0) { + wc_PKCS7_FreeEncodedRecipientSet(pkcs7); + return ret; + } + authAttribsSz += (word32)ret; authAttribsCount += pkcs7->authAttribsSz; } @@ -14394,11 +14442,17 @@ int wc_PKCS7_EncodeAuthEnvelopedData(wc_PKCS7* pkcs7, byte* output, /* build up unauthenticated attributes (unauthAttrs) */ if (pkcs7->unauthAttribsSz > 0) { - unauthAttribsSz = (word32)EncodeAttributes( - unauthAttribs + unauthAttribsCount, + ret = EncodeAttributes(unauthAttribs + unauthAttribsCount, (int)(MAX_UNAUTH_ATTRIBS_SZ - unauthAttribsCount), pkcs7->unauthAttribs, (int)pkcs7->unauthAttribsSz); + if (ret < 0) { + wc_PKCS7_FreeEncodedRecipientSet(pkcs7); + XFREE(aadBuffer, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(flatAuthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + return ret; + } + unauthAttribsSz = (word32)ret; unauthAttribsCount = pkcs7->unauthAttribsSz; if (unauthAttribsSz > 0) { @@ -15337,8 +15391,12 @@ authenv_atrbend: encryptedContent, encryptedContentSz, encryptedContent, pkcs7->devId, pkcs7->heap); if (ret != 0) { - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ret; + /* Fall through to the shared error handler below, which + * ForceZeros and frees encryptedContent, nulls + * stream->bufferPt/key, and resets the stream. Returning + * here would leave a dangling stream->bufferPt and risk a + * use-after-free / double-free on streaming re-entry. */ + break; } if (encodedAttribs != NULL) { @@ -15595,10 +15653,18 @@ int wc_PKCS7_EncodeEncryptedData(wc_PKCS7* pkcs7, byte* output, word32 outputSz) } attribsCount = pkcs7->unprotectedAttribsSz; - attribsSz = (word32)EncodeAttributes(attribs, + ret = EncodeAttributes(attribs, (int)pkcs7->unprotectedAttribsSz, pkcs7->unprotectedAttribs, (int)pkcs7->unprotectedAttribsSz); + if (ret < 0) { + XFREE(attribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + ForceZero(plain, (word32)encryptedOutSz); + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + return ret; + } + attribsSz = (word32)ret; if (attribsSz > 0) { flatAttribs = (byte*)XMALLOC(attribsSz, pkcs7->heap, diff --git a/wolfcrypt/src/port/Renesas/renesas_tsip_rsa.c b/wolfcrypt/src/port/Renesas/renesas_tsip_rsa.c index 732120be2c..309b375c4c 100644 --- a/wolfcrypt/src/port/Renesas/renesas_tsip_rsa.c +++ b/wolfcrypt/src/port/Renesas/renesas_tsip_rsa.c @@ -55,6 +55,7 @@ This code assumes at least one is enabled int wc_tsip_MakeRsaKey(int size, void* ctx) { e_tsip_err_t ret; + int wcRet = WC_HW_E; TsipUserCtx *info = (TsipUserCtx*)ctx; #if defined(TSIP_RSAES_1024) && TSIP_RSAES_1024 == 1 tsip_rsa1024_key_pair_index_t *tsip_pair1024_key = NULL; @@ -148,6 +149,7 @@ int wc_tsip_MakeRsaKey(int size, void* ctx) info->keyflgs_crypt.bits.rsapri1024_key_set = 1; info->keyflgs_crypt.bits.rsapub1024_key_set = 1; info->wrappedKeyType = TSIP_KEY_TYPE_RSA1024; + wcRet = 0; #endif } else if (size == 2048) { @@ -191,13 +193,31 @@ int wc_tsip_MakeRsaKey(int size, void* ctx) info->keyflgs_crypt.bits.rsapri2048_key_set = 1; info->keyflgs_crypt.bits.rsapub2048_key_set = 1; info->wrappedKeyType = TSIP_KEY_TYPE_RSA2048; + wcRet = 0; #endif } } + else { + /* hardware key generation failed; free the key pair buffer that + * was allocated above so it does not leak, and report the error */ + WOLFSSL_MSG_EX("TSIP RSA key generation failed: %d", ret); +#if defined(TSIP_RSAES_1024) && TSIP_RSAES_1024 == 1 + XFREE(tsip_pair1024_key, NULL, DYNAMIC_TYPE_RSA_BUFFER); +#endif +#if defined(TSIP_RSAES_2048) && TSIP_RSAES_2048 == 1 + XFREE(tsip_pair2048_key, NULL, DYNAMIC_TYPE_RSA_BUFFER); +#endif + wcRet = WC_HW_E; + } tsip_hw_unlock(); } + else { + /* could not obtain the TSIP hardware lock */ + WOLFSSL_MSG_EX("TSIP hardware lock failed: %d", ret); + wcRet = WC_HW_E; + } - return 0; + return wcRet; } /* Generate TSIP key index if needed @@ -260,7 +280,9 @@ int wc_tsip_RsaFunction(wc_CryptoInfo* info, TsipUserCtx* tuc) return BAD_FUNC_ARG; } - if (tsip_RsakeyImport(tuc) == 0) { + ret = tsip_RsakeyImport(tuc); + + if (ret == 0) { type = info->pk.rsa.type; keySize = (int)tuc->wrappedKeyType; @@ -364,7 +386,10 @@ int wc_tsip_RsaVerifyPkcs(wc_CryptoInfo* info, TsipUserCtx* tuc) ret = CRYPTOCB_UNAVAILABLE; } - if (tsip_RsakeyImport(tuc) == 0) { + if (ret == 0) + ret = tsip_RsakeyImport(tuc); + + if (ret == 0) { hashData.pdata = (uint8_t*)info->pk.rsa.out; hashData.data_length = *(info->pk.rsa.outLen); hashData.data_type = diff --git a/wolfcrypt/src/port/arm/armv8-32-curve25519.S b/wolfcrypt/src/port/arm/armv8-32-curve25519.S index e307cb9fb4..7171e8c060 100644 --- a/wolfcrypt/src/port/arm/armv8-32-curve25519.S +++ b/wolfcrypt/src/port/arm/armv8-32-curve25519.S @@ -3677,6 +3677,33 @@ L_curve25519_inv_8: ldr r1, [sp, #160] ldr r0, [sp, #160] bl fe_mul_op + # Ensure result is less than modulus + ldr r0, [sp, #160] + ldm r0, {r4, r5, r6, r7, r8, r9, r10, r11} + adds r2, r4, #19 + adcs r2, r5, #0 + adcs r2, r6, #0 + adcs r2, r7, #0 + adcs r2, r8, #0 + adcs r2, r9, #0 + adcs r2, r10, #0 + adc r2, r11, #0 + asr r2, r2, #31 + and r2, r2, #19 + adds r4, r4, r2 + adcs r5, r5, #0 + adcs r6, r6, #0 + adcs r7, r7, #0 + adcs r8, r8, #0 + adcs r9, r9, #0 + adcs r10, r10, #0 + adc r11, r11, #0 +#if defined(WOLFSSL_ARM_ARCH) && (WOLFSSL_ARM_ARCH < 7) + bic r11, r11, #0x80000000 +#else + bfc r11, #31, #1 +#endif + stm r0, {r4, r5, r6, r7, r8, r9, r10, r11} mov r0, #0 add sp, sp, #0xbc pop {r4, r5, r6, r7, r8, r9, r10, r11, pc} @@ -3959,21 +3986,29 @@ L_curve25519_inv_8: # Ensure result is less than modulus ldr r0, [sp, #176] ldm r0, {r4, r5, r6, r7, r8, r9, r10, r11} - mov r2, #19 - and r2, r2, r11, asr #31 + adds r2, r4, #19 + adcs r2, r5, #0 + adcs r2, r6, #0 + adcs r2, r7, #0 + adcs r2, r8, #0 + adcs r2, r9, #0 + adcs r2, r10, #0 + adc r2, r11, #0 + asr r2, r2, #31 + and r2, r2, #19 adds r4, r4, r2 adcs r5, r5, #0 adcs r6, r6, #0 adcs r7, r7, #0 adcs r8, r8, #0 adcs r9, r9, #0 + adcs r10, r10, #0 + adc r11, r11, #0 #if defined(WOLFSSL_ARM_ARCH) && (WOLFSSL_ARM_ARCH < 7) bic r11, r11, #0x80000000 #else bfc r11, #31, #1 #endif - adcs r10, r10, #0 - adc r11, r11, #0 stm r0, {r4, r5, r6, r7, r8, r9, r10, r11} mov r0, #0 add sp, sp, #0xc0 diff --git a/wolfcrypt/src/port/arm/armv8-32-curve25519_c.c b/wolfcrypt/src/port/arm/armv8-32-curve25519_c.c index c981871e4b..726c02905f 100644 --- a/wolfcrypt/src/port/arm/armv8-32-curve25519_c.c +++ b/wolfcrypt/src/port/arm/armv8-32-curve25519_c.c @@ -4082,6 +4082,33 @@ WC_OMIT_FRAME_POINTER int curve25519(byte* r, const byte* n, const byte* a) "ldr r1, [sp, #160]\n\t" "ldr r0, [sp, #160]\n\t" "bl fe_mul_op\n\t" + /* Ensure result is less than modulus */ + "ldr %[r], [sp, #160]\n\t" + "ldm %[r], {r4, r5, r6, r7, r8, r9, r10, r11}\n\t" + "adds %[a], r4, #19\n\t" + "adcs %[a], r5, #0\n\t" + "adcs %[a], r6, #0\n\t" + "adcs %[a], r7, #0\n\t" + "adcs %[a], r8, #0\n\t" + "adcs %[a], r9, #0\n\t" + "adcs %[a], r10, #0\n\t" + "adc %[a], r11, #0\n\t" + "asr %[a], %[a], #31\n\t" + "and %[a], %[a], #19\n\t" + "adds r4, r4, %[a]\n\t" + "adcs r5, r5, #0\n\t" + "adcs r6, r6, #0\n\t" + "adcs r7, r7, #0\n\t" + "adcs r8, r8, #0\n\t" + "adcs r9, r9, #0\n\t" + "adcs r10, r10, #0\n\t" + "adc r11, r11, #0\n\t" +#if defined(WOLFSSL_ARM_ARCH) && (WOLFSSL_ARM_ARCH < 7) + "bic r11, r11, #0x80000000\n\t" +#else + "bfc r11, #31, #1\n\t" +#endif + "stm %[r], {r4, r5, r6, r7, r8, r9, r10, r11}\n\t" "mov r0, #0\n\t" "add sp, sp, #0xbc\n\t" #ifndef WOLFSSL_NO_VAR_ASSIGN_REG @@ -4392,21 +4419,29 @@ WC_OMIT_FRAME_POINTER int curve25519(byte* r, const byte* n, const byte* a) /* Ensure result is less than modulus */ "ldr %[r], [sp, #176]\n\t" "ldm %[r], {r4, r5, r6, r7, r8, r9, r10, r11}\n\t" - "mov %[a], #19\n\t" - "and %[a], %[a], r11, asr #31\n\t" + "adds %[a], r4, #19\n\t" + "adcs %[a], r5, #0\n\t" + "adcs %[a], r6, #0\n\t" + "adcs %[a], r7, #0\n\t" + "adcs %[a], r8, #0\n\t" + "adcs %[a], r9, #0\n\t" + "adcs %[a], r10, #0\n\t" + "adc %[a], r11, #0\n\t" + "asr %[a], %[a], #31\n\t" + "and %[a], %[a], #19\n\t" "adds r4, r4, %[a]\n\t" "adcs r5, r5, #0\n\t" "adcs r6, r6, #0\n\t" "adcs r7, r7, #0\n\t" "adcs r8, r8, #0\n\t" "adcs r9, r9, #0\n\t" + "adcs r10, r10, #0\n\t" + "adc r11, r11, #0\n\t" #if defined(WOLFSSL_ARM_ARCH) && (WOLFSSL_ARM_ARCH < 7) "bic r11, r11, #0x80000000\n\t" #else "bfc r11, #31, #1\n\t" #endif - "adcs r10, r10, #0\n\t" - "adc r11, r11, #0\n\t" "stm %[r], {r4, r5, r6, r7, r8, r9, r10, r11}\n\t" "mov r0, #0\n\t" "add sp, sp, #0xc0\n\t" diff --git a/wolfcrypt/src/port/cavium/cavium_nitrox.c b/wolfcrypt/src/port/cavium/cavium_nitrox.c index 91defa24b8..c214e87577 100644 --- a/wolfcrypt/src/port/cavium/cavium_nitrox.c +++ b/wolfcrypt/src/port/cavium/cavium_nitrox.c @@ -230,7 +230,7 @@ int NitroxCheckRequests(WC_ASYNC_DEV* dev, word32 buf_size = sizeof(req_stat_buf->req); ret = CspGetAllResults(req_stat_buf->req, buf_size, &res_count, dev->nitrox.devId); - multi_req->count = res_count; + req_stat_buf->count = res_count; #endif return NitroxTranslateResponseCode(ret); @@ -324,6 +324,10 @@ int NitroxRsaPrivateDecrypt(const byte* in, word32 inLen, byte* out, word32* outLen, RsaKey* key) { int ret; + /* The Csp call writes a 16-bit length; use a dedicated Uint16 rather than + * casting the word32* outLen, which would place the bytes in the wrong half + * of the word on a big-endian host before the ntohs() below. */ + Uint16 localOutLen = 0; if (key == NULL || in == NULL || out == NULL || inLen != (word32)key->n.raw.len) { @@ -337,17 +341,17 @@ int NitroxRsaPrivateDecrypt(const byte* in, word32 inLen, byte* out, ret = CspPkcs1v15CrtDec(key->asyncDev.nitrox.devId, CAVIUM_REQ_MODE, CAVIUM_SSL_GRP, CAVIUM_DPORT, BT2, key->n.raw.len, key->q.raw.buf, key->dQ.raw.buf, key->p.raw.buf, key->dP.raw.buf, key->u.raw.buf, - (byte*)in, (Uint16*)outLen, out, &key->asyncDev.nitrox.reqId); + (byte*)in, &localOutLen, out, &key->asyncDev.nitrox.reqId); #else ret = CspPkcs1v15CrtDec(CAVIUM_REQ_MODE, BT2, key->n.raw.len, key->q.raw.buf, key->dQ.raw.buf, key->p.raw.buf, key->dP.raw.buf, - key->u.raw.buf, (byte*)in, &outLen, out, &key->asyncDev.nitrox.reqId, - key->asyncDev.nitrox.devId); + key->u.raw.buf, (byte*)in, &localOutLen, out, + &key->asyncDev.nitrox.reqId, key->asyncDev.nitrox.devId); #endif #ifdef WOLFSSL_NITROX_DEBUG printf("NitroxRsaPrivateDecrypt: ret %x, req %lx in %p (%d), out %p (%d)\n", - ret, key->asyncDev.nitrox.reqId, in, inLen, out, *outLen); + ret, key->asyncDev.nitrox.reqId, in, inLen, out, localOutLen); #endif ret = NitroxTranslateResponseCode(ret); @@ -355,7 +359,7 @@ int NitroxRsaPrivateDecrypt(const byte* in, word32 inLen, byte* out, return ret; } - *outLen = ntohs(*outLen); + *outLen = ntohs(localOutLen); return *outLen; } @@ -404,6 +408,10 @@ int NitroxRsaSSL_Verify(const byte* in, word32 inLen, byte* out, word32* outLen, RsaKey* key) { int ret; + /* The Csp call writes a 16-bit length; use a dedicated Uint16 rather than + * casting the word32* outLen, which would place the bytes in the wrong half + * of the word on a big-endian host before the ntohs() below. */ + Uint16 localOutLen = 0; if (key == NULL || in == NULL || out == NULL || inLen != (word32)key->n.raw.len) { @@ -416,17 +424,17 @@ int NitroxRsaSSL_Verify(const byte* in, word32 inLen, byte* out, #ifdef HAVE_CAVIUM_V ret = CspPkcs1v15Dec(key->asyncDev.nitrox.devId, CAVIUM_REQ_MODE, CAVIUM_SSL_GRP, CAVIUM_DPORT, BT1, key->n.raw.len, key->e.raw.len, - key->n.raw.buf, key->e.raw.buf, (byte*)in, (Uint16*)outLen, out, + key->n.raw.buf, key->e.raw.buf, (byte*)in, &localOutLen, out, &key->asyncDev.nitrox.reqId); #else ret = CspPkcs1v15Dec(CAVIUM_REQ_MODE, BT1, key->n.raw.len, key->e.raw.len, - key->n.raw.buf, key->e.raw.buf, (byte*)in, &outLen, out, + key->n.raw.buf, key->e.raw.buf, (byte*)in, &localOutLen, out, &key->asyncDev.nitrox.reqId, key->asyncDev.nitrox.devId); #endif #ifdef WOLFSSL_NITROX_DEBUG printf("NitroxRsaSSL_Verify: ret %x, req %lx in %p (%d), out %p (%d)\n", - ret, key->asyncDev.nitrox.reqId, in, inLen, out, *outLen); + ret, key->asyncDev.nitrox.reqId, in, inLen, out, localOutLen); #endif ret = NitroxTranslateResponseCode(ret); @@ -434,7 +442,7 @@ int NitroxRsaSSL_Verify(const byte* in, word32 inLen, byte* out, return ret; } - *outLen = ntohs(*outLen); + *outLen = ntohs(localOutLen); return *outLen; } diff --git a/wolfcrypt/src/port/cypress/psoc6_crypto.c b/wolfcrypt/src/port/cypress/psoc6_crypto.c index 325eeb4220..655e4c2be4 100644 --- a/wolfcrypt/src/port/cypress/psoc6_crypto.c +++ b/wolfcrypt/src/port/cypress/psoc6_crypto.c @@ -644,6 +644,9 @@ int wc_Sha512_224Final(wc_Sha512* sha, byte* hash) wolfSSL_CryptHwMutexUnLock(); } + if (ret != 0) + return ret; + /* Reset state */ return wc_InitSha512_224(sha); } diff --git a/wolfcrypt/src/port/liboqs/liboqs.c b/wolfcrypt/src/port/liboqs/liboqs.c index 826d1b3cd9..220f704c9e 100644 --- a/wolfcrypt/src/port/liboqs/liboqs.c +++ b/wolfcrypt/src/port/liboqs/liboqs.c @@ -49,7 +49,14 @@ static void wolfSSL_liboqsGetRandomData(uint8_t* buffer, size_t numOfBytes) while (numOfBytes > 0) { numOfBytes_word32 = (word32)numOfBytes; - numOfBytes -= numOfBytes_word32; + /* On platforms where size_t is wider than word32, the cast above can + * truncate. If numOfBytes does not fit into a word32 (including the + * case where it is an exact multiple of 2^32 and truncates to 0), + * generate the largest chunk that fits to guarantee forward progress + * and avoid an infinite loop. */ + if ((size_t)numOfBytes_word32 != numOfBytes) { + numOfBytes_word32 = 0xFFFFFFFFU; + } ret = wc_RNG_GenerateBlock(liboqsCurrentRNG, buffer, numOfBytes_word32); if (ret != 0) { @@ -62,6 +69,10 @@ static void wolfSSL_liboqsGetRandomData(uint8_t* buffer, size_t numOfBytes) ); abort(); } + /* Advance the buffer so subsequent iterations append rather than + * overwrite the previously generated bytes. */ + buffer += numOfBytes_word32; + numOfBytes -= numOfBytes_word32; } } diff --git a/wolfcrypt/src/port/maxim/README.md b/wolfcrypt/src/port/maxim/README.md index 3919ffd0f9..3970fd896f 100644 --- a/wolfcrypt/src/port/maxim/README.md +++ b/wolfcrypt/src/port/maxim/README.md @@ -84,9 +84,11 @@ hardware. - SHA-384 - SHA-512 -Please note that when using `MAX3266X_SHA` there will be a limitation when -attempting to do a larger sized hash as the SDK for the hardware currently -expects a the whole msg buffer to be given. +By default `MAX3266X_SHA` drives the TPU directly, feeding the message to the +hardware incrementally so hashes of any size are supported. Adding +`#define WOLFSSL_MAX3266X_SHA_ONESHOT` to `user_settings.h` instead buffers +the whole message in memory and hashes it in one shot using the SDK, which +has slightly better performance. `#define MAX3266X_MATH` (Replaces math operation calls for algos like RSA and ECC key generation): diff --git a/wolfcrypt/src/port/maxim/max3266x.c b/wolfcrypt/src/port/maxim/max3266x.c index e326ecadbe..06c6b8c7e9 100644 --- a/wolfcrypt/src/port/maxim/max3266x.c +++ b/wolfcrypt/src/port/maxim/max3266x.c @@ -136,6 +136,8 @@ int wc_MxcAesCryptoCb(wc_CryptoInfo* info) #ifdef MAX3266X_SHA_CB +#ifdef WOLFSSL_MAX3266X_SHA_ONESHOT + /* Shared callback handler: Update grows buffer, Final computes hash. */ static int wc_MxcShaCbDispatch(byte** msg, word32* used, word32* len, void* heap, const byte* in, word32 inSz, @@ -202,9 +204,150 @@ int wc_MxcShaCryptoCb(wc_CryptoInfo* info) return WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); } } + +#else /* WOLFSSL_MAX3266X_SHA_ONESHOT */ + +int wc_MXC_TPU_SHA_Update(unsigned int* digest, unsigned int* buffer, + unsigned int* buffLen, unsigned int* loLen, + unsigned int* hiLen, int stateWords, + unsigned int blockSz, MXC_TPU_HASH_TYPE algo, + const unsigned char* data, unsigned int len); +int wc_MXC_TPU_SHA_Final(unsigned int* digest, unsigned int* buffer, + unsigned int* buffLen, unsigned int loLen, + unsigned int hiLen, int stateWords, + unsigned int digestSz, MXC_TPU_HASH_TYPE algo, + unsigned char* hash); +static int wc_MXC_TPU_SHA_Init(unsigned int* digest, int stateWords, + MXC_TPU_HASH_TYPE algo); + +static int wc_MxcShaCbDispatch( + unsigned int* digest, unsigned int* buffer, + unsigned int* buffLen, unsigned int* loLen, + unsigned int* hiLen, void** devCtx, int stateWords, + unsigned int blockSz, unsigned int digestSz, + MXC_TPU_HASH_TYPE algo, + const unsigned char* in, unsigned int inSz, + unsigned char* outDigest) +{ + if (*devCtx == NULL) { + int initRet = wc_MXC_TPU_SHA_Init(digest, stateWords, algo); + if (initRet != 0) + return initRet; + *devCtx = (void*)1; + } + + if (in != NULL && outDigest == NULL) { + MAX3266X_MSG("Update CB"); + return wc_MXC_TPU_SHA_Update(digest, buffer, buffLen, loLen, hiLen, + stateWords, blockSz, algo, in, inSz); + } + if (in == NULL && outDigest != NULL) { + int ret; + MAX3266X_MSG("Final CB"); + ret = wc_MXC_TPU_SHA_Final(digest, buffer, buffLen, + *loLen, *hiLen, stateWords, + digestSz, algo, outDigest); + /* Reset context state for reuse */ + if (ret == 0) { + *buffLen = 0; + *loLen = 0; + *hiLen = 0; + XMEMSET(buffer, 0, blockSz); + ret = wc_MXC_TPU_SHA_Init(digest, stateWords, algo); + } + return ret; + } + if (inSz == 0) { + return 0; /* Don't need to Update when size is zero */ + } + return BAD_FUNC_ARG; +} + +/* SHA-384/512 callback helper: bridges word64 loLen to unsigned int pair + * and delegates to wc_MxcShaCbDispatch. */ +static int wc_MxcShaCbDispatch512(wc_Sha512* ctx, int stateWords, + unsigned int blockSz, unsigned int digestSz, + MXC_TPU_HASH_TYPE algo, + const unsigned char* in, unsigned int inSz, + unsigned char* digest) +{ + unsigned int loLen = (unsigned int)ctx->loLen; + unsigned int hiLen = (unsigned int)(ctx->loLen >> 32); + int ret; + + ret = wc_MxcShaCbDispatch((unsigned int*)ctx->digest, + (unsigned int*)ctx->buffer, + &ctx->buffLen, &loLen, &hiLen, + &ctx->devCtx, stateWords, blockSz, digestSz, + algo, in, inSz, digest); + + ctx->loLen = (word64)loLen | ((word64)hiLen << 32); + return ret; +} + +int wc_MxcShaCryptoCb(wc_CryptoInfo* info) +{ + switch (info->hash.type) { + #ifndef NO_SHA + case WC_HASH_TYPE_SHA: + return wc_MxcShaCbDispatch( + info->hash.sha1->digest, + info->hash.sha1->buffer, + &info->hash.sha1->buffLen, + &info->hash.sha1->loLen, &info->hash.sha1->hiLen, + &info->hash.sha1->devCtx, + MXC_SHA1_STATE_WORDS, WC_SHA_BLOCK_SIZE, + WC_SHA_DIGEST_SIZE, MXC_TPU_HASH_SHA1, + info->hash.in, info->hash.inSz, info->hash.digest); + #endif + #ifdef WOLFSSL_SHA224 + case WC_HASH_TYPE_SHA224: + return wc_MxcShaCbDispatch( + info->hash.sha224->digest, + info->hash.sha224->buffer, + &info->hash.sha224->buffLen, + &info->hash.sha224->loLen, &info->hash.sha224->hiLen, + &info->hash.sha224->devCtx, + MXC_SHA224_STATE_WORDS, WC_SHA224_BLOCK_SIZE, + WC_SHA224_DIGEST_SIZE, MXC_TPU_HASH_SHA224, + info->hash.in, info->hash.inSz, info->hash.digest); + #endif + #ifndef NO_SHA256 + case WC_HASH_TYPE_SHA256: + return wc_MxcShaCbDispatch( + info->hash.sha256->digest, + info->hash.sha256->buffer, + &info->hash.sha256->buffLen, + &info->hash.sha256->loLen, &info->hash.sha256->hiLen, + &info->hash.sha256->devCtx, + MXC_SHA256_STATE_WORDS, WC_SHA256_BLOCK_SIZE, + WC_SHA256_DIGEST_SIZE, MXC_TPU_HASH_SHA256, + info->hash.in, info->hash.inSz, info->hash.digest); + #endif + #ifdef WOLFSSL_SHA384 + case WC_HASH_TYPE_SHA384: + return wc_MxcShaCbDispatch512(info->hash.sha384, + MXC_SHA384_STATE_WORDS, WC_SHA384_BLOCK_SIZE, + WC_SHA384_DIGEST_SIZE, MXC_TPU_HASH_SHA384, + info->hash.in, info->hash.inSz, info->hash.digest); + #endif + #ifdef WOLFSSL_SHA512 + case WC_HASH_TYPE_SHA512: + return wc_MxcShaCbDispatch512(info->hash.sha512, + MXC_SHA512_STATE_WORDS, WC_SHA512_BLOCK_SIZE, + WC_SHA512_DIGEST_SIZE, MXC_TPU_HASH_SHA512, + info->hash.in, info->hash.inSz, info->hash.digest); + #endif + default: + return WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + } +} + +#endif /* WOLFSSL_MAX3266X_SHA_ONESHOT */ #endif /* MAX3266X_SHA_CB */ #ifdef WOLF_CRYPTO_CB_COPY +#ifdef WOLFSSL_MAX3266X_SHA_ONESHOT static int wc_MxcCopyCb(wc_CryptoInfo* info) { if (info == NULL || info->copy.src == NULL || info->copy.dst == NULL) { @@ -268,6 +411,55 @@ static int wc_MxcCopyCb(wc_CryptoInfo* info) return WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); } } +#else /* WOLFSSL_MAX3266X_SHA_ONESHOT */ +static int wc_MxcCopyCb(wc_CryptoInfo* info) +{ + word32 sz; + + if (info == NULL || info->copy.src == NULL || info->copy.dst == NULL) { + return BAD_FUNC_ARG; + } + + switch (info->copy.type) { +#ifdef MAX3266X_SHA_CB + #ifndef NO_SHA + case WC_HASH_TYPE_SHA: + wc_ShaFree((wc_Sha*)info->copy.dst); + sz = sizeof(wc_Sha); + break; + #endif + #ifdef WOLFSSL_SHA224 + case WC_HASH_TYPE_SHA224: + wc_Sha224Free((wc_Sha224*)info->copy.dst); + sz = sizeof(wc_Sha224); + break; + #endif + #ifndef NO_SHA256 + case WC_HASH_TYPE_SHA256: + wc_Sha256Free((wc_Sha256*)info->copy.dst); + sz = sizeof(wc_Sha256); + break; + #endif + #ifdef WOLFSSL_SHA384 + case WC_HASH_TYPE_SHA384: + wc_Sha384Free((wc_Sha384*)info->copy.dst); + sz = sizeof(wc_Sha384); + break; + #endif + #ifdef WOLFSSL_SHA512 + case WC_HASH_TYPE_SHA512: + wc_Sha512Free((wc_Sha512*)info->copy.dst); + sz = sizeof(wc_Sha512); + break; + #endif +#endif /* MAX3266X_SHA_CB */ + default: + return WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + } + XMEMCPY(info->copy.dst, info->copy.src, sz); + return 0; +} +#endif /* WOLFSSL_MAX3266X_SHA_ONESHOT */ #endif /* WOLF_CRYPTO_CB_COPY */ #ifdef WOLF_CRYPTO_CB_FREE @@ -370,7 +562,7 @@ int wc_MxcCryptoCb(int devIdArg, wc_CryptoInfo* info, void* ctx) break; #endif /* WOLF_CRYPTO_CB_FREE */ default: - MAX3266X_MSG("Callback not support with MXC, using SW"); + MAX3266X_MSG("Callback not supported with MXC, using SW"); /* return this to bypass HW and use SW */ ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); } @@ -691,6 +883,8 @@ int wc_MxcCb_AesCbcDecrypt(Aes* aes, byte* out, const byte* in, word32 sz) #if defined(MAX3266X_SHA) || defined(MAX3266X_SHA_CB) +#ifdef WOLFSSL_MAX3266X_SHA_ONESHOT + /* Check for empty message and provide pre-computed digest if so */ /* Returns 1 if empty (digest filled), 0 if needs hardware processing */ int wc_MXC_TPU_SHA_GetDigest(const unsigned char* msg, unsigned int msgSz, @@ -853,7 +1047,285 @@ int wc_MXC_TPU_SHA_Final(unsigned char** msg, unsigned int* used, return status; } +#else /* WOLFSSL_MAX3266X_SHA_ONESHOT */ + +/* TPU hash helpers (bare-metal SHA accelerator) */ + +/* Reset TPU, select hash function, and restore intermediate state into + * the HASH_DIGEST registers. */ +void wc_MXC_TPU_Hash_Setup(MXC_TPU_HASH_TYPE algo, + const unsigned int* state, int stateWords) +{ + int i; + + /* Init TPU clock */ + MXC_TPU_Init(MXC_SYS_PERIPH_CLOCK_TPU); + + /* Reset TPU */ + MXC_TPU->ctrl = MXC_F_TPU_CTRL_RST; + while (!(MXC_TPU->ctrl & MXC_F_TPU_CTRL_RDY)) {} + MXC_TPU->ctrl |= MXC_F_TPU_CTRL_FLAG_MODE; + + /* Select hash function and INIT to prime the hardware's internal state */ + MXC_TPU->hash_ctrl = ((unsigned int)algo << MXC_F_TPU_HASH_CTRL_HASH_POS) + | MXC_F_TPU_HASH_CTRL_INIT; + while (MXC_TPU->hash_ctrl & MXC_F_TPU_HASH_CTRL_INIT) {} + + /* Overwrite the standard IV with our saved intermediate state */ + for (i = 0; i < stateWords; i++) { + MXC_TPU->hash_digest[i] = state[i]; + } +} + +/* Feed one complete block to the TPU and wait for completion. */ +void wc_MXC_TPU_Hash_Feed_Block(const unsigned char* data, + unsigned int blockSz) +{ + unsigned int word; + + MXC_TPU->ctrl |= MXC_F_TPU_CTRL_DMA_DONE | MXC_F_TPU_CTRL_GLS_DONE | + MXC_F_TPU_CTRL_HSH_DONE | MXC_F_TPU_CTRL_CPH_DONE | + MXC_F_TPU_CTRL_MAA_DONE; + + for (word = 0; word < blockSz; word += 4) { + while (!(MXC_TPU->ctrl & MXC_F_TPU_CTRL_RDY)) {} + MXC_TPU->data_in[0] = (unsigned int)data[word] + | ((unsigned int)data[word + 1] << 8) + | ((unsigned int)data[word + 2] << 16) + | ((unsigned int)data[word + 3] << 24); + } + + while (!(MXC_TPU->ctrl & MXC_F_TPU_CTRL_HSH_DONE)) {} +} + +/* Feed the last (possibly partial) block with LAST flag and msg size. */ +void wc_MXC_TPU_Hash_Feed_Last(const unsigned char* data, + unsigned int dataLen, + unsigned int totalLenLo, + unsigned int totalLenHi) +{ + unsigned int word; + + /* Set total message size for padding calculation */ + MXC_TPU->hash_msg_sz[0] = totalLenLo; + MXC_TPU->hash_msg_sz[1] = totalLenHi; + + /* Signal this is the last block */ + MXC_TPU->hash_ctrl |= MXC_F_TPU_HASH_CTRL_LAST; + + /* Empty message: the hardware needs a dummy write to data_in to + * trigger processing of the padding-only block. */ + if (totalLenLo == 0 && totalLenHi == 0) { + while (!(MXC_TPU->ctrl & MXC_F_TPU_CTRL_RDY)) {} + MXC_TPU->data_in[0] = 0; + } + + for (word = 0; word < dataLen; word += 4) { + while (!(MXC_TPU->ctrl & MXC_F_TPU_CTRL_RDY)) {} + if (dataLen >= (word + 4)) { + MXC_TPU->data_in[0] = (unsigned int)data[word] + | ((unsigned int)data[word + 1] << 8) + | ((unsigned int)data[word + 2] << 16) + | ((unsigned int)data[word + 3] << 24); + } + else if ((dataLen & 3) == 1) { + MXC_TPU->data_in[0] = (unsigned int)data[word]; + } + else if ((dataLen & 3) == 2) { + MXC_TPU->data_in[0] = (unsigned int)data[word] + | ((unsigned int)data[word + 1] << 8); + } + else if ((dataLen & 3) == 3) { + MXC_TPU->data_in[0] = (unsigned int)data[word] + | ((unsigned int)data[word + 1] << 8) + | ((unsigned int)data[word + 2] << 16); + } + } + + while (!(MXC_TPU->ctrl & MXC_F_TPU_CTRL_HSH_DONE)) {} +} + +/* Save intermediate hash state from hardware registers into context. */ +void wc_MXC_TPU_Hash_Save_State(unsigned int* state, int stateWords) +{ + int i; + for (i = 0; i < stateWords; i++) { + state[i] = MXC_TPU->hash_digest[i]; + } +} + +/* Read final digest from hardware registers. */ +void wc_MXC_TPU_Hash_Read_Digest(unsigned char* digest, unsigned int digestSz) +{ + XMEMCPY(digest, (const void*)MXC_TPU->hash_digest, digestSz); +} + +/* Generic Update */ +int wc_MXC_TPU_SHA_Update(unsigned int* digest, unsigned int* buffer, + unsigned int* buffLen, unsigned int* loLen, + unsigned int* hiLen, int stateWords, + unsigned int blockSz, MXC_TPU_HASH_TYPE algo, + const unsigned char* data, unsigned int len) +{ + int status; + unsigned int fill; + + if (len == 0) { + return 0; + } + + /* Update total length */ + { + unsigned int oldLo = *loLen; + *loLen += len; + if (*loLen < oldLo) { + (*hiLen)++; + } + } + + /* If there's existing buffered data, try to complete a block */ + if (*buffLen > 0) { + fill = blockSz - *buffLen; + if (len < fill) { + XMEMCPY((unsigned char*)buffer + *buffLen, data, len); + *buffLen += len; + return 0; + } + XMEMCPY((unsigned char*)buffer + *buffLen, data, fill); + data += fill; + len -= fill; + + /* Only process the completed buffer block if there's more data + * coming. The TPU requires LAST to be set with real data (unless the + * entire message is empty), so we always keep at least one block + * buffered for Final. */ + if (len > 0) { + *buffLen = 0; + status = wolfSSL_HwHashMutexLock(); + if (status != 0) return status; + wc_MXC_TPU_Hash_Setup(algo, digest, stateWords); + wc_MXC_TPU_Hash_Feed_Block((const unsigned char*)buffer, blockSz); + wc_MXC_TPU_Hash_Save_State(digest, stateWords); + MAX3266X_MSG("SHA HW Acceleration Used"); + wolfSSL_HwHashMutexUnLock(); + } + else { + *buffLen = blockSz; + return 0; + } + } + + /* Process full blocks directly from input, always leaving the last + * complete block buffered so Final has data to feed with LAST. */ + if (len > blockSz) { + status = wolfSSL_HwHashMutexLock(); + if (status != 0) return status; + wc_MXC_TPU_Hash_Setup(algo, digest, stateWords); + + while (len > blockSz) { + wc_MXC_TPU_Hash_Feed_Block(data, blockSz); + data += blockSz; + len -= blockSz; + } + + wc_MXC_TPU_Hash_Save_State(digest, stateWords); + MAX3266X_MSG("SHA HW Acceleration Used"); + wolfSSL_HwHashMutexUnLock(); + } + + /* Buffer remaining data (1..blockSz bytes) */ + if (len > 0) { + XMEMCPY((unsigned char*)buffer, data, len); + *buffLen = len; + } + + return 0; +} + +/* Generic Final */ +int wc_MXC_TPU_SHA_Final(unsigned int* digest, unsigned int* buffer, + unsigned int* buffLen, unsigned int loLen, + unsigned int hiLen, int stateWords, + unsigned int digestSz, MXC_TPU_HASH_TYPE algo, + unsigned char* hash) +{ + int status; + + status = wolfSSL_HwHashMutexLock(); + if (status != 0) return status; + + wc_MXC_TPU_Hash_Setup(algo, digest, stateWords); + wc_MXC_TPU_Hash_Feed_Last((const unsigned char*)buffer, *buffLen, + loLen, hiLen); + wc_MXC_TPU_Hash_Read_Digest(hash, digestSz); + MAX3266X_MSG("SHA HW Acceleration Used"); + + wolfSSL_HwHashMutexUnLock(); + return 0; +} + +/* Generic GetHash */ +int wc_MXC_TPU_SHA_GetHash(unsigned int* digest, unsigned int* buffer, + unsigned int buffLen, unsigned int loLen, + unsigned int hiLen, int stateWords, + unsigned int digestSz, MXC_TPU_HASH_TYPE algo, + unsigned char* hash) +{ + int status; + /* Use copies so we don't modify the real context */ + unsigned int tmpDigest[MXC_SHA512_STATE_WORDS]; + unsigned int tmpBuf[128 / sizeof(unsigned int)]; /* max block: 1024 bits */ + + XMEMCPY(tmpDigest, digest, stateWords * sizeof(unsigned int)); + if (buffLen > 0) { + XMEMCPY(tmpBuf, buffer, buffLen); + } + + status = wolfSSL_HwHashMutexLock(); + if (status != 0) return status; + + wc_MXC_TPU_Hash_Setup(algo, tmpDigest, stateWords); + wc_MXC_TPU_Hash_Feed_Last((const unsigned char*)tmpBuf, buffLen, + loLen, hiLen); + wc_MXC_TPU_Hash_Read_Digest(hash, digestSz); + MAX3266X_MSG("SHA HW Acceleration Used"); + + wolfSSL_HwHashMutexUnLock(); + return 0; +} + +/* Init helper: use TPU INIT to get the standard IV for any algorithm */ +static int wc_MXC_TPU_SHA_Init(unsigned int* digest, int stateWords, + MXC_TPU_HASH_TYPE algo) +{ + int status = wolfSSL_HwHashMutexLock(); + if (status != 0) return status; + + MXC_TPU_Init(MXC_SYS_PERIPH_CLOCK_TPU); + MXC_TPU->ctrl = MXC_F_TPU_CTRL_RST; + while (!(MXC_TPU->ctrl & MXC_F_TPU_CTRL_RDY)) {} + MXC_TPU->ctrl |= MXC_F_TPU_CTRL_FLAG_MODE; + + /* Select hash function and trigger INIT to load standard IV */ + MXC_TPU->hash_ctrl = (unsigned int)algo << MXC_F_TPU_HASH_CTRL_HASH_POS; + MXC_TPU->hash_ctrl |= MXC_F_TPU_HASH_CTRL_INIT; + while (MXC_TPU->hash_ctrl & MXC_F_TPU_HASH_CTRL_INIT) {} + + /* Save the standard IV into the context */ + wc_MXC_TPU_Hash_Save_State(digest, stateWords); + + wolfSSL_HwHashMutexUnLock(); + return 0; +} + +#endif /* WOLFSSL_MAX3266X_SHA_ONESHOT */ + +/* Per-algorithm Init / Update / Final / GetHash / Copy / Free */ + #ifndef MAX3266X_SHA_CB + +#ifdef WOLFSSL_MAX3266X_SHA_ONESHOT + #if !defined(NO_SHA) WOLFSSL_API int wc_InitSha_ex(wc_Sha* sha, void* heap, int devId) @@ -1198,7 +1670,428 @@ WOLFSSL_API void wc_Sha512Free(wc_Sha512* sha512) } #endif /* WOLFSSL_SHA512 */ -#endif /* !MAX3266X_SHA_CB*/ + +#else /* WOLFSSL_MAX3266X_SHA_ONESHOT */ +/* Non-callback path: provide the wc_Sha* API functions directly */ + +#if !defined(NO_SHA) + +WOLFSSL_API int wc_InitSha_ex(wc_Sha* sha, void* heap, int devId) +{ + if (sha == NULL) { + return BAD_FUNC_ARG; + } + (void)devId; + XMEMSET(sha, 0, sizeof(*sha)); + sha->heap = heap; + return wc_MXC_TPU_SHA_Init(sha->digest, MXC_SHA1_STATE_WORDS, + MXC_TPU_HASH_SHA1); +} + +WOLFSSL_API int wc_ShaUpdate(wc_Sha* sha, const unsigned char* data, + unsigned int len) +{ + if (sha == NULL || (data == NULL && len > 0)) { + return BAD_FUNC_ARG; + } + return wc_MXC_TPU_SHA_Update(sha->digest, + sha->buffer, &sha->buffLen, &sha->loLen, &sha->hiLen, + MXC_SHA1_STATE_WORDS, WC_SHA_BLOCK_SIZE, + MXC_TPU_HASH_SHA1, data, len); +} + +WOLFSSL_API int wc_ShaFinal(wc_Sha* sha, unsigned char* hash) +{ + int ret; + if (sha == NULL || hash == NULL) { + return BAD_FUNC_ARG; + } + ret = wc_MXC_TPU_SHA_Final(sha->digest, + sha->buffer, &sha->buffLen, sha->loLen, sha->hiLen, + MXC_SHA1_STATE_WORDS, + WC_SHA_DIGEST_SIZE, MXC_TPU_HASH_SHA1, hash); + if (ret == 0) { + return wc_InitSha_ex(sha, sha->heap, INVALID_DEVID); + } + return ret; +} + +WOLFSSL_API int wc_ShaGetHash(wc_Sha* sha, unsigned char* hash) +{ + if (sha == NULL || hash == NULL) { + return BAD_FUNC_ARG; + } + return wc_MXC_TPU_SHA_GetHash(sha->digest, + sha->buffer, sha->buffLen, sha->loLen, sha->hiLen, + MXC_SHA1_STATE_WORDS, + WC_SHA_DIGEST_SIZE, MXC_TPU_HASH_SHA1, hash); +} + +WOLFSSL_API int wc_ShaCopy(wc_Sha* src, wc_Sha* dst) +{ + if (src == NULL || dst == NULL) { + return BAD_FUNC_ARG; + } + XMEMCPY(dst, src, sizeof(wc_Sha)); + return 0; +} + +WOLFSSL_API void wc_ShaFree(wc_Sha* sha) +{ + if (sha == NULL) { + return; + } + ForceZero(sha, sizeof(wc_Sha)); +} + +#endif /* !NO_SHA */ + +#if defined(WOLFSSL_SHA224) + +WOLFSSL_API int wc_InitSha224_ex(wc_Sha224* sha224, void* heap, int devId) +{ + if (sha224 == NULL) { + return BAD_FUNC_ARG; + } + (void)devId; + XMEMSET(sha224, 0, sizeof(*sha224)); + sha224->heap = heap; + return wc_MXC_TPU_SHA_Init(sha224->digest, MXC_SHA224_STATE_WORDS, + MXC_TPU_HASH_SHA224); +} + +WOLFSSL_API int wc_InitSha224(wc_Sha224* sha224) +{ + return wc_InitSha224_ex(sha224, NULL, INVALID_DEVID); +} + +WOLFSSL_API int wc_Sha224Update(wc_Sha224* sha224, const unsigned char* data, + unsigned int len) +{ + if (sha224 == NULL || (data == NULL && len > 0)) { + return BAD_FUNC_ARG; + } + return wc_MXC_TPU_SHA_Update(sha224->digest, + sha224->buffer, &sha224->buffLen, + &sha224->loLen, &sha224->hiLen, + MXC_SHA224_STATE_WORDS, WC_SHA224_BLOCK_SIZE, + MXC_TPU_HASH_SHA224, data, len); +} + +WOLFSSL_API int wc_Sha224Final(wc_Sha224* sha224, unsigned char* hash) +{ + int ret; + if (sha224 == NULL || hash == NULL) { + return BAD_FUNC_ARG; + } + ret = wc_MXC_TPU_SHA_Final(sha224->digest, + sha224->buffer, &sha224->buffLen, + sha224->loLen, sha224->hiLen, + MXC_SHA224_STATE_WORDS, + WC_SHA224_DIGEST_SIZE, MXC_TPU_HASH_SHA224, hash); + if (ret == 0) { + return wc_InitSha224_ex(sha224, sha224->heap, INVALID_DEVID); + } + return ret; +} + +WOLFSSL_API int wc_Sha224GetHash(wc_Sha224* sha224, unsigned char* hash) +{ + if (sha224 == NULL || hash == NULL) { + return BAD_FUNC_ARG; + } + return wc_MXC_TPU_SHA_GetHash(sha224->digest, + sha224->buffer, sha224->buffLen, + sha224->loLen, sha224->hiLen, + MXC_SHA224_STATE_WORDS, + WC_SHA224_DIGEST_SIZE, MXC_TPU_HASH_SHA224, hash); +} + +WOLFSSL_API int wc_Sha224Copy(wc_Sha224* src, wc_Sha224* dst) +{ + if (src == NULL || dst == NULL) { + return BAD_FUNC_ARG; + } + XMEMCPY(dst, src, sizeof(wc_Sha224)); + return 0; +} + +WOLFSSL_API void wc_Sha224Free(wc_Sha224* sha224) +{ + if (sha224 == NULL) { + return; + } + ForceZero(sha224, sizeof(wc_Sha224)); +} + +#endif /* WOLFSSL_SHA224 */ + +#if !defined(NO_SHA256) + +WOLFSSL_API int wc_InitSha256_ex(wc_Sha256* sha256, void* heap, int devId) +{ + if (sha256 == NULL) { + return BAD_FUNC_ARG; + } + (void)devId; + XMEMSET(sha256, 0, sizeof(*sha256)); + sha256->heap = heap; + return wc_MXC_TPU_SHA_Init(sha256->digest, MXC_SHA256_STATE_WORDS, + MXC_TPU_HASH_SHA256); +} + +WOLFSSL_API int wc_InitSha256(wc_Sha256* sha256) +{ + return wc_InitSha256_ex(sha256, NULL, INVALID_DEVID); +} + +WOLFSSL_API int wc_Sha256Update(wc_Sha256* sha256, const unsigned char* data, + unsigned int len) +{ + if (sha256 == NULL || (data == NULL && len > 0)) { + return BAD_FUNC_ARG; + } + return wc_MXC_TPU_SHA_Update(sha256->digest, + sha256->buffer, &sha256->buffLen, + &sha256->loLen, &sha256->hiLen, + MXC_SHA256_STATE_WORDS, WC_SHA256_BLOCK_SIZE, + MXC_TPU_HASH_SHA256, data, len); +} + +WOLFSSL_API int wc_Sha256Final(wc_Sha256* sha256, unsigned char* hash) +{ + int ret; + if (sha256 == NULL || hash == NULL) { + return BAD_FUNC_ARG; + } + ret = wc_MXC_TPU_SHA_Final(sha256->digest, + sha256->buffer, &sha256->buffLen, + sha256->loLen, sha256->hiLen, + MXC_SHA256_STATE_WORDS, + WC_SHA256_DIGEST_SIZE, MXC_TPU_HASH_SHA256, hash); + if (ret == 0) { + return wc_InitSha256_ex(sha256, sha256->heap, INVALID_DEVID); + } + return ret; +} + +WOLFSSL_API int wc_Sha256GetHash(wc_Sha256* sha256, unsigned char* hash) +{ + if (sha256 == NULL || hash == NULL) { + return BAD_FUNC_ARG; + } + return wc_MXC_TPU_SHA_GetHash(sha256->digest, + sha256->buffer, sha256->buffLen, + sha256->loLen, sha256->hiLen, + MXC_SHA256_STATE_WORDS, + WC_SHA256_DIGEST_SIZE, MXC_TPU_HASH_SHA256, hash); +} + +WOLFSSL_API int wc_Sha256Copy(wc_Sha256* src, wc_Sha256* dst) +{ + if (src == NULL || dst == NULL) { + return BAD_FUNC_ARG; + } + XMEMCPY(dst, src, sizeof(wc_Sha256)); + return 0; +} + +WOLFSSL_API void wc_Sha256Free(wc_Sha256* sha256) +{ + if (sha256 == NULL) { + return; + } + ForceZero(sha256, sizeof(wc_Sha256)); +} + +#endif /* !NO_SHA256 */ + +#if defined(WOLFSSL_SHA384) + +WOLFSSL_API int wc_InitSha384_ex(wc_Sha384* sha384, void* heap, int devId) +{ + if (sha384 == NULL) { + return BAD_FUNC_ARG; + } + (void)devId; + XMEMSET(sha384, 0, sizeof(*sha384)); + sha384->heap = heap; + return wc_MXC_TPU_SHA_Init((word32*)sha384->digest, + MXC_SHA384_STATE_WORDS, MXC_TPU_HASH_SHA384); +} + +WOLFSSL_API int wc_InitSha384(wc_Sha384* sha384) +{ + return wc_InitSha384_ex(sha384, NULL, INVALID_DEVID); +} + +WOLFSSL_API int wc_Sha384Update(wc_Sha384* sha384, const unsigned char* data, + unsigned int len) +{ + word32 loLen, hiLen; + int ret; + if (sha384 == NULL || (data == NULL && len > 0)) { + return BAD_FUNC_ARG; + } + + /* SHA-384/512 context uses word64 loLen/hiLen; the generic Update helper + * uses word32. We bridge by converting here. */ + loLen = (word32)sha384->loLen; + hiLen = (word32)(sha384->loLen >> 32); + + ret = wc_MXC_TPU_SHA_Update((word32*)sha384->digest, + (word32*)sha384->buffer, &sha384->buffLen, + &loLen, &hiLen, + MXC_SHA384_STATE_WORDS, WC_SHA384_BLOCK_SIZE, + MXC_TPU_HASH_SHA384, data, len); + + /* Write back the updated length */ + sha384->loLen = (word64)loLen | ((word64)hiLen << 32); + return ret; +} + +WOLFSSL_API int wc_Sha384Final(wc_Sha384* sha384, unsigned char* hash) +{ + int ret; + if (sha384 == NULL || hash == NULL) { + return BAD_FUNC_ARG; + } + ret = wc_MXC_TPU_SHA_Final((word32*)sha384->digest, + (word32*)sha384->buffer, &sha384->buffLen, + (word32)sha384->loLen, (word32)(sha384->loLen >> 32), + MXC_SHA384_STATE_WORDS, + WC_SHA384_DIGEST_SIZE, MXC_TPU_HASH_SHA384, hash); + if (ret == 0) { + return wc_InitSha384_ex(sha384, sha384->heap, INVALID_DEVID); + } + return ret; +} + +WOLFSSL_API int wc_Sha384GetHash(wc_Sha384* sha384, unsigned char* hash) +{ + if (sha384 == NULL || hash == NULL) { + return BAD_FUNC_ARG; + } + return wc_MXC_TPU_SHA_GetHash((word32*)sha384->digest, + (word32*)sha384->buffer, sha384->buffLen, + (word32)sha384->loLen, (word32)(sha384->loLen >> 32), + MXC_SHA384_STATE_WORDS, + WC_SHA384_DIGEST_SIZE, MXC_TPU_HASH_SHA384, hash); +} + +WOLFSSL_API int wc_Sha384Copy(wc_Sha384* src, wc_Sha384* dst) +{ + if (src == NULL || dst == NULL) { + return BAD_FUNC_ARG; + } + XMEMCPY(dst, src, sizeof(wc_Sha384)); + return 0; +} + +WOLFSSL_API void wc_Sha384Free(wc_Sha384* sha384) +{ + if (sha384 == NULL) { + return; + } + ForceZero(sha384, sizeof(wc_Sha384)); +} + +#endif /* WOLFSSL_SHA384 */ + +#if defined(WOLFSSL_SHA512) + +WOLFSSL_API int wc_InitSha512_ex(wc_Sha512* sha512, void* heap, int devId) +{ + if (sha512 == NULL) { + return BAD_FUNC_ARG; + } + (void)devId; + XMEMSET(sha512, 0, sizeof(*sha512)); + sha512->heap = heap; +#if defined(WOLFSSL_SHA512_HASHTYPE) + sha512->hashType = WC_HASH_TYPE_SHA512; +#endif + return wc_MXC_TPU_SHA_Init((word32*)sha512->digest, + MXC_SHA512_STATE_WORDS, MXC_TPU_HASH_SHA512); +} + +WOLFSSL_API int wc_InitSha512(wc_Sha512* sha512) +{ + return wc_InitSha512_ex(sha512, NULL, INVALID_DEVID); +} + +WOLFSSL_API int wc_Sha512Update(wc_Sha512* sha512, const unsigned char* data, + unsigned int len) +{ + word32 loLen, hiLen; + int ret; + if (sha512 == NULL || (data == NULL && len > 0)) { + return BAD_FUNC_ARG; + } + + loLen = (word32)sha512->loLen; + hiLen = (word32)(sha512->loLen >> 32); + + ret = wc_MXC_TPU_SHA_Update((word32*)sha512->digest, + (word32*)sha512->buffer, &sha512->buffLen, + &loLen, &hiLen, + MXC_SHA512_STATE_WORDS, WC_SHA512_BLOCK_SIZE, + MXC_TPU_HASH_SHA512, data, len); + + sha512->loLen = (word64)loLen | ((word64)hiLen << 32); + return ret; +} + +WOLFSSL_API int wc_Sha512Final(wc_Sha512* sha512, unsigned char* hash) +{ + int ret; + if (sha512 == NULL || hash == NULL) { + return BAD_FUNC_ARG; + } + ret = wc_MXC_TPU_SHA_Final((word32*)sha512->digest, + (word32*)sha512->buffer, &sha512->buffLen, + (word32)sha512->loLen, (word32)(sha512->loLen >> 32), + MXC_SHA512_STATE_WORDS, + WC_SHA512_DIGEST_SIZE, MXC_TPU_HASH_SHA512, hash); + if (ret == 0) { + return wc_InitSha512_ex(sha512, sha512->heap, INVALID_DEVID); + } + return ret; +} + +WOLFSSL_API int wc_Sha512GetHash(wc_Sha512* sha512, unsigned char* hash) +{ + if (sha512 == NULL || hash == NULL) { + return BAD_FUNC_ARG; + } + return wc_MXC_TPU_SHA_GetHash((word32*)sha512->digest, + (word32*)sha512->buffer, sha512->buffLen, + (word32)sha512->loLen, (word32)(sha512->loLen >> 32), + MXC_SHA512_STATE_WORDS, + WC_SHA512_DIGEST_SIZE, MXC_TPU_HASH_SHA512, hash); +} + +WOLFSSL_API int wc_Sha512Copy(wc_Sha512* src, wc_Sha512* dst) +{ + if (src == NULL || dst == NULL) { + return BAD_FUNC_ARG; + } + XMEMCPY(dst, src, sizeof(wc_Sha512)); + return 0; +} + +WOLFSSL_API void wc_Sha512Free(wc_Sha512* sha512) +{ + if (sha512 == NULL) { + return; + } + ForceZero(sha512, sizeof(wc_Sha512)); +} + +#endif /* WOLFSSL_SHA512 */ + +#endif /* WOLFSSL_MAX3266X_SHA_ONESHOT */ +#endif /* !MAX3266X_SHA_CB */ #endif /* MAX3266X_SHA || MAX3266X_SHA_CB */ #if defined(MAX3266X_MATH) @@ -1285,6 +2178,7 @@ int wc_MXC_MAA_zeroPad(mp_int* multiplier, mp_int* multiplicand, MXC_TPU_MAA_TYPE clc, unsigned int length) { mp_digit* zero_tmp; + unsigned int zero_size; MAX3266X_MSG("Zero Padding Buffers for Hardware"); if (length > MXC_MAA_MAX_SIZE) { MAX3266X_MSG("Hardware cannot exceed 2048 bit input"); @@ -1296,19 +2190,23 @@ int wc_MXC_MAA_zeroPad(mp_int* multiplier, mp_int* multiplicand, } /* Create an array to compare values to to check edge for error edge case */ - zero_tmp = (mp_digit*)XMALLOC(multiplier->size*sizeof(mp_digit), NULL, + zero_size = mod->size; + if ((exp != NULL) && (exp->size > zero_size)) { + zero_size = exp->size; + } + zero_tmp = (mp_digit*)XMALLOC(zero_size*sizeof(mp_digit), NULL, DYNAMIC_TYPE_TMP_BUFFER); if (zero_tmp == NULL) { MAX3266X_MSG("NULL pointer found after XMALLOC call"); return MEMORY_E; } - XMEMSET(zero_tmp, 0x00, multiplier->size*sizeof(mp_digit)); + XMEMSET(zero_tmp, 0x00, zero_size*sizeof(mp_digit)); /* Check for invalid arguments before padding */ switch ((char)clc) { case MXC_TPU_MAA_EXP: /* Cannot be 0 for a^e mod m operation */ - if (XMEMCMP(zero_tmp, exp, (exp->used*sizeof(mp_digit))) == 0) { + if (XMEMCMP(zero_tmp, exp->dp, (exp->used*sizeof(mp_digit))) == 0) { XFREE(zero_tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER); MAX3266X_MSG("Cannot use Value 0 for Exp"); return BAD_FUNC_ARG; @@ -1331,7 +2229,7 @@ int wc_MXC_MAA_zeroPad(mp_int* multiplier, mp_int* multiplicand, case MXC_TPU_MAA_ADD: case MXC_TPU_MAA_SUB: /* Cannot be 0 for mod m value */ - if (XMEMCMP(zero_tmp, mod, (exp->used*sizeof(mp_digit))) == 0) { + if (XMEMCMP(zero_tmp, mod->dp, (mod->used*sizeof(mp_digit))) == 0) { XFREE(zero_tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER); MAX3266X_MSG("Cannot use Value 0 for Exp"); return BAD_FUNC_ARG; diff --git a/wolfcrypt/src/port/ppc64/ppc64-aes-asm.S b/wolfcrypt/src/port/ppc64/ppc64-aes-asm.S index 4e3c681efc..38166beb8a 100644 --- a/wolfcrypt/src/port/ppc64/ppc64-aes-asm.S +++ b/wolfcrypt/src/port/ppc64/ppc64-aes-asm.S @@ -583,6 +583,11 @@ L_AES_PPC64_te: .type AES_invert_key,@function .align 16 AES_invert_key: +#if defined(_CALL_ELF) && _CALL_ELF == 2 +0: addis 2, 12, .TOC.-0b@ha + addi 2, 2, .TOC.-0b@l + .localentry AES_invert_key, .-AES_invert_key +#endif #else .section __TEXT,__text .globl _AES_invert_key @@ -595,20 +600,10 @@ _AES_invert_key: std 14, 0(1) std 15, 8(1) std 16, 16(1) -#if defined(__ARCH_PWR8) || (defined(_ARCH_PWR8)) addis 5, 2, L_AES_PPC64_te@toc@ha addi 5, 5, L_AES_PPC64_te@toc@l -#else - lis 5, L_AES_PPC64_te@ha - la 5, L_AES_PPC64_te@l(5) -#endif /* defined(__ARCH_PWR8) || (defined(_ARCH_PWR8)) */ -#if defined(__ARCH_PWR8) || (defined(_ARCH_PWR8)) addis 6, 2, L_AES_PPC64_td@toc@ha addi 6, 6, L_AES_PPC64_td@toc@l -#else - lis 6, L_AES_PPC64_td@ha - la 6, L_AES_PPC64_td@l(6) -#endif /* defined(__ARCH_PWR8) || (defined(_ARCH_PWR8)) */ addi 5, 5, 3 sldi 16, 4, 4 add 16, 16, 3 @@ -787,6 +782,11 @@ L_AES_PPC64_rcon: .type AES_set_encrypt_key,@function .align 16 AES_set_encrypt_key: +#if defined(_CALL_ELF) && _CALL_ELF == 2 +0: addis 2, 12, .TOC.-0b@ha + addi 2, 2, .TOC.-0b@l + .localentry AES_set_encrypt_key, .-AES_set_encrypt_key +#endif #else .section __TEXT,__text .globl _AES_set_encrypt_key @@ -798,20 +798,10 @@ _AES_set_encrypt_key: std 0, 16(1) std 14, 0(1) std 15, 8(1) -#if defined(__ARCH_PWR8) || (defined(_ARCH_PWR8)) addis 6, 2, L_AES_PPC64_te@toc@ha addi 6, 6, L_AES_PPC64_te@toc@l -#else - lis 6, L_AES_PPC64_te@ha - la 6, L_AES_PPC64_te@l(6) -#endif /* defined(__ARCH_PWR8) || (defined(_ARCH_PWR8)) */ -#if defined(__ARCH_PWR8) || (defined(_ARCH_PWR8)) addis 7, 2, L_AES_PPC64_rcon@toc@ha addi 7, 7, L_AES_PPC64_rcon@toc@l -#else - lis 7, L_AES_PPC64_rcon@ha - la 7, L_AES_PPC64_rcon@l(7) -#endif /* defined(__ARCH_PWR8) || (defined(_ARCH_PWR8)) */ addi 6, 6, 3 cmplwi 4, 0x80 beq L_AES_set_encrypt_key_start_128 @@ -2115,6 +2105,11 @@ L_AES_PPC64_te4_0: .type AES_ECB_encrypt,@function .align 16 AES_ECB_encrypt: +#if defined(_CALL_ELF) && _CALL_ELF == 2 +0: addis 2, 12, .TOC.-0b@ha + addi 2, 2, .TOC.-0b@l + .localentry AES_ECB_encrypt, .-AES_ECB_encrypt +#endif #else .section __TEXT,__text .globl _AES_ECB_encrypt @@ -2136,13 +2131,8 @@ _AES_ECB_encrypt: std 23, 72(1) std 24, 80(1) std 25, 88(1) -#if defined(__ARCH_PWR8) || (defined(_ARCH_PWR8)) addis 8, 2, L_AES_PPC64_te4_0@toc@ha addi 8, 8, L_AES_PPC64_te4_0@toc@l -#else - lis 8, L_AES_PPC64_te4_0@ha - la 8, L_AES_PPC64_te4_0@l(8) -#endif /* defined(__ARCH_PWR8) || (defined(_ARCH_PWR8)) */ addi 9, 8, 0x400 addi 10, 8, 0x800 addi 11, 8, 0xc00 @@ -2479,6 +2469,11 @@ L_AES_ECB_encrypt_loop_nr: .type AES_CBC_encrypt,@function .align 16 AES_CBC_encrypt: +#if defined(_CALL_ELF) && _CALL_ELF == 2 +0: addis 2, 12, .TOC.-0b@ha + addi 2, 2, .TOC.-0b@l + .localentry AES_CBC_encrypt, .-AES_CBC_encrypt +#endif #else .section __TEXT,__text .globl _AES_CBC_encrypt @@ -2501,13 +2496,8 @@ _AES_CBC_encrypt: std 24, 80(1) std 25, 88(1) std 26, 96(1) -#if defined(__ARCH_PWR8) || (defined(_ARCH_PWR8)) addis 9, 2, L_AES_PPC64_te4_0@toc@ha addi 9, 9, L_AES_PPC64_te4_0@toc@l -#else - lis 9, L_AES_PPC64_te4_0@ha - la 9, L_AES_PPC64_te4_0@l(9) -#endif /* defined(__ARCH_PWR8) || (defined(_ARCH_PWR8)) */ ld 14, 0(8) ld 15, 8(8) addi 10, 9, 0x400 @@ -2850,6 +2840,11 @@ L_AES_CBC_encrypt_loop_nr: .type AES_CTR_encrypt,@function .align 16 AES_CTR_encrypt: +#if defined(_CALL_ELF) && _CALL_ELF == 2 +0: addis 2, 12, .TOC.-0b@ha + addi 2, 2, .TOC.-0b@l + .localentry AES_CTR_encrypt, .-AES_CTR_encrypt +#endif #else .section __TEXT,__text .globl _AES_CTR_encrypt @@ -2874,13 +2869,8 @@ _AES_CTR_encrypt: std 26, 96(1) std 27, 104(1) std 28, 112(1) -#if defined(__ARCH_PWR8) || (defined(_ARCH_PWR8)) addis 9, 2, L_AES_PPC64_te4_0@toc@ha addi 9, 9, L_AES_PPC64_te4_0@toc@l -#else - lis 9, L_AES_PPC64_te4_0@ha - la 9, L_AES_PPC64_te4_0@l(9) -#endif /* defined(__ARCH_PWR8) || (defined(_ARCH_PWR8)) */ ld 22, 0(8) ld 23, 8(8) addi 10, 9, 0x400 @@ -3227,6 +3217,11 @@ L_AES_CTR_encrypt_loop_nr: .type AES_GCM_encrypt,@function .align 16 AES_GCM_encrypt: +#if defined(_CALL_ELF) && _CALL_ELF == 2 +0: addis 2, 12, .TOC.-0b@ha + addi 2, 2, .TOC.-0b@l + .localentry AES_GCM_encrypt, .-AES_GCM_encrypt +#endif #else .section __TEXT,__text .globl _AES_GCM_encrypt @@ -3251,13 +3246,8 @@ _AES_GCM_encrypt: std 26, 96(1) std 27, 104(1) std 28, 112(1) -#if defined(__ARCH_PWR8) || (defined(_ARCH_PWR8)) addis 9, 2, L_AES_PPC64_te4_0@toc@ha addi 9, 9, L_AES_PPC64_te4_0@toc@l -#else - lis 9, L_AES_PPC64_te4_0@ha - la 9, L_AES_PPC64_te4_0@l(9) -#endif /* defined(__ARCH_PWR8) || (defined(_ARCH_PWR8)) */ ld 26, 0(8) ld 27, 8(8) addi 10, 9, 0x400 @@ -3604,6 +3594,11 @@ L_AES_GCM_encrypt_loop_nr: .type AES_XTS_encrypt,@function .align 16 AES_XTS_encrypt: +#if defined(_CALL_ELF) && _CALL_ELF == 2 +0: addis 2, 12, .TOC.-0b@ha + addi 2, 2, .TOC.-0b@l + .localentry AES_XTS_encrypt, .-AES_XTS_encrypt +#endif #else .section __TEXT,__text .globl _AES_XTS_encrypt @@ -3629,13 +3624,8 @@ _AES_XTS_encrypt: std 27, 104(1) std 28, 112(1) std 29, 120(1) -#if defined(__ARCH_PWR8) || (defined(_ARCH_PWR8)) addis 11, 2, L_AES_PPC64_te4_0@toc@ha addi 11, 11, L_AES_PPC64_te4_0@toc@l -#else - lis 11, L_AES_PPC64_te4_0@ha - la 11, L_AES_PPC64_te4_0@l(11) -#endif /* defined(__ARCH_PWR8) || (defined(_ARCH_PWR8)) */ addi 12, 11, 0x400 addi 14, 11, 0x800 addi 15, 11, 0xc00 @@ -4893,6 +4883,11 @@ L_AES_PPC64_td4: .type AES_ECB_decrypt,@function .align 16 AES_ECB_decrypt: +#if defined(_CALL_ELF) && _CALL_ELF == 2 +0: addis 2, 12, .TOC.-0b@ha + addi 2, 2, .TOC.-0b@l + .localentry AES_ECB_decrypt, .-AES_ECB_decrypt +#endif #else .section __TEXT,__text .globl _AES_ECB_decrypt @@ -4912,20 +4907,10 @@ _AES_ECB_decrypt: std 21, 56(1) std 22, 64(1) std 23, 72(1) -#if defined(__ARCH_PWR8) || (defined(_ARCH_PWR8)) addis 8, 2, L_AES_PPC64_td@toc@ha addi 8, 8, L_AES_PPC64_td@toc@l -#else - lis 8, L_AES_PPC64_td@ha - la 8, L_AES_PPC64_td@l(8) -#endif /* defined(__ARCH_PWR8) || (defined(_ARCH_PWR8)) */ -#if defined(__ARCH_PWR8) || (defined(_ARCH_PWR8)) addis 9, 2, L_AES_PPC64_td4@toc@ha addi 9, 9, L_AES_PPC64_td4@toc@l -#else - lis 9, L_AES_PPC64_td4@ha - la 9, L_AES_PPC64_td4@l(9) -#endif /* defined(__ARCH_PWR8) || (defined(_ARCH_PWR8)) */ L_AES_ECB_decrypt_loop_block: addi 23, 6, 0 ld 10, 0(3) @@ -5258,6 +5243,11 @@ L_AES_ECB_decrypt_loop_nr: .type AES_CBC_decrypt,@function .align 16 AES_CBC_decrypt: +#if defined(_CALL_ELF) && _CALL_ELF == 2 +0: addis 2, 12, .TOC.-0b@ha + addi 2, 2, .TOC.-0b@l + .localentry AES_CBC_decrypt, .-AES_CBC_decrypt +#endif #else .section __TEXT,__text .globl _AES_CBC_decrypt @@ -5282,20 +5272,10 @@ _AES_CBC_decrypt: std 26, 96(1) std 27, 104(1) std 28, 112(1) -#if defined(__ARCH_PWR8) || (defined(_ARCH_PWR8)) addis 10, 2, L_AES_PPC64_td4@toc@ha addi 10, 10, L_AES_PPC64_td4@toc@l -#else - lis 10, L_AES_PPC64_td4@ha - la 10, L_AES_PPC64_td4@l(10) -#endif /* defined(__ARCH_PWR8) || (defined(_ARCH_PWR8)) */ -#if defined(__ARCH_PWR8) || (defined(_ARCH_PWR8)) addis 9, 2, L_AES_PPC64_td@toc@ha addi 9, 9, L_AES_PPC64_td@toc@l -#else - lis 9, L_AES_PPC64_td@ha - la 9, L_AES_PPC64_td@l(9) -#endif /* defined(__ARCH_PWR8) || (defined(_ARCH_PWR8)) */ ld 24, 0(8) ld 25, 8(8) L_AES_CBC_decrypt_loop_block: @@ -5954,6 +5934,11 @@ L_AES_CBC_decrypt_end_dec: .type AES_XTS_decrypt,@function .align 16 AES_XTS_decrypt: +#if defined(_CALL_ELF) && _CALL_ELF == 2 +0: addis 2, 12, .TOC.-0b@ha + addi 2, 2, .TOC.-0b@l + .localentry AES_XTS_decrypt, .-AES_XTS_decrypt +#endif #else .section __TEXT,__text .globl _AES_XTS_decrypt @@ -5979,13 +5964,8 @@ _AES_XTS_decrypt: std 27, 104(1) std 28, 112(1) std 29, 120(1) -#if defined(__ARCH_PWR8) || (defined(_ARCH_PWR8)) addis 14, 2, L_AES_PPC64_te4_0@toc@ha addi 14, 14, L_AES_PPC64_te4_0@toc@l -#else - lis 14, L_AES_PPC64_te4_0@ha - la 14, L_AES_PPC64_te4_0@l(14) -#endif /* defined(__ARCH_PWR8) || (defined(_ARCH_PWR8)) */ addi 15, 14, 0x400 addi 16, 14, 0x800 addi 17, 14, 0xc00 @@ -6292,20 +6272,10 @@ L_AES_XTS_decrypt_loop_nr_tweak: xor 27, 27, 19 std 26, 0(9) std 27, 8(9) -#if defined(__ARCH_PWR8) || (defined(_ARCH_PWR8)) addis 11, 2, L_AES_PPC64_td@toc@ha addi 11, 11, L_AES_PPC64_td@toc@l -#else - lis 11, L_AES_PPC64_td@ha - la 11, L_AES_PPC64_td@l(11) -#endif /* defined(__ARCH_PWR8) || (defined(_ARCH_PWR8)) */ -#if defined(__ARCH_PWR8) || (defined(_ARCH_PWR8)) addis 12, 2, L_AES_PPC64_td4@toc@ha addi 12, 12, L_AES_PPC64_td4@toc@l -#else - lis 12, L_AES_PPC64_td4@ha - la 12, L_AES_PPC64_td4@l(12) -#endif /* defined(__ARCH_PWR8) || (defined(_ARCH_PWR8)) */ cmpdi 5, 16 blt L_AES_XTS_decrypt_start_partail L_AES_XTS_decrypt_loop_block: @@ -7359,6 +7329,11 @@ L_GCM_gmult_len_r: .type GCM_gmult_len,@function .align 16 GCM_gmult_len: +#if defined(_CALL_ELF) && _CALL_ELF == 2 +0: addis 2, 12, .TOC.-0b@ha + addi 2, 2, .TOC.-0b@l + .localentry GCM_gmult_len, .-GCM_gmult_len +#endif #else .section __TEXT,__text .globl _GCM_gmult_len @@ -7382,13 +7357,8 @@ _GCM_gmult_len: std 25, 88(1) li 21, 0x100 li 25, 8 -#if defined(__ARCH_PWR8) || (defined(_ARCH_PWR8)) addis 7, 2, L_GCM_gmult_len_r@toc@ha addi 7, 7, L_GCM_gmult_len_r@toc@l -#else - lis 7, L_GCM_gmult_len_r@ha - la 7, L_GCM_gmult_len_r@l(7) -#endif /* defined(__ARCH_PWR8) || (defined(_ARCH_PWR8)) */ add 21, 21, 4 addi 20, 4, 8 addi 22, 21, 8 @@ -8351,6 +8321,11 @@ L_GCM_gmult_len_r: .type GCM_gmult_len,@function .align 16 GCM_gmult_len: +#if defined(_CALL_ELF) && _CALL_ELF == 2 +0: addis 2, 12, .TOC.-0b@ha + addi 2, 2, .TOC.-0b@l + .localentry GCM_gmult_len, .-GCM_gmult_len +#endif #else .section __TEXT,__text .globl _GCM_gmult_len @@ -8366,13 +8341,8 @@ _GCM_gmult_len: std 17, 24(1) std 18, 32(1) std 19, 40(1) -#if defined(__ARCH_PWR8) || (defined(_ARCH_PWR8)) addis 7, 2, L_GCM_gmult_len_r@toc@ha addi 7, 7, L_GCM_gmult_len_r@toc@l -#else - lis 7, L_GCM_gmult_len_r@ha - la 7, L_GCM_gmult_len_r@l(7) -#endif /* defined(__ARCH_PWR8) || (defined(_ARCH_PWR8)) */ addi 0, 4, 8 li 17, 8 L_GCM_gmult_len_start_block: diff --git a/wolfcrypt/src/random.c b/wolfcrypt/src/random.c index 7b85d481d7..a75d3400e7 100644 --- a/wolfcrypt/src/random.c +++ b/wolfcrypt/src/random.c @@ -1715,7 +1715,7 @@ static int _InitRng(WC_RNG* rng, byte* nonce, word32 nonceSz, void* heap, int devId) { int ret = 0; -#ifdef HAVE_HASHDRBG +#if defined(HAVE_HASHDRBG) && !defined(CUSTOM_RAND_GENERATE_BLOCK) #if !defined(HAVE_FIPS) && defined(WOLFSSL_RNG_USE_FULL_SEED) word32 seedSz = SEED_SZ; #else @@ -2175,6 +2175,10 @@ int wc_rng_new_ex(WC_RNG **rng, byte* nonce, word32 nonceSz, { int ret; + if (rng == NULL) { + return BAD_FUNC_ARG; + } + *rng = (WC_RNG*)XMALLOC(sizeof(WC_RNG), heap, DYNAMIC_TYPE_RNG); if (*rng == NULL) { return MEMORY_E; diff --git a/wolfcrypt/src/rsa.c b/wolfcrypt/src/rsa.c index e265d69cf4..0a6b6143a7 100644 --- a/wolfcrypt/src/rsa.c +++ b/wolfcrypt/src/rsa.c @@ -831,6 +831,10 @@ int wc_CheckRsaKey(RsaKey* key) } #endif + if (MP_BITS_OVER_MAX(mp_bitsused(&key->n), RSA_MAX_SIZE)) { + return WC_KEY_SIZE_E; + } + NEW_MP_INT_SIZE(tmp, mp_bitsused(&key->n), NULL, DYNAMIC_TYPE_RSA); #ifdef MP_INT_SIZE_CHECK_NULL if (tmp == NULL) { @@ -978,10 +982,10 @@ int wc_CheckRsaKey(RsaKey* key) XFREE(rng, NULL, DYNAMIC_TYPE_RNG); #endif } - FREE_MP_INT_SIZE(tmp, NULL, DYNAMIC_TYPE_RSA); #ifdef WOLFSSL_CHECK_MEM_ZERO mp_memzero_check(tmp); #endif + FREE_MP_INT_SIZE(tmp, NULL, DYNAMIC_TYPE_RSA); return ret; } @@ -2863,6 +2867,10 @@ static int RsaFunctionPrivate(mp_int* tmp, RsaKey* key, WC_RNG* rng) DECL_MP_INT_SIZE_DYN(rndi, mp_bitsused(&key->n), RSA_MAX_SIZE); #endif /* WC_RSA_BLINDING && !WC_NO_RNG */ + if (MP_BITS_OVER_MAX(mp_bitsused(&key->n), RSA_MAX_SIZE)) { + return WC_KEY_SIZE_E; + } + (void)rng; #if defined(WC_RSA_BLINDING) && !defined(WC_NO_RNG) @@ -3042,6 +3050,10 @@ static int RsaFunctionSync(const byte* in, word32 inLen, byte* out, DECL_MP_INT_SIZE_DYN(tmp, mp_bitsused(&key->n), RSA_MAX_SIZE); int ret = 0; + if (MP_BITS_OVER_MAX(mp_bitsused(&key->n), RSA_MAX_SIZE)) { + return WC_KEY_SIZE_E; + } + (void)rng; NEW_MP_INT_SIZE(tmp, mp_bitsused(&key->n), key->heap, DYNAMIC_TYPE_RSA); @@ -3304,7 +3316,7 @@ int wc_RsaDirect(const byte* in, word32 inLen, byte* out, word32* outSz, } if ((ret = wc_RsaEncryptSize(key)) < 0) { - return BAD_FUNC_ARG; + return ret; } if (inLen != (word32)ret) { @@ -3469,8 +3481,13 @@ int RsaFunctionCheckIn(const byte* in, word32 inLen, RsaKey* key, int checkSmallCt) { int ret = 0; + DECL_MP_INT_SIZE_DYN(c, mp_bitsused(&key->n), RSA_MAX_SIZE); + if (MP_BITS_OVER_MAX(mp_bitsused(&key->n), RSA_MAX_SIZE)) { + return WC_KEY_SIZE_E; + } + NEW_MP_INT_SIZE(c, mp_bitsused(&key->n), key->heap, DYNAMIC_TYPE_RSA); #ifdef MP_INT_SIZE_CHECK_NULL if (c == NULL) diff --git a/wolfcrypt/src/sha3.c b/wolfcrypt/src/sha3.c index 2b0106601c..33d0692883 100644 --- a/wolfcrypt/src/sha3.c +++ b/wolfcrypt/src/sha3.c @@ -76,6 +76,24 @@ #include #endif +/* Gates the non-WOLFSSL_SHA3_SMALL software Keccak primitives + * (hash_keccak_r, BlockSha3, InitSha3, Sha3Update, Sha3Final and the + * Load64* helpers). Compiled when: + * - No HW SHA-3 backend is selected (the original baseline), OR + * - STM32 HW SHA-3 is selected and SHAKE is enabled - SHAKE on STM32MP13 + * runs in software because the HASH peripheral's SHAKE support is + * fixed-length and does not match wolfSSL's variable-length / iterative + * SqueezeBlocks API. SHA-3 still uses the HASH peripheral. + * + * Note: the WOLFSSL_SHA3_SMALL branch earlier in this file defines its + * own hash_keccak_r and BlockSha3 unconditionally inside its #ifdef + * block, so this macro only controls the non-SMALL implementation. */ +#if (!defined(STM32_HASH_SHA3) && !defined(PSOC6_HASH_SHA3)) || \ + (defined(STM32_HASH_SHA3) && \ + (defined(WOLFSSL_SHAKE128) || defined(WOLFSSL_SHAKE256))) + #define WC_SHA3_SW_KECCAK +#endif + #if FIPS_VERSION3_GE(6,0,0) const unsigned int wolfCrypt_FIPS_sha3_ro_sanity[2] = { 0x1a2b3c4d, 0x00000016 }; @@ -320,7 +338,7 @@ void BlockSha3(word64* s) */ #define ROTL64(a, n) (((a)<<(n))|((a)>>(64-(n)))) -#if !defined(STM32_HASH_SHA3) && !defined(PSOC6_HASH_SHA3) +#ifdef WC_SHA3_SW_KECCAK /* An array of values to XOR for block operation. */ static const word64 hash_keccak_r[24] = { @@ -555,7 +573,7 @@ do { \ while (0) #endif /* SHA3_BY_SPEC */ -#if !defined(STM32_HASH_SHA3) && !defined(PSOC6_HASH_SHA3) +#ifdef WC_SHA3_SW_KECCAK /* The block operation performed on the state. * * s The state. @@ -581,11 +599,11 @@ void BlockSha3(word64* s) s[0] ^= hash_keccak_r[i+1]; } } -#endif /* WOLFSSL_SHA3_SMALL */ -#endif /* STM32_HASH_SHA3 */ +#endif /* WC_SHA3_SW_KECCAK */ +#endif /* !WOLFSSL_SHA3_SMALL */ #endif /* !WOLFSSL_ARMASM && !WOLFSSL_RISCV_ASM */ -#if !defined(STM32_HASH_SHA3) && !defined(PSOC6_HASH_SHA3) +#ifdef WC_SHA3_SW_KECCAK #if defined(BIG_ENDIAN_ORDER) static WC_INLINE word64 Load64Unaligned(const unsigned char *a) { @@ -929,7 +947,7 @@ static int Sha3Final(wc_Sha3* sha3, byte padChar, byte* hash, byte p, word32 l) return 0; } -#endif +#endif /* WC_SHA3_SW_KECCAK */ #if defined(STM32_HASH_SHA3) /* Supports CubeMX HAL or Standard Peripheral Library */ diff --git a/wolfcrypt/src/sha512.c b/wolfcrypt/src/sha512.c index 425ad745c2..b2f57b13b8 100644 --- a/wolfcrypt/src/sha512.c +++ b/wolfcrypt/src/sha512.c @@ -56,6 +56,12 @@ #include +#if (defined(WOLFSSL_SHA512) || defined(WOLFSSL_SHA384)) && \ + defined(WOLF_CRYPTO_CB_ONLY_SHA512) && defined(WOLFSSL_RISCV_ASM) + #error "WOLF_CRYPTO_CB_ONLY_SHA512 is incompatible with SHA-512 hardware" \ + " acceleration backends" +#endif + #if (defined(WOLFSSL_SHA512) || defined(WOLFSSL_SHA384)) && \ !defined(WOLFSSL_RISCV_ASM) @@ -159,6 +165,45 @@ /* #define DEBUG_YMM */ #endif +#ifdef WOLF_CRYPTO_CB_ONLY_SHA512 +/* WOLF_CRYPTO_CB_ONLY_SHA512 strips the software SHA-512 implementation and + * routes every operation (SHA-512, SHA-384, SHA-512/224, SHA-512/256) through + * the crypto callback. It is mutually exclusive with any in-tree SHA-512 + * hardware/asm backend: keep this list in sync with the backend dispatch + * chains in sha512.c. The RISC-V asm guard lives before the outer file guard; + * these guards live before the dispatch chain so they are evaluated before a + * hardware backend wins the #elif chain (in which case the + * WOLF_CRYPTO_CB_ONLY_SHA512 branch itself is never compiled). */ +#if (defined(WOLFSSL_IMX6_CAAM) && !defined(NO_IMX6_CAAM_HASH) && \ + !defined(WOLFSSL_QNX_CAAM)) || \ + defined(WOLFSSL_SILABS_SHA512) || \ + defined(WOLFSSL_KCAPI_HASH) || \ + (defined(WOLFSSL_RENESAS_RSIP) && \ + !defined(NO_WOLFSSL_RENESAS_FSPSM_HASH)) || \ + defined(MAX3266X_SHA) || \ + (defined(WOLFSSL_SE050) && defined(WOLFSSL_SE050_HASH)) || \ + defined(STM32_HASH_SHA512) || \ + defined(PSOC6_HASH_SHA2) || \ + defined(WOLFSSL_USE_ESP32_CRYPT_HASH_HW) || \ + defined(WOLFSSL_ARMASM) || \ + (defined(WOLFSSL_X86_64_BUILD) && defined(USE_INTEL_SPEEDUP) && \ + (defined(HAVE_INTEL_AVX1) || defined(HAVE_INTEL_AVX2))) + #error "WOLF_CRYPTO_CB_ONLY_SHA512 is incompatible with SHA-512 hardware" \ + " acceleration backends" +#endif +#if defined(HAVE_FIPS) + #error "WOLF_CRYPTO_CB_ONLY_SHA512 is incompatible with FIPS builds" +#endif +/* WOLFSSL_HASH_KEEP accumulates all Update data into sha->msg and passes it + * all to hardware in Final. That pattern is driven by port-specific backends + * (e.g. CAAM) which are already excluded above; the crypto-callback Update + * path dispatches each chunk directly to the callback instead, so the two + * mechanisms are incompatible. */ +#ifdef WOLFSSL_HASH_KEEP + #error "WOLF_CRYPTO_CB_ONLY_SHA512 is incompatible with WOLFSSL_HASH_KEEP" +#endif +#endif /* WOLF_CRYPTO_CB_ONLY_SHA512 */ + #if defined(WOLFSSL_IMX6_CAAM) && !defined(NO_IMX6_CAAM_HASH) && \ !defined(WOLFSSL_QNX_CAAM) /* functions defined in wolfcrypt/src/port/caam/caam_sha.c */ @@ -318,6 +363,544 @@ #elif defined(PSOC6_HASH_SHA2) /* Functions defined in wolfcrypt/src/port/cypress/psoc6_crypto.c */ +#elif defined(WOLF_CRYPTO_CB_ONLY_SHA512) + +static int Sha512_CbReset(wc_Sha512* sha512, const word64* initDigest, + int hashType) +{ + int i; + + if (sha512 == NULL) + return BAD_FUNC_ARG; + + for (i = 0; i < 8; i++) + sha512->digest[i] = initDigest[i]; + + sha512->buffLen = 0; + XMEMSET(sha512->buffer, 0, sizeof(sha512->buffer)); + sha512->loLen = 0; + sha512->hiLen = 0; +#ifdef WOLFSSL_HASH_FLAGS + sha512->flags = 0; +#endif +#if defined(WOLFSSL_SHA512_HASHTYPE) + sha512->hashType = hashType; +#else + (void)hashType; +#endif + return 0; +} + +static int Sha512_CbInit(wc_Sha512* sha512, const word64* initDigest, + void* heap, int devId, int hashType) +{ + int ret; + + /* Zero the whole struct first so fields not touched by the callback path + * (e.g. asyncDev, W, devCtx) never expose uninitialized stack data to a + * callback; the admin fields below are then set explicitly. */ + if (sha512 != NULL) + XMEMSET(sha512, 0, sizeof(*sha512)); + + ret = Sha512_CbReset(sha512, initDigest, hashType); + if (ret != 0) + return ret; + + sha512->heap = heap; + sha512->devId = devId; + sha512->devCtx = NULL; + + return 0; +} + +#ifdef WOLFSSL_SHA512 + +static const word64 sha512Init[8] = { + W64LIT(0x6a09e667f3bcc908), W64LIT(0xbb67ae8584caa73b), + W64LIT(0x3c6ef372fe94f82b), W64LIT(0xa54ff53a5f1d36f1), + W64LIT(0x510e527fade682d1), W64LIT(0x9b05688c2b3e6c1f), + W64LIT(0x1f83d9abfb41bd6b), W64LIT(0x5be0cd19137e2179) +}; + +static int Sha512_CbFinal(wc_Sha512* sha512, byte* hash, size_t digestSz) +{ + if (sha512 == NULL || hash == NULL) + return BAD_FUNC_ARG; + + #ifndef WOLF_CRYPTO_CB_FIND + if (sha512->devId != INVALID_DEVID) + #endif + { + int ret = wc_CryptoCb_Sha512Hash(sha512, NULL, 0, hash, digestSz); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) + return ret; + } + return NO_VALID_DEVID; +} + +int wc_InitSha512_ex(wc_Sha512* sha512, void* heap, int devId) +{ + return Sha512_CbInit(sha512, sha512Init, heap, devId, + WC_HASH_TYPE_SHA512); +} + +int wc_InitSha512(wc_Sha512* sha512) +{ + int devId = INVALID_DEVID; + +#ifdef WOLF_CRYPTO_CB + devId = wc_CryptoCb_DefaultDevID(); +#endif + return wc_InitSha512_ex(sha512, NULL, devId); +} + +int wc_Sha512Update(wc_Sha512* sha512, const byte* data, word32 len) +{ + if (sha512 == NULL) + return BAD_FUNC_ARG; + if (data == NULL && len == 0) + return 0; + if (data == NULL) + return BAD_FUNC_ARG; + + #ifndef WOLF_CRYPTO_CB_FIND + if (sha512->devId != INVALID_DEVID) + #endif + { + int ret = wc_CryptoCb_Sha512Hash(sha512, data, len, NULL, 0); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) + return ret; + } + return NO_VALID_DEVID; +} + +int wc_Sha512Final(wc_Sha512* sha512, byte* hash) +{ + return Sha512_CbFinal(sha512, hash, WC_SHA512_DIGEST_SIZE); +} + +void wc_Sha512Free(wc_Sha512* sha512) +{ +#ifdef WOLF_CRYPTO_CB_FREE + int ret = 0; +#endif + + if (sha512 == NULL) + return; + +#ifdef WOLF_CRYPTO_CB_FREE + #ifndef WOLF_CRYPTO_CB_FIND + if (sha512->devId != INVALID_DEVID) + #endif + { + ret = wc_CryptoCb_Free(sha512->devId, WC_ALGO_TYPE_HASH, + WC_HASH_TYPE_SHA512, 0, (void*)sha512); + /* If they want the standard free, they can call it themselves */ + /* via their callback setting devId to INVALID_DEVID */ + /* otherwise assume the callback handled it */ + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) + return; + /* fall-through when unavailable */ + } + + /* silence compiler warning */ + (void)ret; +#endif /* WOLF_CRYPTO_CB_FREE */ + + ForceZero(sha512, sizeof(*sha512)); +} + +int wc_Sha512GetHash(wc_Sha512* sha512, byte* hash) +{ + int ret; + WC_DECLARE_VAR(tmpSha512, wc_Sha512, 1, 0); + + if (sha512 == NULL || hash == NULL) + return BAD_FUNC_ARG; + + WC_CALLOC_VAR_EX(tmpSha512, wc_Sha512, 1, NULL, DYNAMIC_TYPE_TMP_BUFFER, + return MEMORY_E); + + ret = wc_Sha512Copy(sha512, tmpSha512); + if (ret == 0) { + ret = wc_Sha512Final(tmpSha512, hash); + wc_Sha512Free(tmpSha512); + } + + WC_FREE_VAR_EX(tmpSha512, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + return ret; +} + +int wc_Sha512Copy(wc_Sha512* src, wc_Sha512* dst) +{ + int ret = 0; + + if (src == NULL || dst == NULL) + return BAD_FUNC_ARG; + +#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_COPY) + #ifndef WOLF_CRYPTO_CB_FIND + if (src->devId != INVALID_DEVID) + #endif + { + ret = wc_CryptoCb_Copy(src->devId, WC_ALGO_TYPE_HASH, + WC_HASH_TYPE_SHA512, (void*)src, (void*)dst); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) + return ret; + /* fall-through when the callback is unavailable */ + } + ret = 0; /* discard CRYPTOCB_UNAVAILABLE before the plain struct copy */ +#endif /* WOLF_CRYPTO_CB && WOLF_CRYPTO_CB_COPY */ + + wc_Sha512Free(dst); + XMEMCPY(dst, src, sizeof(wc_Sha512)); + +#ifdef WOLFSSL_HASH_FLAGS + dst->flags |= WC_HASH_FLAG_ISCOPY; +#endif + + return ret; +} + +#ifdef WOLFSSL_HASH_FLAGS +int wc_Sha512SetFlags(wc_Sha512* sha512, word32 flags) +{ + if (sha512) + sha512->flags = flags; + return 0; +} +int wc_Sha512GetFlags(wc_Sha512* sha512, word32* flags) +{ + if (sha512 && flags) + *flags = sha512->flags; + return 0; +} +#endif /* WOLFSSL_HASH_FLAGS */ + +#if !defined(WOLFSSL_NOSHA512_224) && !defined(HAVE_SELFTEST) + +static const word64 sha512_224Init[8] = { + W64LIT(0x8c3d37c819544da2), W64LIT(0x73e1996689dcd4d6), + W64LIT(0x1dfab7ae32ff9c82), W64LIT(0x679dd514582f9fcf), + W64LIT(0x0f6d2b697bd44da8), W64LIT(0x77e36f7304c48942), + W64LIT(0x3f9d85a86a1d36c8), W64LIT(0x1112e6ad91d692a1) +}; + +int wc_InitSha512_224_ex(wc_Sha512* sha512, void* heap, int devId) +{ + return Sha512_CbInit(sha512, sha512_224Init, heap, devId, + WC_HASH_TYPE_SHA512_224); +} + +int wc_InitSha512_224(wc_Sha512* sha512) +{ + int devId = INVALID_DEVID; + +#ifdef WOLF_CRYPTO_CB + devId = wc_CryptoCb_DefaultDevID(); +#endif + return wc_InitSha512_224_ex(sha512, NULL, devId); +} + +int wc_Sha512_224Update(wc_Sha512* sha512, const byte* data, word32 len) +{ + return wc_Sha512Update(sha512, data, len); +} + +int wc_Sha512_224Final(wc_Sha512* sha512, byte* hash) +{ + return Sha512_CbFinal(sha512, hash, WC_SHA512_224_DIGEST_SIZE); +} + +void wc_Sha512_224Free(wc_Sha512* sha512) +{ + wc_Sha512Free(sha512); +} + +int wc_Sha512_224Copy(wc_Sha512* src, wc_Sha512* dst) +{ + return wc_Sha512Copy(src, dst); +} + +int wc_Sha512_224GetHash(wc_Sha512* sha512, byte* hash) +{ + int ret; + WC_DECLARE_VAR(tmpSha512, wc_Sha512, 1, 0); + + if (sha512 == NULL || hash == NULL) + return BAD_FUNC_ARG; + + WC_CALLOC_VAR_EX(tmpSha512, wc_Sha512, 1, NULL, DYNAMIC_TYPE_TMP_BUFFER, + return MEMORY_E); + + ret = wc_Sha512_224Copy(sha512, tmpSha512); + if (ret == 0) { + ret = wc_Sha512_224Final(tmpSha512, hash); + wc_Sha512_224Free(tmpSha512); + } + + WC_FREE_VAR_EX(tmpSha512, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + return ret; +} + +#ifdef WOLFSSL_HASH_FLAGS +int wc_Sha512_224SetFlags(wc_Sha512* sha512, word32 flags) +{ + return wc_Sha512SetFlags(sha512, flags); +} +int wc_Sha512_224GetFlags(wc_Sha512* sha512, word32* flags) +{ + return wc_Sha512GetFlags(sha512, flags); +} +#endif /* WOLFSSL_HASH_FLAGS */ + +#endif /* !WOLFSSL_NOSHA512_224 && !HAVE_SELFTEST */ + +#if !defined(WOLFSSL_NOSHA512_256) && !defined(HAVE_SELFTEST) + +static const word64 sha512_256Init[8] = { + W64LIT(0x22312194fc2bf72c), W64LIT(0x9f555fa3c84c64c2), + W64LIT(0x2393b86b6f53b151), W64LIT(0x963877195940eabd), + W64LIT(0x96283ee2a88effe3), W64LIT(0xbe5e1e2553863992), + W64LIT(0x2b0199fc2c85b8aa), W64LIT(0x0eb72ddc81c52ca2) +}; + +int wc_InitSha512_256_ex(wc_Sha512* sha512, void* heap, int devId) +{ + return Sha512_CbInit(sha512, sha512_256Init, heap, devId, + WC_HASH_TYPE_SHA512_256); +} + +int wc_InitSha512_256(wc_Sha512* sha512) +{ + int devId = INVALID_DEVID; + +#ifdef WOLF_CRYPTO_CB + devId = wc_CryptoCb_DefaultDevID(); +#endif + return wc_InitSha512_256_ex(sha512, NULL, devId); +} + +int wc_Sha512_256Update(wc_Sha512* sha512, const byte* data, word32 len) +{ + return wc_Sha512Update(sha512, data, len); +} + +int wc_Sha512_256Final(wc_Sha512* sha512, byte* hash) +{ + return Sha512_CbFinal(sha512, hash, WC_SHA512_256_DIGEST_SIZE); +} + +void wc_Sha512_256Free(wc_Sha512* sha512) +{ + wc_Sha512Free(sha512); +} + +int wc_Sha512_256Copy(wc_Sha512* src, wc_Sha512* dst) +{ + return wc_Sha512Copy(src, dst); +} + +int wc_Sha512_256GetHash(wc_Sha512* sha512, byte* hash) +{ + int ret; + WC_DECLARE_VAR(tmpSha512, wc_Sha512, 1, 0); + + if (sha512 == NULL || hash == NULL) + return BAD_FUNC_ARG; + + WC_CALLOC_VAR_EX(tmpSha512, wc_Sha512, 1, NULL, DYNAMIC_TYPE_TMP_BUFFER, + return MEMORY_E); + + ret = wc_Sha512_256Copy(sha512, tmpSha512); + if (ret == 0) { + ret = wc_Sha512_256Final(tmpSha512, hash); + wc_Sha512_256Free(tmpSha512); + } + + WC_FREE_VAR_EX(tmpSha512, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + return ret; +} + +#ifdef WOLFSSL_HASH_FLAGS +int wc_Sha512_256SetFlags(wc_Sha512* sha512, word32 flags) +{ + return wc_Sha512SetFlags(sha512, flags); +} +int wc_Sha512_256GetFlags(wc_Sha512* sha512, word32* flags) +{ + return wc_Sha512GetFlags(sha512, flags); +} +#endif /* WOLFSSL_HASH_FLAGS */ + +#endif /* !WOLFSSL_NOSHA512_256 && !HAVE_SELFTEST */ + +#endif /* WOLFSSL_SHA512 */ + +#ifdef WOLFSSL_SHA384 + +static const word64 sha384Init[8] = { + W64LIT(0xcbbb9d5dc1059ed8), W64LIT(0x629a292a367cd507), + W64LIT(0x9159015a3070dd17), W64LIT(0x152fecd8f70e5939), + W64LIT(0x67332667ffc00b31), W64LIT(0x8eb44a8768581511), + W64LIT(0xdb0c2e0d64f98fa7), W64LIT(0x47b5481dbefa4fa4) +}; + +int wc_InitSha384_ex(wc_Sha384* sha384, void* heap, int devId) +{ + return Sha512_CbInit(sha384, sha384Init, heap, devId, + WC_HASH_TYPE_SHA384); +} + +int wc_InitSha384(wc_Sha384* sha384) +{ + int devId = INVALID_DEVID; + +#ifdef WOLF_CRYPTO_CB + devId = wc_CryptoCb_DefaultDevID(); +#endif + return wc_InitSha384_ex(sha384, NULL, devId); +} + +int wc_Sha384Update(wc_Sha384* sha384, const byte* data, word32 len) +{ + if (sha384 == NULL) + return BAD_FUNC_ARG; + if (data == NULL && len == 0) + return 0; + if (data == NULL) + return BAD_FUNC_ARG; + + #ifndef WOLF_CRYPTO_CB_FIND + if (sha384->devId != INVALID_DEVID) + #endif + { + int ret = wc_CryptoCb_Sha384Hash(sha384, data, len, NULL); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) + return ret; + } + return NO_VALID_DEVID; +} + +int wc_Sha384Final(wc_Sha384* sha384, byte* hash) +{ + if (sha384 == NULL || hash == NULL) + return BAD_FUNC_ARG; + + #ifndef WOLF_CRYPTO_CB_FIND + if (sha384->devId != INVALID_DEVID) + #endif + { + int ret = wc_CryptoCb_Sha384Hash(sha384, NULL, 0, hash); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) + return ret; + } + return NO_VALID_DEVID; +} + +void wc_Sha384Free(wc_Sha384* sha384) +{ +#ifdef WOLF_CRYPTO_CB_FREE + int ret = 0; +#endif + + if (sha384 == NULL) + return; + +#ifdef WOLF_CRYPTO_CB_FREE + #ifndef WOLF_CRYPTO_CB_FIND + if (sha384->devId != INVALID_DEVID) + #endif + { + ret = wc_CryptoCb_Free(sha384->devId, WC_ALGO_TYPE_HASH, + WC_HASH_TYPE_SHA384, 0, (void*)sha384); + /* If they want the standard free, they can call it themselves */ + /* via their callback setting devId to INVALID_DEVID */ + /* otherwise assume the callback handled it */ + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) + return; + /* fall-through when unavailable */ + } + + /* silence compiler warning */ + (void)ret; +#endif /* WOLF_CRYPTO_CB_FREE */ + + ForceZero(sha384, sizeof(*sha384)); +} + +int wc_Sha384GetHash(wc_Sha384* sha384, byte* hash) +{ + int ret; + WC_DECLARE_VAR(tmpSha384, wc_Sha384, 1, 0); + + if (sha384 == NULL || hash == NULL) + return BAD_FUNC_ARG; + + WC_CALLOC_VAR_EX(tmpSha384, wc_Sha384, 1, NULL, DYNAMIC_TYPE_TMP_BUFFER, + return MEMORY_E); + + ret = wc_Sha384Copy(sha384, tmpSha384); + if (ret == 0) { + ret = wc_Sha384Final(tmpSha384, hash); + wc_Sha384Free(tmpSha384); + } + + WC_FREE_VAR_EX(tmpSha384, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + return ret; +} + +int wc_Sha384Copy(wc_Sha384* src, wc_Sha384* dst) +{ + int ret = 0; + + if (src == NULL || dst == NULL) + return BAD_FUNC_ARG; + +#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_COPY) + #ifndef WOLF_CRYPTO_CB_FIND + if (src->devId != INVALID_DEVID) + #endif + { + ret = wc_CryptoCb_Copy(src->devId, WC_ALGO_TYPE_HASH, + WC_HASH_TYPE_SHA384, (void*)src, (void*)dst); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) + return ret; + /* fall-through when the callback is unavailable */ + } + ret = 0; /* discard CRYPTOCB_UNAVAILABLE before the plain struct copy */ +#endif /* WOLF_CRYPTO_CB && WOLF_CRYPTO_CB_COPY */ + + wc_Sha384Free(dst); + XMEMCPY(dst, src, sizeof(wc_Sha384)); + +#ifdef WOLFSSL_HASH_FLAGS + dst->flags |= WC_HASH_FLAG_ISCOPY; +#endif + + return ret; +} + +#ifdef WOLFSSL_HASH_FLAGS +int wc_Sha384SetFlags(wc_Sha384* sha384, word32 flags) +{ + if (sha384) + sha384->flags = flags; + return 0; +} +int wc_Sha384GetFlags(wc_Sha384* sha384, word32* flags) +{ + if (sha384 && flags) + *flags = sha384->flags; + return 0; +} +#endif /* WOLFSSL_HASH_FLAGS */ + +#endif /* WOLFSSL_SHA384 */ #else #ifdef WOLFSSL_SHA512 @@ -1393,6 +1976,7 @@ int wc_Sha512Update(wc_Sha512* sha512, const byte* data, word32 len) #endif /* WOLFSSL_IMX6_CAAM || WOLFSSL_SILABS_SHA512 */ +#ifndef WOLF_CRYPTO_CB_ONLY_SHA512 #if defined(WOLFSSL_KCAPI_HASH) /* functions defined in wolfcrypt/src/port/kcapi/kcapi_hash.c */ @@ -2857,4 +3441,6 @@ int wc_Sha384_Grow(wc_Sha384* sha384, const byte* in, int inSz) } #endif /* WOLFSSL_SHA384 */ #endif /* WOLFSSL_HASH_KEEP */ + +#endif /* !WOLF_CRYPTO_CB_ONLY_SHA512 */ #endif /* WOLFSSL_SHA512 || WOLFSSL_SHA384 */ diff --git a/wolfcrypt/src/signature.c b/wolfcrypt/src/signature.c index 74753f07d4..a45bdd0d92 100644 --- a/wolfcrypt/src/signature.c +++ b/wolfcrypt/src/signature.c @@ -46,8 +46,10 @@ #ifndef MAX_DER_DIGEST_ASN_SZ #define MAX_DER_DIGEST_ASN_SZ 36 #endif - #ifndef MAX_ENCODED_SIG_SZ - #define MAX_ENCODED_SIG_SZ 1024 /* Supports 8192 bit keys */ + /* Fallback when asn.h (which defines MAX_ENCODED_CLASSIC_SIG_SZ) is not + * available. Sized to hold an RSA-modulus signature. */ + #ifndef MAX_ENCODED_CLASSIC_SIG_SZ + #define MAX_ENCODED_CLASSIC_SIG_SZ 1024 /* Supports 8192 bit keys */ #endif #endif @@ -289,7 +291,7 @@ int wc_SignatureVerifyHash( #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) byte *plain_data; #else - ALIGN64 byte plain_data[MAX_ENCODED_SIG_SZ]; + ALIGN64 byte plain_data[MAX_ENCODED_CLASSIC_SIG_SZ]; #endif /* Make sure the plain text output is at least key size */ diff --git a/wolfcrypt/src/sp_arm32.c b/wolfcrypt/src/sp_arm32.c index dd10cc64ad..39ce504cd0 100644 --- a/wolfcrypt/src/sp_arm32.c +++ b/wolfcrypt/src/sp_arm32.c @@ -62697,13 +62697,10 @@ static const sp_point_256 p256_base = { /* infinity */ 0 }; -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) || \ - defined(HAVE_COMP_KEY) static const sp_digit p256_b[8] = { 0x27d2604b,0x3bce3c3e,0xcc53b0f6,0x651d06b0,0x769886bc,0xb3ebbd55, 0xaa3a93e7,0x5ac635d8 }; -#endif #ifdef WOLFSSL_SP_SMALL /* Multiply a and b into r. (r = a * b) @@ -75775,9 +75772,9 @@ static THREAD_LS_T int sp_cache_256_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_256_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_256 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_256 = 0; #endif static wolfSSL_Mutex sp_cache_256_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_256_lock); #endif @@ -75844,6 +75841,7 @@ static void sp_ecc_get_cache_256(const sp_point_256* g, sp_cache_256_t** cache) } #endif /* FP_ECC */ + /* Multiply the base point of P256 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -75866,19 +75864,42 @@ static int sp_256_ecc_mulmod_8(sp_point_256* r, const sp_point_256* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 8 * 6, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_256 == 0) { - wc_InitMutex(&sp_cache_256_lock); - initCacheMutex_256 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_256) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_256, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_256_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_256, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_256_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_256_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_256(g, &cache); @@ -75892,9 +75913,9 @@ static int sp_256_ecc_mulmod_8(sp_point_256* r, const sp_point_256* g, err = sp_256_ecc_mulmod_stripe_8(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_256_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -76156,9 +76177,9 @@ static THREAD_LS_T int sp_cache_256_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_256_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_256 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_256 = 0; #endif static wolfSSL_Mutex sp_cache_256_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_256_lock); #endif @@ -76225,6 +76246,7 @@ static void sp_ecc_get_cache_256(const sp_point_256* g, sp_cache_256_t** cache) } #endif /* FP_ECC */ + /* Multiply the base point of P256 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -76247,19 +76269,42 @@ static int sp_256_ecc_mulmod_8(sp_point_256* r, const sp_point_256* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 8 * 6, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_256 == 0) { - wc_InitMutex(&sp_cache_256_lock); - initCacheMutex_256 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_256) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_256, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_256_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_256, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_256_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_256_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_256(g, &cache); @@ -76273,9 +76318,9 @@ static int sp_256_ecc_mulmod_8(sp_point_256* r, const sp_point_256* g, err = sp_256_ecc_mulmod_stripe_8(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_256_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -80782,7 +80827,6 @@ int sp_ecc_verify_256_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, #endif /* WOLFSSL_SP_NONBLOCK */ #endif /* HAVE_ECC_VERIFY */ -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the x and y ordinates are a valid point on the curve. * * point EC point. @@ -80855,6 +80899,7 @@ int sp_ecc_is_point_256(const mp_int* pX, const mp_int* pY) return err; } +#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the private scalar generates the EC point (px, py), the point is * on the curve and the point has the correct order. * @@ -81282,13 +81327,10 @@ static const sp_point_384 p384_base = { /* infinity */ 0 }; -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) || \ - defined(HAVE_COMP_KEY) static const sp_digit p384_b[12] = { 0xd3ec2aef,0x2a85c8ed,0x8a2ed19d,0xc656398d,0x5013875a,0x0314088f, 0xfe814112,0x181d9c6e,0xe3f82d19,0x988e056b,0xe23ee7e4,0xb3312fa7 }; -#endif #ifdef WOLFSSL_SP_SMALL /* Multiply a and b into r. (r = a * b) @@ -93808,9 +93850,9 @@ static THREAD_LS_T int sp_cache_384_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_384_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_384 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_384 = 0; #endif static wolfSSL_Mutex sp_cache_384_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_384_lock); #endif @@ -93877,6 +93919,7 @@ static void sp_ecc_get_cache_384(const sp_point_384* g, sp_cache_384_t** cache) } #endif /* FP_ECC */ + /* Multiply the base point of P384 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -93899,19 +93942,42 @@ static int sp_384_ecc_mulmod_12(sp_point_384* r, const sp_point_384* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 12 * 7, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_384 == 0) { - wc_InitMutex(&sp_cache_384_lock); - initCacheMutex_384 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_384) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_384, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_384_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_384, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_384_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_384_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_384(g, &cache); @@ -93925,9 +93991,9 @@ static int sp_384_ecc_mulmod_12(sp_point_384* r, const sp_point_384* g, err = sp_384_ecc_mulmod_stripe_12(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_384_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -94205,9 +94271,9 @@ static THREAD_LS_T int sp_cache_384_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_384_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_384 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_384 = 0; #endif static wolfSSL_Mutex sp_cache_384_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_384_lock); #endif @@ -94274,6 +94340,7 @@ static void sp_ecc_get_cache_384(const sp_point_384* g, sp_cache_384_t** cache) } #endif /* FP_ECC */ + /* Multiply the base point of P384 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -94296,19 +94363,42 @@ static int sp_384_ecc_mulmod_12(sp_point_384* r, const sp_point_384* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 12 * 7, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_384 == 0) { - wc_InitMutex(&sp_cache_384_lock); - initCacheMutex_384 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_384) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_384, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_384_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_384, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_384_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_384_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_384(g, &cache); @@ -94322,9 +94412,9 @@ static int sp_384_ecc_mulmod_12(sp_point_384* r, const sp_point_384* g, err = sp_384_ecc_mulmod_stripe_12(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_384_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -99065,7 +99155,6 @@ int sp_ecc_verify_384_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, #endif /* WOLFSSL_SP_NONBLOCK */ #endif /* HAVE_ECC_VERIFY */ -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the x and y ordinates are a valid point on the curve. * * point EC point. @@ -99138,6 +99227,7 @@ int sp_ecc_is_point_384(const mp_int* pX, const mp_int* pY) return err; } +#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the private scalar generates the EC point (px, py), the point is * on the curve and the point has the correct order. * @@ -99607,14 +99697,11 @@ static const sp_point_521 p521_base = { /* infinity */ 0 }; -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) || \ - defined(HAVE_COMP_KEY) static const sp_digit p521_b[17] = { 0x6b503f00,0xef451fd4,0x3d2c34f1,0x3573df88,0x3bb1bf07,0x1652c0bd, 0xec7e937b,0x56193951,0x8ef109e1,0xb8b48991,0x99b315f3,0xa2da725b, 0xb68540ee,0x929a21a0,0x8e1c9a1f,0x953eb961,0x00000051 }; -#endif #ifdef WOLFSSL_SP_SMALL /* Multiply a and b into r. (r = a * b) @@ -120967,9 +121054,9 @@ static THREAD_LS_T int sp_cache_521_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_521_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_521 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_521 = 0; #endif static wolfSSL_Mutex sp_cache_521_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_521_lock); #endif @@ -121036,6 +121123,7 @@ static void sp_ecc_get_cache_521(const sp_point_521* g, sp_cache_521_t** cache) } #endif /* FP_ECC */ + /* Multiply the base point of P521 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -121058,19 +121146,42 @@ static int sp_521_ecc_mulmod_17(sp_point_521* r, const sp_point_521* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 17 * 6, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_521 == 0) { - wc_InitMutex(&sp_cache_521_lock); - initCacheMutex_521 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_521) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_521, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_521_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_521, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_521_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_521_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_521(g, &cache); @@ -121084,9 +121195,9 @@ static int sp_521_ecc_mulmod_17(sp_point_521* r, const sp_point_521* g, err = sp_521_ecc_mulmod_stripe_17(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_521_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -121384,9 +121495,9 @@ static THREAD_LS_T int sp_cache_521_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_521_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_521 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_521 = 0; #endif static wolfSSL_Mutex sp_cache_521_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_521_lock); #endif @@ -121453,6 +121564,7 @@ static void sp_ecc_get_cache_521(const sp_point_521* g, sp_cache_521_t** cache) } #endif /* FP_ECC */ + /* Multiply the base point of P521 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -121475,19 +121587,42 @@ static int sp_521_ecc_mulmod_17(sp_point_521* r, const sp_point_521* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 17 * 6, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_521 == 0) { - wc_InitMutex(&sp_cache_521_lock); - initCacheMutex_521 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_521) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_521, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_521_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_521, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_521_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_521_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_521(g, &cache); @@ -121501,9 +121636,9 @@ static int sp_521_ecc_mulmod_17(sp_point_521* r, const sp_point_521* g, err = sp_521_ecc_mulmod_stripe_17(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_521_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -128007,7 +128142,6 @@ int sp_ecc_verify_521_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, #endif /* WOLFSSL_SP_NONBLOCK */ #endif /* HAVE_ECC_VERIFY */ -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the x and y ordinates are a valid point on the curve. * * point EC point. @@ -128080,6 +128214,7 @@ int sp_ecc_is_point_521(const mp_int* pX, const mp_int* pY) return err; } +#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the private scalar generates the EC point (px, py), the point is * on the curve and the point has the correct order. * @@ -150732,9 +150867,9 @@ static THREAD_LS_T int sp_cache_1024_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_1024_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_1024 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_1024 = 0; #endif static wolfSSL_Mutex sp_cache_1024_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_1024_lock); #endif @@ -150801,6 +150936,7 @@ static void sp_ecc_get_cache_1024(const sp_point_1024* g, sp_cache_1024_t** cach } #endif /* FP_ECC */ + /* Multiply the base point of P1024 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -150823,19 +150959,42 @@ static int sp_1024_ecc_mulmod_32(sp_point_1024* r, const sp_point_1024* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 32 * 38, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_1024 == 0) { - wc_InitMutex(&sp_cache_1024_lock); - initCacheMutex_1024 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_1024) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_1024, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_1024_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_1024, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_1024_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_1024_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_1024(g, &cache); @@ -150849,9 +151008,9 @@ static int sp_1024_ecc_mulmod_32(sp_point_1024* r, const sp_point_1024* g, err = sp_1024_ecc_mulmod_stripe_32(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_1024_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -151046,9 +151205,9 @@ static THREAD_LS_T int sp_cache_1024_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_1024_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_1024 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_1024 = 0; #endif static wolfSSL_Mutex sp_cache_1024_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_1024_lock); #endif @@ -151115,6 +151274,7 @@ static void sp_ecc_get_cache_1024(const sp_point_1024* g, sp_cache_1024_t** cach } #endif /* FP_ECC */ + /* Multiply the base point of P1024 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -151137,19 +151297,42 @@ static int sp_1024_ecc_mulmod_32(sp_point_1024* r, const sp_point_1024* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 32 * 38, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_1024 == 0) { - wc_InitMutex(&sp_cache_1024_lock); - initCacheMutex_1024 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_1024) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_1024, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_1024_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_1024, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_1024_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_1024_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_1024(g, &cache); @@ -151163,9 +151346,9 @@ static int sp_1024_ecc_mulmod_32(sp_point_1024* r, const sp_point_1024* g, err = sp_1024_ecc_mulmod_stripe_32(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_1024_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -158404,7 +158587,6 @@ int sp_Pairing_precomp_1024(const ecc_point* pm, const ecc_point* qm, } #endif /* WOLFSSL_SP_SMALL */ -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Read big endian unsigned byte array into r. * * r A single precision integer. @@ -158528,6 +158710,7 @@ int sp_ecc_is_point_1024(const mp_int* pX, const mp_int* pY) return err; } +#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the private scalar generates the EC point (px, py), the point is * on the curve and the point has the correct order. * diff --git a/wolfcrypt/src/sp_arm64.c b/wolfcrypt/src/sp_arm64.c index 59751ebe0c..08d041a857 100644 --- a/wolfcrypt/src/sp_arm64.c +++ b/wolfcrypt/src/sp_arm64.c @@ -21506,13 +21506,10 @@ static const sp_point_256 p256_base = { 0 }; #endif /* WOLFSSL_SP_SMALL */ -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) || \ - defined(HAVE_COMP_KEY) static const sp_digit p256_b[4] = { 0x3bce3c3e27d2604bL,0x651d06b0cc53b0f6L,0xb3ebbd55769886bcL, 0x5ac635d8aa3a93e7L }; -#endif #ifdef WOLFSSL_SP_SMALL /* Multiply a and b into r. (r = a * b) @@ -24586,9 +24583,9 @@ static THREAD_LS_T int sp_cache_256_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_256_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_256 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_256 = 0; #endif static wolfSSL_Mutex sp_cache_256_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_256_lock); #endif @@ -24655,6 +24652,7 @@ static void sp_ecc_get_cache_256(const sp_point_256* g, sp_cache_256_t** cache) } #endif /* FP_ECC */ + /* Multiply the base point of P256 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -24677,19 +24675,42 @@ static int sp_256_ecc_mulmod_4(sp_point_256* r, const sp_point_256* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 4 * 5, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_256 == 0) { - wc_InitMutex(&sp_cache_256_lock); - initCacheMutex_256 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_256) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_256, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_256_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_256, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_256_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_256_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_256(g, &cache); @@ -24703,9 +24724,9 @@ static int sp_256_ecc_mulmod_4(sp_point_256* r, const sp_point_256* g, err = sp_256_ecc_mulmod_stripe_4(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_256_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -24974,9 +24995,9 @@ static THREAD_LS_T int sp_cache_256_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_256_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_256 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_256 = 0; #endif static wolfSSL_Mutex sp_cache_256_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_256_lock); #endif @@ -25043,6 +25064,7 @@ static void sp_ecc_get_cache_256(const sp_point_256* g, sp_cache_256_t** cache) } #endif /* FP_ECC */ + /* Multiply the base point of P256 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -25065,19 +25087,42 @@ static int sp_256_ecc_mulmod_4(sp_point_256* r, const sp_point_256* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 4 * 5, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_256 == 0) { - wc_InitMutex(&sp_cache_256_lock); - initCacheMutex_256 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_256) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_256, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_256_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_256, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_256_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_256_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_256(g, &cache); @@ -25091,9 +25136,9 @@ static int sp_256_ecc_mulmod_4(sp_point_256* r, const sp_point_256* g, err = sp_256_ecc_mulmod_stripe_4(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_256_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -41481,7 +41526,6 @@ int sp_ecc_verify_256_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, #endif /* WOLFSSL_SP_NONBLOCK */ #endif /* HAVE_ECC_VERIFY */ -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Add two Montgomery form numbers (r = a + b % m). * * r Result of addition. @@ -41598,6 +41642,7 @@ int sp_ecc_is_point_256(const mp_int* pX, const mp_int* pY) return err; } +#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the private scalar generates the EC point (px, py), the point is * on the curve and the point has the correct order. * @@ -42024,13 +42069,10 @@ static const sp_point_384 p384_base = { 0 }; #endif /* WOLFSSL_SP_SMALL */ -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) || \ - defined(HAVE_COMP_KEY) static const sp_digit p384_b[6] = { 0x2a85c8edd3ec2aefL,0xc656398d8a2ed19dL,0x0314088f5013875aL, 0x181d9c6efe814112L,0x988e056be3f82d19L,0xb3312fa7e23ee7e4L }; -#endif #ifdef WOLFSSL_SP_SMALL /* Multiply a and b into r. (r = a * b) @@ -45088,9 +45130,9 @@ static THREAD_LS_T int sp_cache_384_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_384_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_384 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_384 = 0; #endif static wolfSSL_Mutex sp_cache_384_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_384_lock); #endif @@ -45157,6 +45199,7 @@ static void sp_ecc_get_cache_384(const sp_point_384* g, sp_cache_384_t** cache) } #endif /* FP_ECC */ + /* Multiply the base point of P384 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -45179,19 +45222,42 @@ static int sp_384_ecc_mulmod_6(sp_point_384* r, const sp_point_384* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 6 * 7, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_384 == 0) { - wc_InitMutex(&sp_cache_384_lock); - initCacheMutex_384 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_384) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_384, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_384_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_384, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_384_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_384_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_384(g, &cache); @@ -45205,9 +45271,9 @@ static int sp_384_ecc_mulmod_6(sp_point_384* r, const sp_point_384* g, err = sp_384_ecc_mulmod_stripe_6(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_384_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -45476,9 +45542,9 @@ static THREAD_LS_T int sp_cache_384_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_384_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_384 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_384 = 0; #endif static wolfSSL_Mutex sp_cache_384_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_384_lock); #endif @@ -45545,6 +45611,7 @@ static void sp_ecc_get_cache_384(const sp_point_384* g, sp_cache_384_t** cache) } #endif /* FP_ECC */ + /* Multiply the base point of P384 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -45567,19 +45634,42 @@ static int sp_384_ecc_mulmod_6(sp_point_384* r, const sp_point_384* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 6 * 7, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_384 == 0) { - wc_InitMutex(&sp_cache_384_lock); - initCacheMutex_384 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_384) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_384, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_384_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_384, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_384_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_384_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_384(g, &cache); @@ -45593,9 +45683,9 @@ static int sp_384_ecc_mulmod_6(sp_point_384* r, const sp_point_384* g, err = sp_384_ecc_mulmod_stripe_6(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_384_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -67158,7 +67248,6 @@ int sp_ecc_verify_384_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, #endif /* WOLFSSL_SP_NONBLOCK */ #endif /* HAVE_ECC_VERIFY */ -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the x and y ordinates are a valid point on the curve. * * point EC point. @@ -67231,6 +67320,7 @@ int sp_ecc_is_point_384(const mp_int* pX, const mp_int* pY) return err; } +#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the private scalar generates the EC point (px, py), the point is * on the curve and the point has the correct order. * @@ -67696,14 +67786,11 @@ static const sp_point_521 p521_base = { 0 }; #endif /* WOLFSSL_SP_SMALL */ -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) || \ - defined(HAVE_COMP_KEY) static const sp_digit p521_b[9] = { 0xef451fd46b503f00L,0x3573df883d2c34f1L,0x1652c0bd3bb1bf07L, 0x56193951ec7e937bL,0xb8b489918ef109e1L,0xa2da725b99b315f3L, 0x929a21a0b68540eeL,0x953eb9618e1c9a1fL,0x0000000000000051L }; -#endif #ifdef WOLFSSL_SP_SMALL /* Multiply a and b into r. (r = a * b) @@ -73076,9 +73163,9 @@ static THREAD_LS_T int sp_cache_521_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_521_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_521 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_521 = 0; #endif static wolfSSL_Mutex sp_cache_521_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_521_lock); #endif @@ -73145,6 +73232,7 @@ static void sp_ecc_get_cache_521(const sp_point_521* g, sp_cache_521_t** cache) } #endif /* FP_ECC */ + /* Multiply the base point of P521 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -73167,19 +73255,42 @@ static int sp_521_ecc_mulmod_9(sp_point_521* r, const sp_point_521* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 9 * 6, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_521 == 0) { - wc_InitMutex(&sp_cache_521_lock); - initCacheMutex_521 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_521) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_521, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_521_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_521, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_521_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_521_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_521(g, &cache); @@ -73193,9 +73304,9 @@ static int sp_521_ecc_mulmod_9(sp_point_521* r, const sp_point_521* g, err = sp_521_ecc_mulmod_stripe_9(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_521_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -73482,9 +73593,9 @@ static THREAD_LS_T int sp_cache_521_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_521_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_521 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_521 = 0; #endif static wolfSSL_Mutex sp_cache_521_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_521_lock); #endif @@ -73551,6 +73662,7 @@ static void sp_ecc_get_cache_521(const sp_point_521* g, sp_cache_521_t** cache) } #endif /* FP_ECC */ + /* Multiply the base point of P521 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -73573,19 +73685,42 @@ static int sp_521_ecc_mulmod_9(sp_point_521* r, const sp_point_521* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 9 * 6, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_521 == 0) { - wc_InitMutex(&sp_cache_521_lock); - initCacheMutex_521 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_521) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_521, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_521_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_521, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_521_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_521_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_521(g, &cache); @@ -73599,9 +73734,9 @@ static int sp_521_ecc_mulmod_9(sp_point_521* r, const sp_point_521* g, err = sp_521_ecc_mulmod_stripe_9(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_521_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -111666,7 +111801,6 @@ int sp_ecc_verify_521_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, #endif /* WOLFSSL_SP_NONBLOCK */ #endif /* HAVE_ECC_VERIFY */ -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the x and y ordinates are a valid point on the curve. * * point EC point. @@ -111739,6 +111873,7 @@ int sp_ecc_is_point_521(const mp_int* pX, const mp_int* pY) return err; } +#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the private scalar generates the EC point (px, py), the point is * on the curve and the point has the correct order. * @@ -116561,9 +116696,9 @@ static THREAD_LS_T int sp_cache_1024_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_1024_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_1024 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_1024 = 0; #endif static wolfSSL_Mutex sp_cache_1024_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_1024_lock); #endif @@ -116630,6 +116765,7 @@ static void sp_ecc_get_cache_1024(const sp_point_1024* g, sp_cache_1024_t** cach } #endif /* FP_ECC */ + /* Multiply the base point of P1024 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -116652,19 +116788,42 @@ static int sp_1024_ecc_mulmod_16(sp_point_1024* r, const sp_point_1024* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 16 * 38, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_1024 == 0) { - wc_InitMutex(&sp_cache_1024_lock); - initCacheMutex_1024 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_1024) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_1024, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_1024_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_1024, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_1024_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_1024_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_1024(g, &cache); @@ -116678,9 +116837,9 @@ static int sp_1024_ecc_mulmod_16(sp_point_1024* r, const sp_point_1024* g, err = sp_1024_ecc_mulmod_stripe_16(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_1024_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -123425,7 +123584,6 @@ int sp_Pairing_precomp_1024(const ecc_point* pm, const ecc_point* qm, } #endif /* WOLFSSL_SP_SMALL */ -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Read big endian unsigned byte array into r. * * r A single precision integer. @@ -123615,6 +123773,7 @@ int sp_ecc_is_point_1024(const mp_int* pX, const mp_int* pY) return err; } +#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the private scalar generates the EC point (px, py), the point is * on the curve and the point has the correct order. * diff --git a/wolfcrypt/src/sp_armthumb.c b/wolfcrypt/src/sp_armthumb.c index f56e1d9091..dd4ac7d60a 100644 --- a/wolfcrypt/src/sp_armthumb.c +++ b/wolfcrypt/src/sp_armthumb.c @@ -96590,13 +96590,10 @@ static const sp_point_256 p256_base = { /* infinity */ 0 }; -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) || \ - defined(HAVE_COMP_KEY) static const sp_digit p256_b[8] = { 0x27d2604b,0x3bce3c3e,0xcc53b0f6,0x651d06b0,0x769886bc,0xb3ebbd55, 0xaa3a93e7,0x5ac635d8 }; -#endif /* Multiply a and b into r. (r = a * b) * @@ -101395,9 +101392,9 @@ static THREAD_LS_T int sp_cache_256_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_256_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_256 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_256 = 0; #endif static wolfSSL_Mutex sp_cache_256_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_256_lock); #endif @@ -101464,6 +101461,7 @@ static void sp_ecc_get_cache_256(const sp_point_256* g, sp_cache_256_t** cache) } #endif /* FP_ECC */ + /* Multiply the base point of P256 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -101486,19 +101484,42 @@ static int sp_256_ecc_mulmod_8(sp_point_256* r, const sp_point_256* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 8 * 6, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_256 == 0) { - wc_InitMutex(&sp_cache_256_lock); - initCacheMutex_256 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_256) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_256, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_256_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_256, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_256_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_256_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_256(g, &cache); @@ -101512,9 +101533,9 @@ static int sp_256_ecc_mulmod_8(sp_point_256* r, const sp_point_256* g, err = sp_256_ecc_mulmod_stripe_8(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_256_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -101776,9 +101797,9 @@ static THREAD_LS_T int sp_cache_256_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_256_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_256 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_256 = 0; #endif static wolfSSL_Mutex sp_cache_256_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_256_lock); #endif @@ -101845,6 +101866,7 @@ static void sp_ecc_get_cache_256(const sp_point_256* g, sp_cache_256_t** cache) } #endif /* FP_ECC */ + /* Multiply the base point of P256 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -101867,19 +101889,42 @@ static int sp_256_ecc_mulmod_8(sp_point_256* r, const sp_point_256* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 8 * 6, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_256 == 0) { - wc_InitMutex(&sp_cache_256_lock); - initCacheMutex_256 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_256) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_256, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_256_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_256, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_256_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_256_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_256(g, &cache); @@ -101893,9 +101938,9 @@ static int sp_256_ecc_mulmod_8(sp_point_256* r, const sp_point_256* g, err = sp_256_ecc_mulmod_stripe_8(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_256_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -107292,7 +107337,6 @@ int sp_ecc_verify_256_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, #endif /* WOLFSSL_SP_NONBLOCK */ #endif /* HAVE_ECC_VERIFY */ -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the x and y ordinates are a valid point on the curve. * * point EC point. @@ -107365,6 +107409,7 @@ int sp_ecc_is_point_256(const mp_int* pX, const mp_int* pY) return err; } +#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the private scalar generates the EC point (px, py), the point is * on the curve and the point has the correct order. * @@ -107792,13 +107837,10 @@ static const sp_point_384 p384_base = { /* infinity */ 0 }; -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) || \ - defined(HAVE_COMP_KEY) static const sp_digit p384_b[12] = { 0xd3ec2aef,0x2a85c8ed,0x8a2ed19d,0xc656398d,0x5013875a,0x0314088f, 0xfe814112,0x181d9c6e,0xe3f82d19,0x988e056b,0xe23ee7e4,0xb3312fa7 }; -#endif /* Multiply a and b into r. (r = a * b) * @@ -111863,9 +111905,9 @@ static THREAD_LS_T int sp_cache_384_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_384_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_384 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_384 = 0; #endif static wolfSSL_Mutex sp_cache_384_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_384_lock); #endif @@ -111932,6 +111974,7 @@ static void sp_ecc_get_cache_384(const sp_point_384* g, sp_cache_384_t** cache) } #endif /* FP_ECC */ + /* Multiply the base point of P384 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -111954,19 +111997,42 @@ static int sp_384_ecc_mulmod_12(sp_point_384* r, const sp_point_384* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 12 * 7, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_384 == 0) { - wc_InitMutex(&sp_cache_384_lock); - initCacheMutex_384 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_384) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_384, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_384_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_384, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_384_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_384_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_384(g, &cache); @@ -111980,9 +112046,9 @@ static int sp_384_ecc_mulmod_12(sp_point_384* r, const sp_point_384* g, err = sp_384_ecc_mulmod_stripe_12(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_384_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -112260,9 +112326,9 @@ static THREAD_LS_T int sp_cache_384_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_384_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_384 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_384 = 0; #endif static wolfSSL_Mutex sp_cache_384_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_384_lock); #endif @@ -112329,6 +112395,7 @@ static void sp_ecc_get_cache_384(const sp_point_384* g, sp_cache_384_t** cache) } #endif /* FP_ECC */ + /* Multiply the base point of P384 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -112351,19 +112418,42 @@ static int sp_384_ecc_mulmod_12(sp_point_384* r, const sp_point_384* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 12 * 7, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_384 == 0) { - wc_InitMutex(&sp_cache_384_lock); - initCacheMutex_384 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_384) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_384, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_384_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_384, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_384_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_384_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_384(g, &cache); @@ -112377,9 +112467,9 @@ static int sp_384_ecc_mulmod_12(sp_point_384* r, const sp_point_384* g, err = sp_384_ecc_mulmod_stripe_12(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_384_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -118083,7 +118173,6 @@ int sp_ecc_verify_384_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, #endif /* WOLFSSL_SP_NONBLOCK */ #endif /* HAVE_ECC_VERIFY */ -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the x and y ordinates are a valid point on the curve. * * point EC point. @@ -118156,6 +118245,7 @@ int sp_ecc_is_point_384(const mp_int* pX, const mp_int* pY) return err; } +#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the private scalar generates the EC point (px, py), the point is * on the curve and the point has the correct order. * @@ -118625,14 +118715,11 @@ static const sp_point_521 p521_base = { /* infinity */ 0 }; -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) || \ - defined(HAVE_COMP_KEY) static const sp_digit p521_b[17] = { 0x6b503f00,0xef451fd4,0x3d2c34f1,0x3573df88,0x3bb1bf07,0x1652c0bd, 0xec7e937b,0x56193951,0x8ef109e1,0xb8b48991,0x99b315f3,0xa2da725b, 0xb68540ee,0x929a21a0,0x8e1c9a1f,0x953eb961,0x00000051 }; -#endif /* Multiply a and b into r. (r = a * b) * @@ -125126,9 +125213,9 @@ static THREAD_LS_T int sp_cache_521_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_521_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_521 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_521 = 0; #endif static wolfSSL_Mutex sp_cache_521_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_521_lock); #endif @@ -125195,6 +125282,7 @@ static void sp_ecc_get_cache_521(const sp_point_521* g, sp_cache_521_t** cache) } #endif /* FP_ECC */ + /* Multiply the base point of P521 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -125217,19 +125305,42 @@ static int sp_521_ecc_mulmod_17(sp_point_521* r, const sp_point_521* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 17 * 6, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_521 == 0) { - wc_InitMutex(&sp_cache_521_lock); - initCacheMutex_521 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_521) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_521, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_521_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_521, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_521_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_521_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_521(g, &cache); @@ -125243,9 +125354,9 @@ static int sp_521_ecc_mulmod_17(sp_point_521* r, const sp_point_521* g, err = sp_521_ecc_mulmod_stripe_17(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_521_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -125543,9 +125654,9 @@ static THREAD_LS_T int sp_cache_521_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_521_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_521 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_521 = 0; #endif static wolfSSL_Mutex sp_cache_521_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_521_lock); #endif @@ -125612,6 +125723,7 @@ static void sp_ecc_get_cache_521(const sp_point_521* g, sp_cache_521_t** cache) } #endif /* FP_ECC */ + /* Multiply the base point of P521 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -125634,19 +125746,42 @@ static int sp_521_ecc_mulmod_17(sp_point_521* r, const sp_point_521* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 17 * 6, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_521 == 0) { - wc_InitMutex(&sp_cache_521_lock); - initCacheMutex_521 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_521) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_521, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_521_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_521, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_521_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_521_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_521(g, &cache); @@ -125660,9 +125795,9 @@ static int sp_521_ecc_mulmod_17(sp_point_521* r, const sp_point_521* g, err = sp_521_ecc_mulmod_stripe_17(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_521_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -134651,7 +134786,6 @@ int sp_ecc_verify_521_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, #endif /* WOLFSSL_SP_NONBLOCK */ #endif /* HAVE_ECC_VERIFY */ -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the x and y ordinates are a valid point on the curve. * * point EC point. @@ -134724,6 +134858,7 @@ int sp_ecc_is_point_521(const mp_int* pX, const mp_int* pY) return err; } +#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the private scalar generates the EC point (px, py), the point is * on the curve and the point has the correct order. * @@ -209386,9 +209521,9 @@ static THREAD_LS_T int sp_cache_1024_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_1024_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_1024 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_1024 = 0; #endif static wolfSSL_Mutex sp_cache_1024_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_1024_lock); #endif @@ -209455,6 +209590,7 @@ static void sp_ecc_get_cache_1024(const sp_point_1024* g, sp_cache_1024_t** cach } #endif /* FP_ECC */ + /* Multiply the base point of P1024 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -209477,19 +209613,42 @@ static int sp_1024_ecc_mulmod_32(sp_point_1024* r, const sp_point_1024* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 32 * 38, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_1024 == 0) { - wc_InitMutex(&sp_cache_1024_lock); - initCacheMutex_1024 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_1024) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_1024, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_1024_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_1024, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_1024_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_1024_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_1024(g, &cache); @@ -209503,9 +209662,9 @@ static int sp_1024_ecc_mulmod_32(sp_point_1024* r, const sp_point_1024* g, err = sp_1024_ecc_mulmod_stripe_32(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_1024_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -209700,9 +209859,9 @@ static THREAD_LS_T int sp_cache_1024_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_1024_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_1024 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_1024 = 0; #endif static wolfSSL_Mutex sp_cache_1024_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_1024_lock); #endif @@ -209769,6 +209928,7 @@ static void sp_ecc_get_cache_1024(const sp_point_1024* g, sp_cache_1024_t** cach } #endif /* FP_ECC */ + /* Multiply the base point of P1024 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -209791,19 +209951,42 @@ static int sp_1024_ecc_mulmod_32(sp_point_1024* r, const sp_point_1024* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 32 * 38, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_1024 == 0) { - wc_InitMutex(&sp_cache_1024_lock); - initCacheMutex_1024 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_1024) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_1024, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_1024_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_1024, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_1024_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_1024_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_1024(g, &cache); @@ -209817,9 +210000,9 @@ static int sp_1024_ecc_mulmod_32(sp_point_1024* r, const sp_point_1024* g, err = sp_1024_ecc_mulmod_stripe_32(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_1024_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -217058,7 +217241,6 @@ int sp_Pairing_precomp_1024(const ecc_point* pm, const ecc_point* qm, } #endif /* WOLFSSL_SP_SMALL */ -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Read big endian unsigned byte array into r. * * r A single precision integer. @@ -217182,6 +217364,7 @@ int sp_ecc_is_point_1024(const mp_int* pX, const mp_int* pY) return err; } +#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the private scalar generates the EC point (px, py), the point is * on the curve and the point has the correct order. * diff --git a/wolfcrypt/src/sp_c32.c b/wolfcrypt/src/sp_c32.c index 8262fb2f73..87e4e93554 100644 --- a/wolfcrypt/src/sp_c32.c +++ b/wolfcrypt/src/sp_c32.c @@ -20367,13 +20367,10 @@ static const sp_point_256 p256_base = { /* infinity */ 0 }; -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) || \ - defined(HAVE_COMP_KEY) static const sp_digit p256_b[9] = { 0x07d2604b,0x1e71e1f1,0x14ec3d8e,0x1a0d6198,0x086bc651,0x1eaabb4c, 0x0f9ecfae,0x1b154752,0x005ac635 }; -#endif #ifdef WOLFSSL_SP_SMALL /* Multiply a and b into r. (r = a * b) @@ -23319,9 +23316,9 @@ static THREAD_LS_T int sp_cache_256_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_256_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_256 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_256 = 0; #endif static wolfSSL_Mutex sp_cache_256_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_256_lock); #endif @@ -23388,6 +23385,7 @@ static void sp_ecc_get_cache_256(const sp_point_256* g, sp_cache_256_t** cache) } #endif /* FP_ECC */ + /* Multiply the base point of P256 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -23410,19 +23408,42 @@ static int sp_256_ecc_mulmod_9(sp_point_256* r, const sp_point_256* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 9 * 6, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_256 == 0) { - wc_InitMutex(&sp_cache_256_lock); - initCacheMutex_256 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_256) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_256, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_256_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_256, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_256_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_256_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_256(g, &cache); @@ -23436,9 +23457,9 @@ static int sp_256_ecc_mulmod_9(sp_point_256* r, const sp_point_256* g, err = sp_256_ecc_mulmod_stripe_9(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_256_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -26531,7 +26552,6 @@ int sp_ecc_verify_256_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, #endif /* WOLFSSL_SP_NONBLOCK */ #endif /* HAVE_ECC_VERIFY */ -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the x and y ordinates are a valid point on the curve. * * point EC point. @@ -26604,6 +26624,7 @@ int sp_ecc_is_point_256(const mp_int* pX, const mp_int* pY) return err; } +#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the private scalar generates the EC point (px, py), the point is * on the curve and the point has the correct order. * @@ -27039,14 +27060,11 @@ static const sp_point_384 p384_base = { /* infinity */ 0 }; -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) || \ - defined(HAVE_COMP_KEY) static const sp_digit p384_b[15] = { 0x3ec2aef,0x1723b74,0x119d2a8,0x23628bb,0x2c65639,0x004e1d6,0x14088f5, 0x104480c,0x06efe81,0x2460767,0x23f82d1,0x23815af,0x2e7e498,0x3e9f88f, 0x00b3312 }; -#endif #ifdef WOLFSSL_SP_SMALL /* Multiply a and b into r. (r = a * b) @@ -30437,9 +30455,9 @@ static THREAD_LS_T int sp_cache_384_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_384_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_384 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_384 = 0; #endif static wolfSSL_Mutex sp_cache_384_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_384_lock); #endif @@ -30506,6 +30524,7 @@ static void sp_ecc_get_cache_384(const sp_point_384* g, sp_cache_384_t** cache) } #endif /* FP_ECC */ + /* Multiply the base point of P384 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -30528,19 +30547,42 @@ static int sp_384_ecc_mulmod_15(sp_point_384* r, const sp_point_384* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 15 * 7, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_384 == 0) { - wc_InitMutex(&sp_cache_384_lock); - initCacheMutex_384 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_384) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_384, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_384_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_384, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_384_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_384_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_384(g, &cache); @@ -30554,9 +30596,9 @@ static int sp_384_ecc_mulmod_15(sp_point_384* r, const sp_point_384* g, err = sp_384_ecc_mulmod_stripe_15(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_384_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -34176,7 +34218,6 @@ int sp_ecc_verify_384_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, #endif /* WOLFSSL_SP_NONBLOCK */ #endif /* HAVE_ECC_VERIFY */ -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the x and y ordinates are a valid point on the curve. * * point EC point. @@ -34249,6 +34290,7 @@ int sp_ecc_is_point_384(const mp_int* pX, const mp_int* pY) return err; } +#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the private scalar generates the EC point (px, py), the point is * on the curve and the point has the correct order. * @@ -34721,14 +34763,11 @@ static const sp_point_521 p521_base = { /* infinity */ 0 }; -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) || \ - defined(HAVE_COMP_KEY) static const sp_digit p521_b[21] = { 0x1503f00,0x08fea35,0x13c7bd1,0x107a586,0x1573df8,0x18df839,0x102f4ee, 0x0f62ca5,0x1ec7e93,0x10c9ca8,0x0427855,0x13231de,0x13b8b48,0x0cd98af, 0x169c96e,0x081dd45,0x1a0b685,0x1c94d10,0x1872687,0x1d72c31,0x0051953 }; -#endif #ifdef WOLFSSL_SP_SMALL /* Multiply a and b into r. (r = a * b) @@ -37617,9 +37656,9 @@ static THREAD_LS_T int sp_cache_521_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_521_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_521 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_521 = 0; #endif static wolfSSL_Mutex sp_cache_521_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_521_lock); #endif @@ -37686,6 +37725,7 @@ static void sp_ecc_get_cache_521(const sp_point_521* g, sp_cache_521_t** cache) } #endif /* FP_ECC */ + /* Multiply the base point of P521 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -37708,19 +37748,42 @@ static int sp_521_ecc_mulmod_21(sp_point_521* r, const sp_point_521* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 21 * 6, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_521 == 0) { - wc_InitMutex(&sp_cache_521_lock); - initCacheMutex_521 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_521) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_521, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_521_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_521, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_521_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_521_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_521(g, &cache); @@ -37734,9 +37797,9 @@ static int sp_521_ecc_mulmod_21(sp_point_521* r, const sp_point_521* g, err = sp_521_ecc_mulmod_stripe_21(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_521_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -41927,7 +41990,6 @@ int sp_ecc_verify_521_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, #endif /* WOLFSSL_SP_NONBLOCK */ #endif /* HAVE_ECC_VERIFY */ -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the x and y ordinates are a valid point on the curve. * * point EC point. @@ -42000,6 +42062,7 @@ int sp_ecc_is_point_521(const mp_int* pX, const mp_int* pY) return err; } +#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the private scalar generates the EC point (px, py), the point is * on the curve and the point has the correct order. * @@ -45757,9 +45820,9 @@ static THREAD_LS_T int sp_cache_1024_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_1024_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_1024 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_1024 = 0; #endif static wolfSSL_Mutex sp_cache_1024_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_1024_lock); #endif @@ -45826,6 +45889,7 @@ static void sp_ecc_get_cache_1024(const sp_point_1024* g, sp_cache_1024_t** cach } #endif /* FP_ECC */ + /* Multiply the base point of P1024 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -45848,19 +45912,42 @@ static int sp_1024_ecc_mulmod_42(sp_point_1024* r, const sp_point_1024* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 42 * 38, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_1024 == 0) { - wc_InitMutex(&sp_cache_1024_lock); - initCacheMutex_1024 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_1024) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_1024, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_1024_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_1024, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_1024_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_1024_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_1024(g, &cache); @@ -45874,9 +45961,9 @@ static int sp_1024_ecc_mulmod_42(sp_point_1024* r, const sp_point_1024* g, err = sp_1024_ecc_mulmod_stripe_42(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_1024_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -53422,7 +53509,6 @@ int sp_Pairing_precomp_1024(const ecc_point* pm, const ecc_point* qm, } #endif /* WOLFSSL_SP_SMALL */ -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Read big endian unsigned byte array into r. * * r A single precision integer. @@ -53534,6 +53620,7 @@ int sp_ecc_is_point_1024(const mp_int* pX, const mp_int* pY) return err; } +#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the private scalar generates the EC point (px, py), the point is * on the curve and the point has the correct order. * diff --git a/wolfcrypt/src/sp_c64.c b/wolfcrypt/src/sp_c64.c index b0dd93cbd9..64c64144b6 100644 --- a/wolfcrypt/src/sp_c64.c +++ b/wolfcrypt/src/sp_c64.c @@ -21245,13 +21245,10 @@ static const sp_point_256 p256_base = { /* infinity */ 0 }; -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) || \ - defined(HAVE_COMP_KEY) static const sp_digit p256_b[5] = { 0xe3c3e27d2604bL,0xb0cc53b0f63bcL,0x69886bc651d06L,0x93e7b3ebbd557L, 0x05ac635d8aa3aL }; -#endif #ifdef WOLFSSL_SP_SMALL /* Multiply a and b into r. (r = a * b) @@ -23947,9 +23944,9 @@ static THREAD_LS_T int sp_cache_256_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_256_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_256 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_256 = 0; #endif static wolfSSL_Mutex sp_cache_256_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_256_lock); #endif @@ -24016,6 +24013,7 @@ static void sp_ecc_get_cache_256(const sp_point_256* g, sp_cache_256_t** cache) } #endif /* FP_ECC */ + /* Multiply the base point of P256 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -24038,19 +24036,42 @@ static int sp_256_ecc_mulmod_5(sp_point_256* r, const sp_point_256* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 5 * 6, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_256 == 0) { - wc_InitMutex(&sp_cache_256_lock); - initCacheMutex_256 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_256) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_256, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_256_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_256, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_256_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_256_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_256(g, &cache); @@ -24064,9 +24085,9 @@ static int sp_256_ecc_mulmod_5(sp_point_256* r, const sp_point_256* g, err = sp_256_ecc_mulmod_stripe_5(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_256_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -27146,7 +27167,6 @@ int sp_ecc_verify_256_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, #endif /* WOLFSSL_SP_NONBLOCK */ #endif /* HAVE_ECC_VERIFY */ -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the x and y ordinates are a valid point on the curve. * * point EC point. @@ -27219,6 +27239,7 @@ int sp_ecc_is_point_256(const mp_int* pX, const mp_int* pY) return err; } +#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the private scalar generates the EC point (px, py), the point is * on the curve and the point has the correct order. * @@ -27643,13 +27664,10 @@ static const sp_point_384 p384_base = { /* infinity */ 0 }; -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) || \ - defined(HAVE_COMP_KEY) static const sp_digit p384_b[7] = { 0x05c8edd3ec2aefL,0x731b145da33a55L,0x3d404e1d6b1958L,0x740a089018a044L, 0x02d19181d9c6efL,0x7c9311c0ad7c7fL,0x2ccc4be9f88fb9L }; -#endif #ifdef WOLFSSL_SP_SMALL /* Multiply a and b into r. (r = a * b) @@ -30492,9 +30510,9 @@ static THREAD_LS_T int sp_cache_384_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_384_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_384 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_384 = 0; #endif static wolfSSL_Mutex sp_cache_384_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_384_lock); #endif @@ -30561,6 +30579,7 @@ static void sp_ecc_get_cache_384(const sp_point_384* g, sp_cache_384_t** cache) } #endif /* FP_ECC */ + /* Multiply the base point of P384 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -30583,19 +30602,42 @@ static int sp_384_ecc_mulmod_7(sp_point_384* r, const sp_point_384* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 7 * 7, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_384 == 0) { - wc_InitMutex(&sp_cache_384_lock); - initCacheMutex_384 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_384) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_384, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_384_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_384, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_384_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_384_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_384(g, &cache); @@ -30609,9 +30651,9 @@ static int sp_384_ecc_mulmod_7(sp_point_384* r, const sp_point_384* g, err = sp_384_ecc_mulmod_stripe_7(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_384_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -34178,7 +34220,6 @@ int sp_ecc_verify_384_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, #endif /* WOLFSSL_SP_NONBLOCK */ #endif /* HAVE_ECC_VERIFY */ -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the x and y ordinates are a valid point on the curve. * * point EC point. @@ -34251,6 +34292,7 @@ int sp_ecc_is_point_384(const mp_int* pX, const mp_int* pY) return err; } +#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the private scalar generates the EC point (px, py), the point is * on the curve and the point has the correct order. * @@ -34714,14 +34756,11 @@ static const sp_point_521 p521_base = { /* infinity */ 0 }; -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) || \ - defined(HAVE_COMP_KEY) static const sp_digit p521_b[9] = { 0x3451fd46b503f00L,0x0f7e20f4b0d3c7bL,0x00bd3bb1bf07357L,0x147b1fa4dec594bL, 0x18ef109e1561939L,0x26cc57cee2d2264L,0x0540eea2da725b9L,0x2687e4a688682daL, 0x051953eb9618e1cL }; -#endif #ifdef WOLFSSL_SP_SMALL /* Multiply a and b into r. (r = a * b) @@ -37510,9 +37549,9 @@ static THREAD_LS_T int sp_cache_521_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_521_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_521 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_521 = 0; #endif static wolfSSL_Mutex sp_cache_521_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_521_lock); #endif @@ -37579,6 +37618,7 @@ static void sp_ecc_get_cache_521(const sp_point_521* g, sp_cache_521_t** cache) } #endif /* FP_ECC */ + /* Multiply the base point of P521 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -37601,19 +37641,42 @@ static int sp_521_ecc_mulmod_9(sp_point_521* r, const sp_point_521* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 9 * 6, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_521 == 0) { - wc_InitMutex(&sp_cache_521_lock); - initCacheMutex_521 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_521) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_521, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_521_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_521, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_521_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_521_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_521(g, &cache); @@ -37627,9 +37690,9 @@ static int sp_521_ecc_mulmod_9(sp_point_521* r, const sp_point_521* g, err = sp_521_ecc_mulmod_stripe_9(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_521_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -41239,7 +41302,6 @@ int sp_ecc_verify_521_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, #endif /* WOLFSSL_SP_NONBLOCK */ #endif /* HAVE_ECC_VERIFY */ -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the x and y ordinates are a valid point on the curve. * * point EC point. @@ -41312,6 +41374,7 @@ int sp_ecc_is_point_521(const mp_int* pX, const mp_int* pY) return err; } +#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the private scalar generates the EC point (px, py), the point is * on the curve and the point has the correct order. * @@ -44832,9 +44895,9 @@ static THREAD_LS_T int sp_cache_1024_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_1024_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_1024 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_1024 = 0; #endif static wolfSSL_Mutex sp_cache_1024_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_1024_lock); #endif @@ -44901,6 +44964,7 @@ static void sp_ecc_get_cache_1024(const sp_point_1024* g, sp_cache_1024_t** cach } #endif /* FP_ECC */ + /* Multiply the base point of P1024 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -44923,19 +44987,42 @@ static int sp_1024_ecc_mulmod_18(sp_point_1024* r, const sp_point_1024* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 18 * 38, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_1024 == 0) { - wc_InitMutex(&sp_cache_1024_lock); - initCacheMutex_1024 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_1024) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_1024, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_1024_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_1024, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_1024_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_1024_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_1024(g, &cache); @@ -44949,9 +45036,9 @@ static int sp_1024_ecc_mulmod_18(sp_point_1024* r, const sp_point_1024* g, err = sp_1024_ecc_mulmod_stripe_18(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_1024_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -51727,7 +51814,6 @@ int sp_Pairing_precomp_1024(const ecc_point* pm, const ecc_point* qm, } #endif /* WOLFSSL_SP_SMALL */ -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Read big endian unsigned byte array into r. * * r A single precision integer. @@ -51839,6 +51925,7 @@ int sp_ecc_is_point_1024(const mp_int* pX, const mp_int* pY) return err; } +#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the private scalar generates the EC point (px, py), the point is * on the curve and the point has the correct order. * diff --git a/wolfcrypt/src/sp_cortexm.c b/wolfcrypt/src/sp_cortexm.c index f9d22092d9..29641a9d70 100644 --- a/wolfcrypt/src/sp_cortexm.c +++ b/wolfcrypt/src/sp_cortexm.c @@ -32083,13 +32083,10 @@ static const sp_point_256 p256_base = { /* infinity */ 0 }; -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) || \ - defined(HAVE_COMP_KEY) static const sp_digit p256_b[8] = { 0x27d2604b,0x3bce3c3e,0xcc53b0f6,0x651d06b0,0x769886bc,0xb3ebbd55, 0xaa3a93e7,0x5ac635d8 }; -#endif #ifdef WOLFSSL_SP_SMALL /* Multiply a and b into r. (r = a * b) @@ -37881,9 +37878,9 @@ static THREAD_LS_T int sp_cache_256_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_256_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_256 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_256 = 0; #endif static wolfSSL_Mutex sp_cache_256_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_256_lock); #endif @@ -37950,6 +37947,7 @@ static void sp_ecc_get_cache_256(const sp_point_256* g, sp_cache_256_t** cache) } #endif /* FP_ECC */ + /* Multiply the base point of P256 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -37972,19 +37970,42 @@ static int sp_256_ecc_mulmod_8(sp_point_256* r, const sp_point_256* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 8 * 6, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_256 == 0) { - wc_InitMutex(&sp_cache_256_lock); - initCacheMutex_256 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_256) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_256, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_256_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_256, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_256_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_256_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_256(g, &cache); @@ -37998,9 +38019,9 @@ static int sp_256_ecc_mulmod_8(sp_point_256* r, const sp_point_256* g, err = sp_256_ecc_mulmod_stripe_8(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_256_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -38262,9 +38283,9 @@ static THREAD_LS_T int sp_cache_256_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_256_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_256 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_256 = 0; #endif static wolfSSL_Mutex sp_cache_256_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_256_lock); #endif @@ -38331,6 +38352,7 @@ static void sp_ecc_get_cache_256(const sp_point_256* g, sp_cache_256_t** cache) } #endif /* FP_ECC */ + /* Multiply the base point of P256 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -38353,19 +38375,42 @@ static int sp_256_ecc_mulmod_8(sp_point_256* r, const sp_point_256* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 8 * 6, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_256 == 0) { - wc_InitMutex(&sp_cache_256_lock); - initCacheMutex_256 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_256) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_256, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_256_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_256, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_256_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_256_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_256(g, &cache); @@ -38379,9 +38424,9 @@ static int sp_256_ecc_mulmod_8(sp_point_256* r, const sp_point_256* g, err = sp_256_ecc_mulmod_stripe_8(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_256_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -42288,7 +42333,6 @@ int sp_ecc_verify_256_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, #endif /* WOLFSSL_SP_NONBLOCK */ #endif /* HAVE_ECC_VERIFY */ -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the x and y ordinates are a valid point on the curve. * * point EC point. @@ -42361,6 +42405,7 @@ int sp_ecc_is_point_256(const mp_int* pX, const mp_int* pY) return err; } +#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the private scalar generates the EC point (px, py), the point is * on the curve and the point has the correct order. * @@ -42788,13 +42833,10 @@ static const sp_point_384 p384_base = { /* infinity */ 0 }; -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) || \ - defined(HAVE_COMP_KEY) static const sp_digit p384_b[12] = { 0xd3ec2aef,0x2a85c8ed,0x8a2ed19d,0xc656398d,0x5013875a,0x0314088f, 0xfe814112,0x181d9c6e,0xe3f82d19,0x988e056b,0xe23ee7e4,0xb3312fa7 }; -#endif #ifdef WOLFSSL_SP_SMALL /* Multiply a and b into r. (r = a * b) @@ -47989,9 +48031,9 @@ static THREAD_LS_T int sp_cache_384_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_384_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_384 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_384 = 0; #endif static wolfSSL_Mutex sp_cache_384_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_384_lock); #endif @@ -48058,6 +48100,7 @@ static void sp_ecc_get_cache_384(const sp_point_384* g, sp_cache_384_t** cache) } #endif /* FP_ECC */ + /* Multiply the base point of P384 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -48080,19 +48123,42 @@ static int sp_384_ecc_mulmod_12(sp_point_384* r, const sp_point_384* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 12 * 7, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_384 == 0) { - wc_InitMutex(&sp_cache_384_lock); - initCacheMutex_384 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_384) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_384, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_384_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_384, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_384_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_384_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_384(g, &cache); @@ -48106,9 +48172,9 @@ static int sp_384_ecc_mulmod_12(sp_point_384* r, const sp_point_384* g, err = sp_384_ecc_mulmod_stripe_12(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_384_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -48386,9 +48452,9 @@ static THREAD_LS_T int sp_cache_384_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_384_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_384 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_384 = 0; #endif static wolfSSL_Mutex sp_cache_384_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_384_lock); #endif @@ -48455,6 +48521,7 @@ static void sp_ecc_get_cache_384(const sp_point_384* g, sp_cache_384_t** cache) } #endif /* FP_ECC */ + /* Multiply the base point of P384 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -48477,19 +48544,42 @@ static int sp_384_ecc_mulmod_12(sp_point_384* r, const sp_point_384* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 12 * 7, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_384 == 0) { - wc_InitMutex(&sp_cache_384_lock); - initCacheMutex_384 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_384) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_384, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_384_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_384, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_384_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_384_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_384(g, &cache); @@ -48503,9 +48593,9 @@ static int sp_384_ecc_mulmod_12(sp_point_384* r, const sp_point_384* g, err = sp_384_ecc_mulmod_stripe_12(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_384_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -52395,7 +52485,6 @@ int sp_ecc_verify_384_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, #endif /* WOLFSSL_SP_NONBLOCK */ #endif /* HAVE_ECC_VERIFY */ -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the x and y ordinates are a valid point on the curve. * * point EC point. @@ -52468,6 +52557,7 @@ int sp_ecc_is_point_384(const mp_int* pX, const mp_int* pY) return err; } +#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the private scalar generates the EC point (px, py), the point is * on the curve and the point has the correct order. * @@ -52937,14 +53027,11 @@ static const sp_point_521 p521_base = { /* infinity */ 0 }; -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) || \ - defined(HAVE_COMP_KEY) static const sp_digit p521_b[17] = { 0x6b503f00,0xef451fd4,0x3d2c34f1,0x3573df88,0x3bb1bf07,0x1652c0bd, 0xec7e937b,0x56193951,0x8ef109e1,0xb8b48991,0x99b315f3,0xa2da725b, 0xb68540ee,0x929a21a0,0x8e1c9a1f,0x953eb961,0x00000051 }; -#endif #ifdef WOLFSSL_SP_SMALL /* Multiply a and b into r. (r = a * b) @@ -59986,9 +60073,9 @@ static THREAD_LS_T int sp_cache_521_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_521_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_521 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_521 = 0; #endif static wolfSSL_Mutex sp_cache_521_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_521_lock); #endif @@ -60055,6 +60142,7 @@ static void sp_ecc_get_cache_521(const sp_point_521* g, sp_cache_521_t** cache) } #endif /* FP_ECC */ + /* Multiply the base point of P521 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -60077,19 +60165,42 @@ static int sp_521_ecc_mulmod_17(sp_point_521* r, const sp_point_521* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 17 * 6, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_521 == 0) { - wc_InitMutex(&sp_cache_521_lock); - initCacheMutex_521 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_521) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_521, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_521_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_521, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_521_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_521_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_521(g, &cache); @@ -60103,9 +60214,9 @@ static int sp_521_ecc_mulmod_17(sp_point_521* r, const sp_point_521* g, err = sp_521_ecc_mulmod_stripe_17(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_521_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -60403,9 +60514,9 @@ static THREAD_LS_T int sp_cache_521_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_521_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_521 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_521 = 0; #endif static wolfSSL_Mutex sp_cache_521_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_521_lock); #endif @@ -60472,6 +60583,7 @@ static void sp_ecc_get_cache_521(const sp_point_521* g, sp_cache_521_t** cache) } #endif /* FP_ECC */ + /* Multiply the base point of P521 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -60494,19 +60606,42 @@ static int sp_521_ecc_mulmod_17(sp_point_521* r, const sp_point_521* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 17 * 6, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_521 == 0) { - wc_InitMutex(&sp_cache_521_lock); - initCacheMutex_521 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_521) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_521, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_521_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_521, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_521_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_521_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_521(g, &cache); @@ -60520,9 +60655,9 @@ static int sp_521_ecc_mulmod_17(sp_point_521* r, const sp_point_521* g, err = sp_521_ecc_mulmod_stripe_17(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_521_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -65811,7 +65946,6 @@ int sp_ecc_verify_521_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, #endif /* WOLFSSL_SP_NONBLOCK */ #endif /* HAVE_ECC_VERIFY */ -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the x and y ordinates are a valid point on the curve. * * point EC point. @@ -65884,6 +66018,7 @@ int sp_ecc_is_point_521(const mp_int* pX, const mp_int* pY) return err; } +#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the private scalar generates the EC point (px, py), the point is * on the curve and the point has the correct order. * @@ -74469,9 +74604,9 @@ static THREAD_LS_T int sp_cache_1024_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_1024_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_1024 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_1024 = 0; #endif static wolfSSL_Mutex sp_cache_1024_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_1024_lock); #endif @@ -74538,6 +74673,7 @@ static void sp_ecc_get_cache_1024(const sp_point_1024* g, sp_cache_1024_t** cach } #endif /* FP_ECC */ + /* Multiply the base point of P1024 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -74560,19 +74696,42 @@ static int sp_1024_ecc_mulmod_32(sp_point_1024* r, const sp_point_1024* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 32 * 38, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_1024 == 0) { - wc_InitMutex(&sp_cache_1024_lock); - initCacheMutex_1024 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_1024) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_1024, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_1024_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_1024, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_1024_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_1024_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_1024(g, &cache); @@ -74586,9 +74745,9 @@ static int sp_1024_ecc_mulmod_32(sp_point_1024* r, const sp_point_1024* g, err = sp_1024_ecc_mulmod_stripe_32(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_1024_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -74783,9 +74942,9 @@ static THREAD_LS_T int sp_cache_1024_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_1024_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_1024 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_1024 = 0; #endif static wolfSSL_Mutex sp_cache_1024_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_1024_lock); #endif @@ -74852,6 +75011,7 @@ static void sp_ecc_get_cache_1024(const sp_point_1024* g, sp_cache_1024_t** cach } #endif /* FP_ECC */ + /* Multiply the base point of P1024 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -74874,19 +75034,42 @@ static int sp_1024_ecc_mulmod_32(sp_point_1024* r, const sp_point_1024* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 32 * 38, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_1024 == 0) { - wc_InitMutex(&sp_cache_1024_lock); - initCacheMutex_1024 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_1024) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_1024, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_1024_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_1024, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_1024_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_1024_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_1024(g, &cache); @@ -74900,9 +75083,9 @@ static int sp_1024_ecc_mulmod_32(sp_point_1024* r, const sp_point_1024* g, err = sp_1024_ecc_mulmod_stripe_32(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_1024_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -82141,7 +82324,6 @@ int sp_Pairing_precomp_1024(const ecc_point* pm, const ecc_point* qm, } #endif /* WOLFSSL_SP_SMALL */ -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Read big endian unsigned byte array into r. * * r A single precision integer. @@ -82265,6 +82447,7 @@ int sp_ecc_is_point_1024(const mp_int* pX, const mp_int* pY) return err; } +#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the private scalar generates the EC point (px, py), the point is * on the curve and the point has the correct order. * diff --git a/wolfcrypt/src/sp_int.c b/wolfcrypt/src/sp_int.c index ff5a33e2e6..53f464282a 100644 --- a/wolfcrypt/src/sp_int.c +++ b/wolfcrypt/src/sp_int.c @@ -7423,7 +7423,8 @@ static void _sp_div_2(const sp_int* a, sp_int* r) /* Last word only needs to be shifted down. */ r->dp[i] = a->dp[i] >> 1; /* Set used to be all words seen. */ - r->used = (sp_size_t)(i + 1 - (int)((r->dp[i] - 1) >> (SP_WORD_SIZE - 1))); + r->used = (sp_size_t)(i + 1 - (int)((sp_int_digit)(r->dp[i] - 1) >> + (SP_WORD_SIZE - 1))); #ifdef WOLFSSL_SP_INT_NEGATIVE /* Same sign in result. */ r->sign = a->sign; diff --git a/wolfcrypt/src/sp_x86_64.c b/wolfcrypt/src/sp_x86_64.c index 7ce9b9ab6a..a984ce6a86 100644 --- a/wolfcrypt/src/sp_x86_64.c +++ b/wolfcrypt/src/sp_x86_64.c @@ -7585,13 +7585,10 @@ static const sp_point_256 p256_base = { 0 }; #endif /* WOLFSSL_SP_SMALL */ -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) || \ - defined(HAVE_COMP_KEY) static const sp_digit p256_b[4] = { 0x3bce3c3e27d2604bL,0x651d06b0cc53b0f6L,0xb3ebbd55769886bcL, 0x5ac635d8aa3a93e7L }; -#endif #ifdef __cplusplus extern "C" { @@ -10441,9 +10438,9 @@ static THREAD_LS_T int sp_cache_256_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_256_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_256 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_256 = 0; #endif static wolfSSL_Mutex sp_cache_256_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_256_lock); #endif @@ -10510,6 +10507,7 @@ static void sp_ecc_get_cache_256(const sp_point_256* g, sp_cache_256_t** cache) } #endif /* FP_ECC */ + /* Multiply the base point of P256 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -10532,19 +10530,42 @@ static int sp_256_ecc_mulmod_4(sp_point_256* r, const sp_point_256* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 4 * 5, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_256 == 0) { - wc_InitMutex(&sp_cache_256_lock); - initCacheMutex_256 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_256) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_256, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_256_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_256, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_256_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_256_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_256(g, &cache); @@ -10558,9 +10579,9 @@ static int sp_256_ecc_mulmod_4(sp_point_256* r, const sp_point_256* g, err = sp_256_ecc_mulmod_stripe_4(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_256_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -10848,6 +10869,7 @@ static int sp_256_ecc_mulmod_stripe_avx2_4(sp_point_256* r, const sp_point_256* } #endif /* FP_ECC | WOLFSSL_SP_SMALL */ + /* Multiply the base point of P256 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -10870,19 +10892,42 @@ static int sp_256_ecc_mulmod_avx2_4(sp_point_256* r, const sp_point_256* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 4 * 5, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_256 == 0) { - wc_InitMutex(&sp_cache_256_lock); - initCacheMutex_256 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_256) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_256, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_256_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_256, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_256_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_256_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_256(g, &cache); @@ -10896,9 +10941,9 @@ static int sp_256_ecc_mulmod_avx2_4(sp_point_256* r, const sp_point_256* g, err = sp_256_ecc_mulmod_stripe_avx2_4(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_256_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -25637,7 +25682,6 @@ int sp_ecc_verify_256_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, #endif /* WOLFSSL_SP_NONBLOCK */ #endif /* HAVE_ECC_VERIFY */ -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the x and y ordinates are a valid point on the curve. * * point EC point. @@ -25710,6 +25754,7 @@ int sp_ecc_is_point_256(const mp_int* pX, const mp_int* pY) return err; } +#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the private scalar generates the EC point (px, py), the point is * on the curve and the point has the correct order. * @@ -26240,13 +26285,10 @@ static const sp_point_384 p384_base = { 0 }; #endif /* WOLFSSL_SP_SMALL */ -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) || \ - defined(HAVE_COMP_KEY) static const sp_digit p384_b[6] = { 0x2a85c8edd3ec2aefL,0xc656398d8a2ed19dL,0x0314088f5013875aL, 0x181d9c6efe814112L,0x988e056be3f82d19L,0xb3312fa7e23ee7e4L }; -#endif #ifdef __cplusplus extern "C" { @@ -29217,9 +29259,9 @@ static THREAD_LS_T int sp_cache_384_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_384_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_384 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_384 = 0; #endif static wolfSSL_Mutex sp_cache_384_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_384_lock); #endif @@ -29286,6 +29328,7 @@ static void sp_ecc_get_cache_384(const sp_point_384* g, sp_cache_384_t** cache) } #endif /* FP_ECC */ + /* Multiply the base point of P384 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -29308,19 +29351,42 @@ static int sp_384_ecc_mulmod_6(sp_point_384* r, const sp_point_384* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 6 * 7, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_384 == 0) { - wc_InitMutex(&sp_cache_384_lock); - initCacheMutex_384 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_384) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_384, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_384_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_384, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_384_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_384_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_384(g, &cache); @@ -29334,9 +29400,9 @@ static int sp_384_ecc_mulmod_6(sp_point_384* r, const sp_point_384* g, err = sp_384_ecc_mulmod_stripe_6(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_384_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -29627,6 +29693,7 @@ static int sp_384_ecc_mulmod_stripe_avx2_6(sp_point_384* r, const sp_point_384* } #endif /* FP_ECC | WOLFSSL_SP_SMALL */ + /* Multiply the base point of P384 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -29649,19 +29716,42 @@ static int sp_384_ecc_mulmod_avx2_6(sp_point_384* r, const sp_point_384* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 6 * 7, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_384 == 0) { - wc_InitMutex(&sp_cache_384_lock); - initCacheMutex_384 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_384) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_384, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_384_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_384, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_384_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_384_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_384(g, &cache); @@ -29675,9 +29765,9 @@ static int sp_384_ecc_mulmod_avx2_6(sp_point_384* r, const sp_point_384* g, err = sp_384_ecc_mulmod_stripe_avx2_6(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_384_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -50181,7 +50271,6 @@ int sp_ecc_verify_384_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, #endif /* WOLFSSL_SP_NONBLOCK */ #endif /* HAVE_ECC_VERIFY */ -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the x and y ordinates are a valid point on the curve. * * point EC point. @@ -50254,6 +50343,7 @@ int sp_ecc_is_point_384(const mp_int* pX, const mp_int* pY) return err; } +#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the private scalar generates the EC point (px, py), the point is * on the curve and the point has the correct order. * @@ -50848,14 +50938,11 @@ static const sp_point_521 p521_base = { 0 }; #endif /* WOLFSSL_SP_SMALL */ -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) || \ - defined(HAVE_COMP_KEY) static const sp_digit p521_b[9] = { 0xef451fd46b503f00L,0x3573df883d2c34f1L,0x1652c0bd3bb1bf07L, 0x56193951ec7e937bL,0xb8b489918ef109e1L,0xa2da725b99b315f3L, 0x929a21a0b68540eeL,0x953eb9618e1c9a1fL,0x0000000000000051L }; -#endif #ifdef __cplusplus extern "C" { @@ -53703,9 +53790,9 @@ static THREAD_LS_T int sp_cache_521_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_521_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_521 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_521 = 0; #endif static wolfSSL_Mutex sp_cache_521_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_521_lock); #endif @@ -53772,6 +53859,7 @@ static void sp_ecc_get_cache_521(const sp_point_521* g, sp_cache_521_t** cache) } #endif /* FP_ECC */ + /* Multiply the base point of P521 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -53794,19 +53882,42 @@ static int sp_521_ecc_mulmod_9(sp_point_521* r, const sp_point_521* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 9 * 6, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_521 == 0) { - wc_InitMutex(&sp_cache_521_lock); - initCacheMutex_521 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_521) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_521, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_521_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_521, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_521_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_521_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_521(g, &cache); @@ -53820,9 +53931,9 @@ static int sp_521_ecc_mulmod_9(sp_point_521* r, const sp_point_521* g, err = sp_521_ecc_mulmod_stripe_9(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_521_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -54113,6 +54224,7 @@ static int sp_521_ecc_mulmod_stripe_avx2_9(sp_point_521* r, const sp_point_521* } #endif /* FP_ECC | WOLFSSL_SP_SMALL */ + /* Multiply the base point of P521 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -54135,19 +54247,42 @@ static int sp_521_ecc_mulmod_avx2_9(sp_point_521* r, const sp_point_521* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 9 * 6, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_521 == 0) { - wc_InitMutex(&sp_cache_521_lock); - initCacheMutex_521 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_521) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_521, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_521_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_521, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_521_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_521_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_521(g, &cache); @@ -54161,9 +54296,9 @@ static int sp_521_ecc_mulmod_avx2_9(sp_point_521* r, const sp_point_521* g, err = sp_521_ecc_mulmod_stripe_avx2_9(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_521_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -90927,7 +91062,6 @@ int sp_ecc_verify_521_nb(sp_ecc_ctx_t* sp_ctx, const byte* hash, #endif /* WOLFSSL_SP_NONBLOCK */ #endif /* HAVE_ECC_VERIFY */ -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the x and y ordinates are a valid point on the curve. * * point EC point. @@ -91000,6 +91134,7 @@ int sp_ecc_is_point_521(const mp_int* pX, const mp_int* pY) return err; } +#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the private scalar generates the EC point (px, py), the point is * on the curve and the point has the correct order. * @@ -94505,9 +94640,9 @@ static THREAD_LS_T int sp_cache_1024_last = -1; /* Cache has been initialized. */ static THREAD_LS_T int sp_cache_1024_inited = 0; -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) #ifndef WOLFSSL_MUTEX_INITIALIZER - static volatile int initCacheMutex_1024 = 0; + static wolfSSL_Atomic_Uint initCacheMutex_1024 = 0; #endif static wolfSSL_Mutex sp_cache_1024_lock WOLFSSL_MUTEX_INITIALIZER_CLAUSE(sp_cache_1024_lock); #endif @@ -94574,6 +94709,7 @@ static void sp_ecc_get_cache_1024(const sp_point_1024* g, sp_cache_1024_t** cach } #endif /* FP_ECC */ + /* Multiply the base point of P1024 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -94596,19 +94732,42 @@ static int sp_1024_ecc_mulmod_16(sp_point_1024* r, const sp_point_1024* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 16 * 38, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_1024 == 0) { - wc_InitMutex(&sp_cache_1024_lock); - initCacheMutex_1024 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_1024) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_1024, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_1024_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_1024, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_1024_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_1024_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_1024(g, &cache); @@ -94622,9 +94781,9 @@ static int sp_1024_ecc_mulmod_16(sp_point_1024* r, const sp_point_1024* g, err = sp_1024_ecc_mulmod_stripe_16(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_1024_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -94898,6 +95057,7 @@ static int sp_1024_ecc_mulmod_stripe_avx2_16(sp_point_1024* r, const sp_point_10 return err; } + /* Multiply the base point of P1024 by the scalar and return the result. * If map is true then convert result to affine coordinates. * @@ -94920,19 +95080,42 @@ static int sp_1024_ecc_mulmod_avx2_16(sp_point_1024* r, const sp_point_1024* g, int err = MP_OKAY; SP_ALLOC_VAR(sp_digit, tmp, 2 * 16 * 38, heap, DYNAMIC_TYPE_ECC); -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) if (err == MP_OKAY) { - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (initCacheMutex_1024 == 0) { - wc_InitMutex(&sp_cache_1024_lock); - initCacheMutex_1024 = 1; + #ifndef WOLFSSL_MUTEX_INITIALIZER + /* Lazy initialization of mutex - one atomic with three states: + * 0 = uninitialized, 1 = initialization in progress, + * 2 = initialized. + */ + if (WOLFSSL_ATOMIC_LOAD(initCacheMutex_1024) != 2) { + unsigned int expected_then_actual; + + for (;;) { + expected_then_actual = 0; + if (wolfSSL_Atomic_Uint_CompareExchange( + &initCacheMutex_1024, &expected_then_actual, + 1) == 1) { + /* Won race - initialize mutex. On failure, reset state + * to 0 so that a later call retries. */ + err = wc_InitMutex(&sp_cache_1024_lock); + WOLFSSL_ATOMIC_STORE(initCacheMutex_1024, + (err == 0) ? 2U : 0U); + break; + } + if (expected_then_actual == 2) { + /* Another thread completed initialization. */ + break; + } + /* Initialization in progress in another thread. */ + WC_RELAX_LONG_LOOP(); + } } - #endif - if (wc_LockMutex(&sp_cache_1024_lock) != 0) { + #endif + if ((err == MP_OKAY) && (wc_LockMutex(&sp_cache_1024_lock) != 0)) { err = BAD_MUTEX_E; } } -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ if (err == MP_OKAY) { sp_ecc_get_cache_1024(g, &cache); @@ -94946,9 +95129,9 @@ static int sp_1024_ecc_mulmod_avx2_16(sp_point_1024* r, const sp_point_1024* g, err = sp_1024_ecc_mulmod_stripe_avx2_16(r, g, cache->table, k, map, ct, heap); } -#ifndef HAVE_THREAD_LS +#if !defined(SINGLE_THREADED) && !defined(HAVE_THREAD_LS) wc_UnLockMutex(&sp_cache_1024_lock); -#endif /* HAVE_THREAD_LS */ +#endif /* !SINGLE_THREADED && !HAVE_THREAD_LS */ } SP_FREE_VAR(tmp, heap, DYNAMIC_TYPE_ECC); @@ -103475,7 +103658,6 @@ int sp_Pairing_precomp_1024(const ecc_point* pm, const ecc_point* qm, mp_int* re return err; } -#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) #ifdef __cplusplus extern "C" { #endif @@ -103588,6 +103770,7 @@ int sp_ecc_is_point_1024(const mp_int* pX, const mp_int* pY) return err; } +#if defined(HAVE_ECC_CHECK_KEY) || !defined(NO_ECC_CHECK_PUBKEY_ORDER) /* Check that the private scalar generates the EC point (px, py), the point is * on the curve and the point has the correct order. * diff --git a/wolfcrypt/src/wc_mldsa.c b/wolfcrypt/src/wc_mldsa.c index dca96173a6..73b7a9b118 100644 --- a/wolfcrypt/src/wc_mldsa.c +++ b/wolfcrypt/src/wc_mldsa.c @@ -7927,6 +7927,12 @@ static int mldsa_make_key_from_seed(wc_MlDsaKey* key, const byte* seed) } #ifndef WC_MLDSA_CACHE_PRIV_VECTORS + /* Zeroize the private vectors s1, s2 and t before freeing. These occupy + * the front of the buffer; any matrix A that follows is public (expanded + * from the public seed) and need not be cleared. */ + if (s1 != NULL) { + ForceZero(s1, (word32)params->s1Sz + 2U * (word32)params->s2Sz); + } XFREE(s1, key->heap, DYNAMIC_TYPE_MLDSA); #endif return ret; @@ -7945,6 +7951,7 @@ static int mldsa_make_key_from_seed(wc_MlDsaKey* key, const byte* seed) unsigned int r; unsigned int s; byte kl[2]; + unsigned int allocSz = 0; #ifdef WOLFSSL_MLDSA_DYNAMIC_KEYS ret = mldsa_alloc_priv_buf(key); @@ -7959,8 +7966,6 @@ static int mldsa_make_key_from_seed(wc_MlDsaKey* key, const byte* seed) /* Allocate memory for large intermediates. */ if (ret == 0) { - unsigned int allocSz; - /* s1-l, s2-k, t-k, a-1 */ allocSz = (unsigned int)params->s1Sz + params->s2Sz + params->s2Sz + (unsigned int)MLDSA_REJ_NTT_POLY_H_SIZE + @@ -8158,6 +8163,15 @@ static int mldsa_make_key_from_seed(wc_MlDsaKey* key, const byte* seed) key->pubKeySet = 1; } + /* Zeroize the whole buffer before freeing. It holds the private vectors + * s1, s2 and t at the front; the rejection-sampling / matrix A region in + * the middle is public, but the trailing t64 accumulator (POLY64 builds) + * holds A o NTT(s1) - from which s1 is recoverable - so it must be + * cleared too. As the secret material is not contiguous, zeroize the + * entire allocation rather than a sub-range. */ + if (s1 != NULL) { + ForceZero(s1, allocSz); + } XFREE(s1, key->heap, DYNAMIC_TYPE_MLDSA); return ret; #endif @@ -8584,7 +8598,14 @@ static int mldsa_sign_with_seed_mu(wc_MlDsaKey* key, ForceZero(priv_rand_seed, sizeof(priv_rand_seed)); if (y != NULL) { - ForceZero(y, allocSz); + word32 zeroSz = allocSz; +#ifndef WC_MLDSA_CACHE_MATRIX_A + /* The public matrix A is appended at the end of the buffer and is + * expanded from the public seed - it need not be zeroized. The + * preceding vectors (y, w0, s1, s2, t0, ...) are secret dependent. */ + zeroSz -= (word32)params->aSz; +#endif + ForceZero(y, zeroSz); } XFREE(y, key->heap, DYNAMIC_TYPE_MLDSA); return ret; @@ -8593,10 +8614,12 @@ static int mldsa_sign_with_seed_mu(wc_MlDsaKey* key, const wc_MlDsaParams* params = key->params; const byte* pub_seed = key->k; const byte* k = pub_seed + MLDSA_PUB_SEED_SZ; +#ifndef WOLFSSL_MLDSA_SIGN_SMALL_MEM_PRECALC const byte* tr = k + MLDSA_K_SZ; const byte* s1p = tr + MLDSA_TR_SZ; const byte* s2p = s1p + params->s1EncSz; const byte* t0p = s2p + params->s2EncSz; +#endif const byte* mu = seedMu + MLDSA_RND_SZ; sword32* a = NULL; sword32* s1 = NULL; @@ -9027,8 +9050,8 @@ static int mldsa_sign_with_seed_mu(wc_MlDsaKey* key, } } if ((ret == 0) && valid) { - const byte* t0pt = t0p; #ifndef WOLFSSL_MLDSA_SIGN_SMALL_MEM_PRECALC + const byte* t0pt = t0p; const byte* s2pt = s2p; #endif sword32* cs2 = ct0; @@ -9112,7 +9135,9 @@ static int mldsa_sign_with_seed_mu(wc_MlDsaKey* key, #endif } + #ifndef WOLFSSL_MLDSA_SIGN_SMALL_MEM_PRECALC t0pt += MLDSA_D * MLDSA_N / 8; + #endif w0t += MLDSA_N; w1t += MLDSA_N; } diff --git a/wolfcrypt/src/wc_port.c b/wolfcrypt/src/wc_port.c index e7463732ce..63c1bb57f5 100644 --- a/wolfcrypt/src/wc_port.c +++ b/wolfcrypt/src/wc_port.c @@ -241,12 +241,172 @@ Threading/Mutex options: #endif #endif -/* prevent multiple mutex initializations */ -#ifdef WOLFSSL_ATOMIC_OPS - wolfSSL_Atomic_Int initRefCount = WOLFSSL_ATOMIC_INITIALIZER(0); +/* Internal APIs for counting initialization depth, with initialization/cleanup + * races fully mitigated + */ +int wc_local_InitUp(wc_init_state_t *s) +{ + union wc_init_state_bitfields exp_wc_init_state, new_wc_init_state; + exp_wc_init_state.u = WOLFSSL_ATOMIC_LOAD(*s); + + /* Mitigate races on init/shutdown by looping, unless + * WC_INIT_ERROR_WHEN_CONTENDED. + */ + for (;;) { + wc_static_assert(WC_INIT_STATE_STATE_BITS + WC_INIT_STATE_COUNT_BITS == + sizeof(WC_ATOMIC_UINT_ARG) * 8); + if (exp_wc_init_state.c.count == + (((WC_ATOMIC_UINT_ARG)1 << WC_INIT_STATE_COUNT_BITS) + - (WC_ATOMIC_UINT_ARG)1)) + { + return SEQ_OVERFLOW_E; + } + new_wc_init_state = exp_wc_init_state; + if (exp_wc_init_state.c.state == WC_INIT_STATE_UNINITED) { + if (exp_wc_init_state.c.count != 0) + return BAD_STATE_E; + new_wc_init_state.c.state = WC_INIT_STATE_INITING; + } + else if (exp_wc_init_state.c.state >= WC_INIT_STATE_BAD_STATE) { + wc_static_assert(WC_INIT_STATE_BAD_STATE > WC_INIT_STATE_UNINITED && + WC_INIT_STATE_BAD_STATE > WC_INIT_STATE_INITING && + WC_INIT_STATE_BAD_STATE > WC_INIT_STATE_INITED && + WC_INIT_STATE_BAD_STATE > WC_INIT_STATE_CLEANING_UP); + return BAD_STATE_E; + } + else { + if (exp_wc_init_state.c.count == 0) + return BAD_STATE_E; + /* Force expected state to _INITED -- if actual value upon cmpxchg + * doesn't match (normally either _INITING or _CLEANING_UP), we'll + * spin until the transient state resolves to _INITED or _UNINITED + * (when the competing thread calls wc_local_InitUpDone() or + * wc_local_InitDownDone(), respectively). + */ + exp_wc_init_state.c.state = WC_INIT_STATE_INITED; + new_wc_init_state.c.state = WC_INIT_STATE_INITED; + } + ++new_wc_init_state.c.count; + /* if another thread entered _STATE_INITING or _CLEANING_UP, this will + * fail and spin. + */ + if (wolfSSL_Atomic_Uint_CompareExchange(s, + &exp_wc_init_state.u, + new_wc_init_state.u)) + break; +#ifdef WC_INIT_ERROR_WHEN_CONTENDED + return BUSY_E; #else - static int initRefCount = 0; + WC_RELAX_LONG_LOOP(); /* not really long. */ #endif + } + return new_wc_init_state.c.state; +} + +int wc_local_InitUpDone(wc_init_state_t *s) +{ + union wc_init_state_bitfields cur_wc_init_state; + cur_wc_init_state.u = WOLFSSL_ATOMIC_LOAD(*s); + if (cur_wc_init_state.c.state != WC_INIT_STATE_INITING) + return BAD_FUNC_ARG; + cur_wc_init_state.c.state = WC_INIT_STATE_INITED; + /* Note, because WC_INIT_STATE_INITING functions as a mutex on the module + * state, we can use a plain _STORE() to release the module into its _INITED + * state. + */ + WOLFSSL_ATOMIC_STORE(*s, cur_wc_init_state.u); + return 0; +} + +int wc_local_InitDown(wc_init_state_t *s) +{ + union wc_init_state_bitfields exp_wc_init_state, new_wc_init_state; + + exp_wc_init_state.u = WOLFSSL_ATOMIC_LOAD(*s); + + /* Mitigate races on init/shutdown by looping, unless + * WC_INIT_ERROR_WHEN_CONTENDED. + */ + for (;;) { + if (exp_wc_init_state.c.state >= WC_INIT_STATE_BAD_STATE) { + /* wc_static_assert above in wc_local_InitUp() protects the logic of + * the inequality test. + */ + return BAD_STATE_E; + } + else if (exp_wc_init_state.c.state == WC_INIT_STATE_UNINITED) { + if (exp_wc_init_state.c.count == 0) { + /* thread attempted to wc_local_InitDown() without a matching + * previous wc_local_InitUp(). + */ + return ALREADY_E; /* backward compat */ + } + else { + /* nonzero .count with _STATE_UNINITED is impossible. */ + return BAD_STATE_E; + } + } + else if (exp_wc_init_state.c.state == WC_INIT_STATE_INITING) { + /* _INITING is impossible here unless a thread calls + * wc_local_InitDown() before (or without) successfully calling + * wc_local_InitUpDone(). + */ + return BAD_FUNC_ARG; + } + else if (exp_wc_init_state.c.state == WC_INIT_STATE_CLEANING_UP) { + if (exp_wc_init_state.c.count == 1) { + /* thread attempted to wc_local_InitDown() without a matching + * previous wc_local_InitUp(). + */ + return ALREADY_E; /* backward compat */ + } + else { + /* _CLEANING_UP is impossible with .count != 1. */ + return BAD_STATE_E; + } + } + else if (exp_wc_init_state.c.count == 0) { + /* zero count with state != _UNINITED is impossible. */ + return BAD_STATE_E; + } + new_wc_init_state = exp_wc_init_state; + if (exp_wc_init_state.c.count == 1) { + new_wc_init_state.c.state = WC_INIT_STATE_CLEANING_UP; + /* don't zero until end. */ + } + else + --new_wc_init_state.c.count; + if (wolfSSL_Atomic_Uint_CompareExchange(s, + &exp_wc_init_state.u, + new_wc_init_state.u)) + break; +#ifdef WC_INIT_ERROR_WHEN_CONTENDED + return BUSY_E; +#else + WC_RELAX_LONG_LOOP(); /* not really long. */ +#endif + } + + return new_wc_init_state.c.state; +} + +int wc_local_InitDownDone(wc_init_state_t *s) +{ + union wc_init_state_bitfields cur_wc_init_state; + cur_wc_init_state.u = WOLFSSL_ATOMIC_LOAD(*s); + if (cur_wc_init_state.c.state != WC_INIT_STATE_CLEANING_UP) + return BAD_FUNC_ARG; + cur_wc_init_state.c.state = WC_INIT_STATE_UNINITED; + cur_wc_init_state.c.count = 0; + /* Note, because WC_INIT_STATE_CLEANING_UP functions as a mutex on the + * module state, we can use a plain _STORE() to release the module into its + * _UNINITED state. + */ + WOLFSSL_ATOMIC_STORE(*s, cur_wc_init_state.u); + return 0; +} + +static WC_DECLARE_INIT_STATE(wolfcrypt_init_state); #if defined(__aarch64__) && defined(WOLFSSL_ARMASM_BARRIER_DETECT) int aarch64_use_sb = 0; @@ -258,11 +418,40 @@ int aarch64_use_sb = 0; WOLFSSL_ABI int wolfCrypt_Init(void) { - int ret = 0; - int my_initRefCount = wolfSSL_Atomic_Int_FetchAdd(&initRefCount, 1); - if (my_initRefCount == 0) { + int ret; +#if defined(HAVE_THREAD_LS) && !defined(NO_THREAD_LS) && defined(__GNUC__) + /* If thread-local storage is available, use it to prevent deadlock on + * recursion. We only do this when __GNUC__ -- this code is known to cause + * internal compiler faults on Watcom, and is probably problematic on other + * non-_GNUC__ targets besides. + */ + static THREAD_LS_T int in_init = 0; + if (in_init) + return DEADLOCK_AVERTED_E; + #define WOLFCRYPT_INIT_RAISE_BAD_STATE() do { \ + in_init = 0; \ + WC_INIT_STATE_RAISE_BAD_STATE(wolfcrypt_init_state); \ + return ret; \ + } while (0) +#else + #define WOLFCRYPT_INIT_RAISE_BAD_STATE() do { \ + WC_INIT_STATE_RAISE_BAD_STATE(wolfcrypt_init_state); \ + return ret; \ + } while (0) +#endif + + ret = wc_local_InitUp(&wolfcrypt_init_state); + if (ret < 0) + return ret; + else if (ret == WC_INIT_STATE_INITED) + return 0; + else { WOLFSSL_ENTER("wolfCrypt_Init"); +#if defined(HAVE_THREAD_LS) && !defined(NO_THREAD_LS) && defined(__GNUC__) + in_init = 1; +#endif + #if defined(__aarch64__) && defined(WOLFSSL_ARMASM_BARRIER_DETECT) aarch64_use_sb = IS_AARCH64_SB(cpuid_get_flags()); #endif @@ -304,8 +493,8 @@ int wolfCrypt_Init(void) if( ret != TSIP_SUCCESS ) { WOLFSSL_MSG("RENESAS TSIP Open failed"); /* not return 1 since WOLFSSL_SUCCESS=1*/ - ret = -1;/* FATAL ERROR */ - return ret; + ret = WC_FAILURE; + WOLFCRYPT_INIT_RAISE_BAD_STATE(); } #endif @@ -314,8 +503,8 @@ int wolfCrypt_Init(void) if( ret != 0 ) { WOLFSSL_MSG("Renesas RX64 HW Open failed"); /* not return 1 since WOLFSSL_SUCCESS=1*/ - ret = -1;/* FATAL ERROR */ - return ret; + ret = WC_FAILURE; + WOLFCRYPT_INIT_RAISE_BAD_STATE(); } #endif @@ -324,8 +513,8 @@ int wolfCrypt_Init(void) if( ret != FSP_SUCCESS ) { WOLFSSL_MSG("RENESAS SCE Open failed"); /* not return 1 since WOLFSSL_SUCCESS=1*/ - ret = -1;/* FATAL ERROR */ - return ret; + ret = WC_FAILURE; + WOLFCRYPT_INIT_RAISE_BAD_STATE(); } #endif @@ -333,7 +522,7 @@ int wolfCrypt_Init(void) ret = InitMemoryTracker(); if (ret != 0) { WOLFSSL_MSG("InitMemoryTracker failed"); - return ret; + WOLFCRYPT_INIT_RAISE_BAD_STATE(); } #endif @@ -341,7 +530,7 @@ int wolfCrypt_Init(void) ret = allocate_wolfcrypt_linuxkm_fpu_states(); if (ret != 0) { WOLFSSL_MSG("allocate_wolfcrypt_linuxkm_fpu_states failed"); - return ret; + WOLFCRYPT_INIT_RAISE_BAD_STATE(); } #endif @@ -350,7 +539,7 @@ int wolfCrypt_Init(void) ret = wolfSSL_CryptHwMutexInit(); if (ret != 0) { WOLFSSL_MSG("Hw crypt mutex init failed"); - return ret; + WOLFCRYPT_INIT_RAISE_BAD_STATE(); } #endif @@ -360,7 +549,7 @@ int wolfCrypt_Init(void) ret = wc_DrbgState_MutexInit(); if (ret != 0) { WOLFSSL_MSG("DRBG state mutex init failed"); - return ret; + WOLFCRYPT_INIT_RAISE_BAD_STATE(); } #endif @@ -368,7 +557,7 @@ int wolfCrypt_Init(void) ret = ksdk_port_init(); if (ret != 0) { WOLFSSL_MSG("KSDK port init failed"); - return ret; + WOLFCRYPT_INIT_RAISE_BAD_STATE(); } #endif @@ -376,15 +565,16 @@ int wolfCrypt_Init(void) #if defined(MAX3266X_AES) && defined(WOLF_CRYPTO_CB) ret = wc_CryptoCb_RegisterDevice(WOLFSSL_MAX3266X_DEVID, wc_MxcCryptoCb, NULL); - if(ret != 0) { - return ret; + if (ret != 0) { + WOLFCRYPT_INIT_RAISE_BAD_STATE(); } #endif #if defined(MAX3266X_RTC) ret = wc_MXC_RTC_Init(); if (ret != 0) { WOLFSSL_MSG("MXC RTC Init Failed"); - return WC_HW_E; + ret = WC_HW_E; + WOLFCRYPT_INIT_RAISE_BAD_STATE(); } #endif @@ -393,7 +583,7 @@ int wolfCrypt_Init(void) ret = atmel_init(); if (ret != 0) { WOLFSSL_MSG("CryptoAuthLib init failed"); - return ret; + WOLFCRYPT_INIT_RAISE_BAD_STATE(); } #endif #if defined(WOLFSSL_CRYPTOCELL) @@ -401,28 +591,28 @@ int wolfCrypt_Init(void) ret = cc310_Init(); if (ret != 0) { WOLFSSL_MSG("CRYPTOCELL init failed"); - return ret; + WOLFCRYPT_INIT_RAISE_BAD_STATE(); } #endif #ifdef WOLFSSL_STSAFE ret = stsafe_interface_init(); if (ret != 0) { WOLFSSL_MSG("STSAFE init failed"); - return ret; + WOLFCRYPT_INIT_RAISE_BAD_STATE(); } #endif #if defined(WOLFSSL_TROPIC01) ret = Tropic01_Init(); if (ret != 0) { WOLFSSL_MSG("Tropic01 init failed"); - return ret; + WOLFCRYPT_INIT_RAISE_BAD_STATE(); } #endif #if defined(WOLFSSL_PSOC6_CRYPTO) ret = psoc6_crypto_port_init(); if (ret != 0) { WOLFSSL_MSG("PSoC6 crypto engine init failed"); - return ret; + WOLFCRYPT_INIT_RAISE_BAD_STATE(); } #endif @@ -430,20 +620,24 @@ int wolfCrypt_Init(void) ret = maxq10xx_port_init(); if (ret != 0) { WOLFSSL_MSG("MAXQ10xx port init failed"); - return ret; + WOLFCRYPT_INIT_RAISE_BAD_STATE(); } #endif #ifdef WOLFSSL_SILABS_SE_ACCEL /* init handles if it is already initialized */ ret = sl_se_init(); + if (ret != 0) { + WOLFSSL_MSG("SILABS_SE_ACCEL init failed"); + WOLFCRYPT_INIT_RAISE_BAD_STATE(); + } #endif #if defined(WOLFSSL_SE050) && defined(WOLFSSL_SE050_INIT) ret = wc_se050_init(NULL); if (ret != 0) { WOLFSSL_MSG("SE050 init failed"); - return ret; + WOLFCRYPT_INIT_RAISE_BAD_STATE(); } #endif @@ -462,13 +656,14 @@ int wolfCrypt_Init(void) #if defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE) if ((ret = wc_LoggingInit()) != 0) { WOLFSSL_MSG("Error creating logging mutex"); - return ret; + WOLFCRYPT_INIT_RAISE_BAD_STATE(); } #endif #if defined(WOLFSSL_HAVE_PSA) - if ((ret = wc_psa_init()) != 0) - return ret; + if ((ret = wc_psa_init()) != 0) { + WOLFCRYPT_INIT_RAISE_BAD_STATE(); + } #endif #if defined(USE_WINDOWS_API) && defined(WIN_REUSE_CRYPT_HANDLE) @@ -482,7 +677,7 @@ int wolfCrypt_Init(void) ret = Entropy_Init(); if (ret != 0) { WOLFSSL_MSG("Error initializing entropy"); - return ret; + WOLFCRYPT_INIT_RAISE_BAD_STATE(); } #endif @@ -493,14 +688,14 @@ int wolfCrypt_Init(void) #ifdef ECC_CACHE_CURVE if ((ret = wc_ecc_curve_cache_init()) != 0) { WOLFSSL_MSG("Error creating curve cache"); - return ret; + WOLFCRYPT_INIT_RAISE_BAD_STATE(); } #endif #if defined(HAVE_OID_ENCODING) && (!defined(HAVE_FIPS) || \ (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(6,0))) if ((ret = wc_ecc_oid_cache_init()) != 0) { WOLFSSL_MSG("Error creating ECC oid cache"); - return ret; + WOLFCRYPT_INIT_RAISE_BAD_STATE(); } #endif #endif @@ -514,69 +709,67 @@ int wolfCrypt_Init(void) } if (ret != SSP_SUCCESS) { WOLFSSL_MSG("Error opening SCE"); - return -1; /* FATAL_ERROR */ + ret = WC_FAILURE; + WOLFCRYPT_INIT_RAISE_BAD_STATE(); } #endif #if defined(WOLFSSL_DEVCRYPTO) if ((ret = wc_DevCryptoInit()) != 0) { - return ret; + WOLFCRYPT_INIT_RAISE_BAD_STATE(); } #endif #if defined(WOLFSSL_CAAM) if ((ret = wc_caamInit()) != 0) { - return ret; + WOLFCRYPT_INIT_RAISE_BAD_STATE(); } #endif #if defined(HAVE_ARIA) if ((ret = wc_AriaInit()) != 0) { - return ret; + WOLFCRYPT_INIT_RAISE_BAD_STATE(); } #endif #ifdef WOLFSSL_IMXRT_DCP if ((ret = wc_dcp_init()) != 0) { - return ret; + WOLFCRYPT_INIT_RAISE_BAD_STATE(); } #endif #ifdef WOLFSSL_NXP_CASPER if ((ret = wc_casper_init()) != 0) { - return ret; + WOLFCRYPT_INIT_RAISE_BAD_STATE(); } #endif #ifdef WOLFSSL_NXP_HASHCRYPT if ((ret = wc_hashcrypt_init()) != 0) { - return ret; + WOLFCRYPT_INIT_RAISE_BAD_STATE(); } #endif #if defined(WOLFSSL_DSP) && !defined(WOLFSSL_DSP_BUILD) if ((ret = wolfSSL_InitHandle()) != 0) { - return ret; + WOLFCRYPT_INIT_RAISE_BAD_STATE(); } rpcmem_init(); #endif #if defined(HAVE_LIBOQS) if ((ret = wolfSSL_liboqsInit()) != 0) { - return ret; + WOLFCRYPT_INIT_RAISE_BAD_STATE(); } #endif - /* increment to 2, to signify successful initialization: */ - (void)wolfSSL_Atomic_Int_FetchAdd(&initRefCount, 1); - } - else { - if (my_initRefCount < 2) { - (void)wolfSSL_Atomic_Int_FetchSub(&initRefCount, 1); - ret = BUSY_E; - } - } +#undef WOLFCRYPT_INIT_RAISE_BAD_STATE - return ret; +#if defined(HAVE_THREAD_LS) && !defined(NO_THREAD_LS) && defined(__GNUC__) + in_init = 0; +#endif + return wc_local_InitUpDone(&wolfcrypt_init_state); + } + /* not reached */ } #if defined(WOLFSSL_TRACK_MEMORY_VERBOSE) && !defined(WOLFSSL_STATIC_MEMORY) @@ -597,10 +790,27 @@ long wolfCrypt_heap_peakBytes_checkpoint(void) { WOLFSSL_ABI int wolfCrypt_Cleanup(void) { - int ret = 0; - int my_initRefCount = wolfSSL_Atomic_Int_SubFetch(&initRefCount, 1); + int ret; + + ret = wc_local_InitDown(&wolfcrypt_init_state); + if (ret < 0) { + if (ret == WC_NO_ERR_TRACE(ALREADY_E)) + WOLFSSL_MSG("wolfCrypt_Cleanup() called during or after prior final cleanup."); + else if (ret == WC_NO_ERR_TRACE(BAD_STATE_E)) + WOLFSSL_MSG("wolfCrypt_Cleanup() failed: bad internal state."); +#ifdef WC_INIT_ERROR_WHEN_CONTENDED + else if (ret == WC_NO_ERR_TRACE(BUSY_E)) + WOLFSSL_MSG("wolfCrypt_Cleanup() failed with BUSY_E -- retry."); +#endif + else + WOLFSSL_MSG("wolfCrypt_Cleanup() failed with unexpected error."); + return ret; + } + else if (ret == WC_INIT_STATE_INITED) + return 0; + else { + ret = 0; - if (my_initRefCount == 1) { WOLFSSL_ENTER("wolfCrypt_Cleanup"); #ifdef HAVE_ECC @@ -617,7 +827,11 @@ int wolfCrypt_Cleanup(void) #endif /* HAVE_ECC */ #if defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE) - ret = wc_LoggingCleanup(); + { + int ret2 = wc_LoggingCleanup(); + if (ret == 0) + ret = ret2; + } #endif #if defined(WOLFSSL_TRACK_MEMORY) && !defined(WOLFSSL_STATIC_MEMORY) @@ -651,7 +865,11 @@ int wolfCrypt_Cleanup(void) cc310_Free(); #endif #ifdef WOLFSSL_SILABS_SE_ACCEL - ret = sl_se_deinit(); + { + int ret2 = sl_se_deinit(); + if (ret == 0) + ret = ret2; + } #endif #if defined(WOLFSSL_TROPIC01) Tropic01_Deinit(); @@ -697,19 +915,20 @@ int wolfCrypt_Cleanup(void) wc_MemZero_Free(); #endif - (void)wolfSSL_Atomic_Int_SubFetch(&initRefCount, 1); - #if defined(HAVE_LIBOQS) wolfSSL_liboqsClose(); #endif - } - else if (my_initRefCount < 0) { - (void)wolfSSL_Atomic_Int_AddFetch(&initRefCount, 1); - WOLFSSL_MSG("wolfCrypt_Cleanup() called with initRefCount <= 0."); - ret = ALREADY_E; + + { + int ret2 = wc_local_InitDownDone(&wolfcrypt_init_state); + if (ret == 0) + ret = ret2; + } + + return ret; } - return ret; + /* not reached */ } #ifndef NO_FILESYSTEM @@ -1421,71 +1640,77 @@ char* wc_strdup_ex(const char *src, int memType) { * build in FreeBSD kernel, but are not commonly used in FreeBSD kernel and * might not be safe or portable. * */ -void wolfSSL_Atomic_Int_Init(wolfSSL_Atomic_Int* c, int i) +void wolfSSL_Atomic_Int_Init(wolfSSL_Atomic_Int* c, WC_ATOMIC_INT_ARG i) { *c = i; } -void wolfSSL_Atomic_Uint_Init(wolfSSL_Atomic_Uint* c, unsigned int i) +void wolfSSL_Atomic_Uint_Init(wolfSSL_Atomic_Uint* c, WC_ATOMIC_UINT_ARG i) { *c = i; } -int wolfSSL_Atomic_Int_FetchAdd(wolfSSL_Atomic_Int* c, int i) +WC_ATOMIC_INT_ARG wolfSSL_Atomic_Int_FetchAdd(wolfSSL_Atomic_Int* c, + WC_ATOMIC_INT_ARG i) { return atomic_fetchadd_int(c, i); } -int wolfSSL_Atomic_Int_FetchSub(wolfSSL_Atomic_Int* c, int i) +WC_ATOMIC_INT_ARG wolfSSL_Atomic_Int_FetchSub(wolfSSL_Atomic_Int* c, + WC_ATOMIC_INT_ARG i) { return atomic_fetchadd_int(c, -i); } -int wolfSSL_Atomic_Int_AddFetch(wolfSSL_Atomic_Int* c, int i) +WC_ATOMIC_INT_ARG wolfSSL_Atomic_Int_AddFetch(wolfSSL_Atomic_Int* c, + WC_ATOMIC_INT_ARG i) { int val = atomic_fetchadd_int(c, i); return val + i; } -int wolfSSL_Atomic_Int_SubFetch(wolfSSL_Atomic_Int* c, int i) +WC_ATOMIC_INT_ARG wolfSSL_Atomic_Int_SubFetch(wolfSSL_Atomic_Int* c, + WC_ATOMIC_INT_ARG i) { int val = atomic_fetchadd_int(c, -i); return val - i; } -unsigned int wolfSSL_Atomic_Uint_FetchAdd(wolfSSL_Atomic_Uint* c, - unsigned int i) +WC_ATOMIC_UINT_ARG wolfSSL_Atomic_Uint_FetchAdd(wolfSSL_Atomic_Uint* c, + WC_ATOMIC_UINT_ARG i) { return atomic_fetchadd_int(c, i); } -unsigned int wolfSSL_Atomic_Uint_FetchSub(wolfSSL_Atomic_Uint* c, - unsigned int i) +WC_ATOMIC_UINT_ARG wolfSSL_Atomic_Uint_FetchSub(wolfSSL_Atomic_Uint* c, + WC_ATOMIC_UINT_ARG i) { return atomic_fetchadd_int(c, -i); } -unsigned int wolfSSL_Atomic_Uint_AddFetch(wolfSSL_Atomic_Uint* c, - unsigned int i) +WC_ATOMIC_UINT_ARG wolfSSL_Atomic_Uint_AddFetch(wolfSSL_Atomic_Uint* c, + WC_ATOMIC_UINT_ARG i) { - unsigned int val = atomic_fetchadd_int(c, i); + WC_ATOMIC_UINT_ARG val = atomic_fetchadd_int(c, i); return val + i; } -unsigned int wolfSSL_Atomic_Uint_SubFetch(wolfSSL_Atomic_Uint* c, - unsigned int i) +WC_ATOMIC_UINT_ARG wolfSSL_Atomic_Uint_SubFetch(wolfSSL_Atomic_Uint* c, + WC_ATOMIC_UINT_ARG i) { unsigned int val = atomic_fetchadd_int(c, -i); return val - i; } -int wolfSSL_Atomic_Int_Exchange(wolfSSL_Atomic_Int* c, int new_i) +WC_ATOMIC_INT_ARG wolfSSL_Atomic_Int_Exchange(wolfSSL_Atomic_Int* c, + WC_ATOMIC_INT_ARG new_i) { return atomic_swap_int(c, new_i); } -int wolfSSL_Atomic_Int_CompareExchange(wolfSSL_Atomic_Int* c, int *expected_i, - int new_i) +int wolfSSL_Atomic_Int_CompareExchange(wolfSSL_Atomic_Int* c, + WC_ATOMIC_INT_ARG *expected_i, + WC_ATOMIC_INT_ARG new_i) { u_int exp = (u_int) *expected_i; int ret = atomic_fcmpset_int(c, &exp, new_i); @@ -1494,7 +1719,8 @@ int wolfSSL_Atomic_Int_CompareExchange(wolfSSL_Atomic_Int* c, int *expected_i, } int wolfSSL_Atomic_Uint_CompareExchange( - wolfSSL_Atomic_Uint* c, unsigned int *expected_i, unsigned int new_i) + wolfSSL_Atomic_Uint* c, WC_ATOMIC_UINT_ARG *expected_i, + WC_ATOMIC_UINT_ARG new_i) { u_int exp = (u_int)*expected_i; int ret = atomic_fcmpset_int(c, &exp, new_i); @@ -1515,45 +1741,53 @@ int wolfSSL_Atomic_Ptr_CompareExchange( !defined(__cplusplus) /* Default C Implementation */ -void wolfSSL_Atomic_Int_Init(wolfSSL_Atomic_Int* c, int i) +void wolfSSL_Atomic_Int_Init(wolfSSL_Atomic_Int* c, WC_ATOMIC_INT_ARG i) { atomic_init(c, i); } -void wolfSSL_Atomic_Uint_Init(wolfSSL_Atomic_Uint* c, unsigned int i) +void wolfSSL_Atomic_Uint_Init(wolfSSL_Atomic_Uint* c, WC_ATOMIC_UINT_ARG i) { atomic_init(c, i); } -int wolfSSL_Atomic_Int_FetchAdd(wolfSSL_Atomic_Int* c, int i) +WC_ATOMIC_INT_ARG wolfSSL_Atomic_Int_FetchAdd(wolfSSL_Atomic_Int* c, + WC_ATOMIC_INT_ARG i) { return atomic_fetch_add_explicit(c, i, memory_order_relaxed); } -int wolfSSL_Atomic_Int_FetchSub(wolfSSL_Atomic_Int* c, int i) +WC_ATOMIC_INT_ARG wolfSSL_Atomic_Int_FetchSub(wolfSSL_Atomic_Int* c, + WC_ATOMIC_INT_ARG i) { return atomic_fetch_sub_explicit(c, i, memory_order_relaxed); } -int wolfSSL_Atomic_Int_AddFetch(wolfSSL_Atomic_Int* c, int i) +WC_ATOMIC_INT_ARG wolfSSL_Atomic_Int_AddFetch(wolfSSL_Atomic_Int* c, + WC_ATOMIC_INT_ARG i) { - int ret = atomic_fetch_add_explicit(c, i, memory_order_relaxed); + WC_ATOMIC_INT_ARG ret = + atomic_fetch_add_explicit(c, i, memory_order_relaxed); return ret + i; } -int wolfSSL_Atomic_Int_SubFetch(wolfSSL_Atomic_Int* c, int i) +WC_ATOMIC_INT_ARG wolfSSL_Atomic_Int_SubFetch(wolfSSL_Atomic_Int* c, + WC_ATOMIC_INT_ARG i) { - int ret = atomic_fetch_sub_explicit(c, i, memory_order_relaxed); + WC_ATOMIC_INT_ARG ret = + atomic_fetch_sub_explicit(c, i, memory_order_relaxed); return ret - i; } -int wolfSSL_Atomic_Int_Exchange(wolfSSL_Atomic_Int* c, int new_i) +WC_ATOMIC_INT_ARG wolfSSL_Atomic_Int_Exchange(wolfSSL_Atomic_Int* c, + WC_ATOMIC_INT_ARG new_i) { return atomic_exchange_explicit(c, new_i, memory_order_seq_cst); } int wolfSSL_Atomic_Int_CompareExchange( - wolfSSL_Atomic_Int* c, int *expected_i, int new_i) + wolfSSL_Atomic_Int* c, WC_ATOMIC_INT_ARG *expected_i, + WC_ATOMIC_INT_ARG new_i) { /* For the success path, use full synchronization with barriers -- * "Sequentially-consistent ordering" -- so that all threads see the same @@ -1565,34 +1799,37 @@ int wolfSSL_Atomic_Int_CompareExchange( c, expected_i, new_i, memory_order_seq_cst, memory_order_acquire); } -unsigned int wolfSSL_Atomic_Uint_FetchAdd(wolfSSL_Atomic_Uint* c, - unsigned int i) +WC_ATOMIC_UINT_ARG wolfSSL_Atomic_Uint_FetchAdd(wolfSSL_Atomic_Uint* c, + WC_ATOMIC_UINT_ARG i) { return atomic_fetch_add_explicit(c, i, memory_order_relaxed); } -unsigned int wolfSSL_Atomic_Uint_FetchSub(wolfSSL_Atomic_Uint* c, - unsigned int i) +WC_ATOMIC_UINT_ARG wolfSSL_Atomic_Uint_FetchSub(wolfSSL_Atomic_Uint* c, + WC_ATOMIC_UINT_ARG i) { return atomic_fetch_sub_explicit(c, i, memory_order_relaxed); } -unsigned int wolfSSL_Atomic_Uint_AddFetch(wolfSSL_Atomic_Uint* c, - unsigned int i) +WC_ATOMIC_UINT_ARG wolfSSL_Atomic_Uint_AddFetch(wolfSSL_Atomic_Uint* c, + WC_ATOMIC_UINT_ARG i) { - unsigned int ret = atomic_fetch_add_explicit(c, i, memory_order_relaxed); + WC_ATOMIC_UINT_ARG ret = + atomic_fetch_add_explicit(c, i, memory_order_relaxed); return ret + i; } -unsigned int wolfSSL_Atomic_Uint_SubFetch(wolfSSL_Atomic_Uint* c, - unsigned int i) +WC_ATOMIC_UINT_ARG wolfSSL_Atomic_Uint_SubFetch(wolfSSL_Atomic_Uint* c, + WC_ATOMIC_UINT_ARG i) { - unsigned int ret = atomic_fetch_sub_explicit(c, i, memory_order_relaxed); + WC_ATOMIC_UINT_ARG ret = + atomic_fetch_sub_explicit(c, i, memory_order_relaxed); return ret - i; } int wolfSSL_Atomic_Uint_CompareExchange( - wolfSSL_Atomic_Uint* c, unsigned int *expected_i, unsigned int new_i) + wolfSSL_Atomic_Uint* c, WC_ATOMIC_UINT_ARG *expected_i, + WC_ATOMIC_UINT_ARG new_i) { /* For the success path, use full synchronization with barriers -- * "Sequentially-consistent ordering" -- so that all threads see the same @@ -1627,43 +1864,49 @@ int wolfSSL_Atomic_Ptr_CompareExchange( #elif defined(__GNUC__) && defined(__ATOMIC_RELAXED) /* direct calls using gcc-style compiler built-ins */ -void wolfSSL_Atomic_Int_Init(wolfSSL_Atomic_Int* c, int i) +void wolfSSL_Atomic_Int_Init(wolfSSL_Atomic_Int* c, WC_ATOMIC_INT_ARG i) { *c = i; } -void wolfSSL_Atomic_Uint_Init(wolfSSL_Atomic_Uint* c, unsigned int i) +void wolfSSL_Atomic_Uint_Init(wolfSSL_Atomic_Uint* c, WC_ATOMIC_UINT_ARG i) { *c = i; } -int wolfSSL_Atomic_Int_FetchAdd(wolfSSL_Atomic_Int* c, int i) +WC_ATOMIC_INT_ARG wolfSSL_Atomic_Int_FetchAdd(wolfSSL_Atomic_Int* c, + WC_ATOMIC_INT_ARG i) { return __atomic_fetch_add(c, i, __ATOMIC_RELAXED); } -int wolfSSL_Atomic_Int_FetchSub(wolfSSL_Atomic_Int* c, int i) +WC_ATOMIC_INT_ARG wolfSSL_Atomic_Int_FetchSub(wolfSSL_Atomic_Int* c, + WC_ATOMIC_INT_ARG i) { return __atomic_fetch_sub(c, i, __ATOMIC_RELAXED); } -int wolfSSL_Atomic_Int_AddFetch(wolfSSL_Atomic_Int* c, int i) +WC_ATOMIC_INT_ARG wolfSSL_Atomic_Int_AddFetch(wolfSSL_Atomic_Int* c, + WC_ATOMIC_INT_ARG i) { return __atomic_add_fetch(c, i, __ATOMIC_RELAXED); } -int wolfSSL_Atomic_Int_SubFetch(wolfSSL_Atomic_Int* c, int i) +WC_ATOMIC_INT_ARG wolfSSL_Atomic_Int_SubFetch(wolfSSL_Atomic_Int* c, + WC_ATOMIC_INT_ARG i) { return __atomic_sub_fetch(c, i, __ATOMIC_RELAXED); } -int wolfSSL_Atomic_Int_Exchange(wolfSSL_Atomic_Int* c, int new_i) +WC_ATOMIC_INT_ARG wolfSSL_Atomic_Int_Exchange(wolfSSL_Atomic_Int* c, + WC_ATOMIC_INT_ARG new_i) { return __atomic_exchange_n(c, new_i, __ATOMIC_SEQ_CST); } -int wolfSSL_Atomic_Int_CompareExchange(wolfSSL_Atomic_Int* c, int *expected_i, - int new_i) +int wolfSSL_Atomic_Int_CompareExchange(wolfSSL_Atomic_Int* c, + WC_ATOMIC_INT_ARG *expected_i, + WC_ATOMIC_INT_ARG new_i) { /* For the success path, use full synchronization with barriers -- * "Sequentially-consistent ordering" -- so that all threads see the same @@ -1675,32 +1918,33 @@ int wolfSSL_Atomic_Int_CompareExchange(wolfSSL_Atomic_Int* c, int *expected_i, __ATOMIC_SEQ_CST, __ATOMIC_ACQUIRE); } -unsigned int wolfSSL_Atomic_Uint_FetchAdd(wolfSSL_Atomic_Uint* c, - unsigned int i) +WC_ATOMIC_UINT_ARG wolfSSL_Atomic_Uint_FetchAdd(wolfSSL_Atomic_Uint* c, + WC_ATOMIC_UINT_ARG i) { return __atomic_fetch_add(c, i, __ATOMIC_RELAXED); } -unsigned int wolfSSL_Atomic_Uint_FetchSub(wolfSSL_Atomic_Uint* c, - unsigned int i) +WC_ATOMIC_UINT_ARG wolfSSL_Atomic_Uint_FetchSub(wolfSSL_Atomic_Uint* c, + WC_ATOMIC_UINT_ARG i) { return __atomic_fetch_sub(c, i, __ATOMIC_RELAXED); } -unsigned int wolfSSL_Atomic_Uint_AddFetch(wolfSSL_Atomic_Uint* c, - unsigned int i) +WC_ATOMIC_UINT_ARG wolfSSL_Atomic_Uint_AddFetch(wolfSSL_Atomic_Uint* c, + WC_ATOMIC_UINT_ARG i) { return __atomic_add_fetch(c, i, __ATOMIC_RELAXED); } -unsigned int wolfSSL_Atomic_Uint_SubFetch(wolfSSL_Atomic_Uint* c, - unsigned int i) +WC_ATOMIC_UINT_ARG wolfSSL_Atomic_Uint_SubFetch(wolfSSL_Atomic_Uint* c, + WC_ATOMIC_UINT_ARG i) { return __atomic_sub_fetch(c, i, __ATOMIC_RELAXED); } int wolfSSL_Atomic_Uint_CompareExchange( - wolfSSL_Atomic_Uint* c, unsigned int *expected_i, unsigned int new_i) + wolfSSL_Atomic_Uint* c, WC_ATOMIC_UINT_ARG *expected_i, + WC_ATOMIC_UINT_ARG new_i) { /* For the success path, use full synchronization with barriers -- * "Sequentially-consistent ordering" -- so that all threads see the same @@ -1722,46 +1966,54 @@ int wolfSSL_Atomic_Ptr_CompareExchange( #elif defined(_MSC_VER) && !defined(WOLFSSL_NOT_WINDOWS_API) -void wolfSSL_Atomic_Int_Init(wolfSSL_Atomic_Int* c, int i) +void wolfSSL_Atomic_Int_Init(wolfSSL_Atomic_Int* c, WC_ATOMIC_INT_ARG i) { *c = i; } -void wolfSSL_Atomic_Uint_Init(wolfSSL_Atomic_Uint* c, unsigned int i) +void wolfSSL_Atomic_Uint_Init(wolfSSL_Atomic_Uint* c, WC_ATOMIC_UINT_ARG i) { *c = i; } -int wolfSSL_Atomic_Int_FetchAdd(wolfSSL_Atomic_Int* c, int i) +WC_ATOMIC_INT_ARG wolfSSL_Atomic_Int_FetchAdd(wolfSSL_Atomic_Int* c, + WC_ATOMIC_INT_ARG i) { return (int)_InterlockedExchangeAdd(c, (long)i); } -int wolfSSL_Atomic_Int_FetchSub(wolfSSL_Atomic_Int* c, int i) +WC_ATOMIC_INT_ARG wolfSSL_Atomic_Int_FetchSub(wolfSSL_Atomic_Int* c, + WC_ATOMIC_INT_ARG i) { return (int)_InterlockedExchangeAdd(c, (long)-i); } -int wolfSSL_Atomic_Int_AddFetch(wolfSSL_Atomic_Int* c, int i) +WC_ATOMIC_INT_ARG wolfSSL_Atomic_Int_AddFetch(wolfSSL_Atomic_Int* c, + WC_ATOMIC_INT_ARG i) { - int ret = (int)_InterlockedExchangeAdd(c, (long)i); + WC_ATOMIC_INT_ARG ret = + (WC_ATOMIC_INT_ARG)_InterlockedExchangeAdd(c, (long)i); return ret + i; } -int wolfSSL_Atomic_Int_SubFetch(wolfSSL_Atomic_Int* c, int i) +WC_ATOMIC_INT_ARG wolfSSL_Atomic_Int_SubFetch(wolfSSL_Atomic_Int* c, + WC_ATOMIC_INT_ARG i) { - int ret = (int)_InterlockedExchangeAdd(c, (long)-i); + WC_ATOMIC_INT_ARG ret = + (WC_ATOMIC_INT_ARG)_InterlockedExchangeAdd(c, (long)-i); return ret - i; } -int wolfSSL_Atomic_Int_Exchange(wolfSSL_Atomic_Int* c, int new_i) +WC_ATOMIC_INT_ARG wolfSSL_Atomic_Int_Exchange(wolfSSL_Atomic_Int* c, + WC_ATOMIC_INT_ARG new_i) { long actual_i = InterlockedExchange(c, (long)new_i); - return (int)actual_i; + return (WC_ATOMIC_INT_ARG)actual_i; } -int wolfSSL_Atomic_Int_CompareExchange(wolfSSL_Atomic_Int* c, int *expected_i, - int new_i) +int wolfSSL_Atomic_Int_CompareExchange(wolfSSL_Atomic_Int* c, + WC_ATOMIC_INT_ARG *expected_i, + WC_ATOMIC_INT_ARG new_i) { long actual_i = InterlockedCompareExchange(c, (long)new_i, (long)*expected_i); @@ -1769,43 +2021,44 @@ int wolfSSL_Atomic_Int_CompareExchange(wolfSSL_Atomic_Int* c, int *expected_i, return 1; } else { - *expected_i = (int)actual_i; + *expected_i = (WC_ATOMIC_INT_ARG)actual_i; return 0; } } -unsigned int wolfSSL_Atomic_Uint_FetchAdd(wolfSSL_Atomic_Uint* c, - unsigned int i) +WC_ATOMIC_UINT_ARG wolfSSL_Atomic_Uint_FetchAdd(wolfSSL_Atomic_Uint* c, + WC_ATOMIC_UINT_ARG i) { - return (unsigned int)_InterlockedExchangeAdd((wolfSSL_Atomic_Int *)c, - (long)i); + return (WC_ATOMIC_UINT_ARG)_InterlockedExchangeAdd((wolfSSL_Atomic_Int *)c, + (long)i); } -unsigned int wolfSSL_Atomic_Uint_FetchSub(wolfSSL_Atomic_Uint* c, - unsigned int i) +WC_ATOMIC_UINT_ARG wolfSSL_Atomic_Uint_FetchSub(wolfSSL_Atomic_Uint* c, + WC_ATOMIC_UINT_ARG i) { - return (unsigned int)_InterlockedExchangeAdd((wolfSSL_Atomic_Int *)c, - -(long)i); + return (WC_ATOMIC_UINT_ARG)_InterlockedExchangeAdd((wolfSSL_Atomic_Int *)c, + -(long)i); } -unsigned int wolfSSL_Atomic_Uint_AddFetch(wolfSSL_Atomic_Uint* c, - unsigned int i) +WC_ATOMIC_UINT_ARG wolfSSL_Atomic_Uint_AddFetch(wolfSSL_Atomic_Uint* c, + WC_ATOMIC_UINT_ARG i) { - unsigned int ret = (unsigned int)_InterlockedExchangeAdd + WC_ATOMIC_UINT_ARG ret = (WC_ATOMIC_UINT_ARG)_InterlockedExchangeAdd ((wolfSSL_Atomic_Int *)c, (long)i); return ret + i; } -unsigned int wolfSSL_Atomic_Uint_SubFetch(wolfSSL_Atomic_Uint* c, - unsigned int i) +WC_ATOMIC_UINT_ARG wolfSSL_Atomic_Uint_SubFetch(wolfSSL_Atomic_Uint* c, + WC_ATOMIC_UINT_ARG i) { - unsigned int ret = (unsigned int)_InterlockedExchangeAdd + WC_ATOMIC_UINT_ARG ret = (WC_ATOMIC_UINT_ARG)_InterlockedExchangeAdd ((wolfSSL_Atomic_Int *)c, -(long)i); return ret - i; } int wolfSSL_Atomic_Uint_CompareExchange( - wolfSSL_Atomic_Uint* c, unsigned int *expected_i, unsigned int new_i) + wolfSSL_Atomic_Uint* c, WC_ATOMIC_UINT_ARG *expected_i, + WC_ATOMIC_UINT_ARG new_i) { long actual_i = InterlockedCompareExchange( (wolfSSL_Atomic_Int *)c, (long)new_i, (long)*expected_i); @@ -1813,7 +2066,7 @@ int wolfSSL_Atomic_Uint_CompareExchange( return 1; } else { - *expected_i = (unsigned int)actual_i; + *expected_i = (WC_ATOMIC_UINT_ARG)actual_i; return 0; } } diff --git a/wolfcrypt/src/wc_xmss.c b/wolfcrypt/src/wc_xmss.c index 576e109e70..9ad311d0ba 100644 --- a/wolfcrypt/src/wc_xmss.c +++ b/wolfcrypt/src/wc_xmss.c @@ -1575,7 +1575,7 @@ int wc_XmssKey_GetPubLen(const XmssKey* key, word32* len) int ret = 0; /* Validate parameters. */ - if ((key == NULL) || (len == NULL)) { + if ((key == NULL) || (key->params == NULL) || (len == NULL)) { ret = BAD_FUNC_ARG; } else { diff --git a/wolfcrypt/src/wolfentropy.c b/wolfcrypt/src/wolfentropy.c index a8f42119f6..1d23c7d8c2 100644 --- a/wolfcrypt/src/wolfentropy.c +++ b/wolfcrypt/src/wolfentropy.c @@ -816,7 +816,7 @@ int wc_Entropy_Get(int bits, unsigned char* entropy, word32 len) int noise_len; static byte noise[MAX_NOISE_CNT]; - if (bits <= 0 || (entropy == NULL && len > 0)) { + if (bits <= 0 || bits > MAX_ENTROPY_BITS || (entropy == NULL && len > 0)) { return BAD_FUNC_ARG; } diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index cd3275650b..d76dd112c9 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -8732,7 +8732,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hash_test(void) #endif WC_HASH_TYPE_NONE }; - int typesBad[] = { WC_HASH_TYPE_NONE, WC_HASH_TYPE_MAX + 1 }; + enum wc_HashType typesBad[] = { WC_HASH_TYPE_NONE }; enum wc_HashType typesHashBad[] = { #ifndef WOLFSSL_MD2 @@ -13509,14 +13509,17 @@ out: Aes enc[1]; #endif byte cipher[WC_AES_BLOCK_SIZE * 4]; -#ifdef HAVE_AES_DECRYPT +/* dec and plain are used by the HAVE_AES_DECRYPT paths and are also passed to + * aescfb_192_stream_test_0() (which ignores them when HAVE_AES_DECRYPT is not + * defined). */ +#if defined(HAVE_AES_DECRYPT) || defined(WOLFSSL_AES_192) #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) Aes *dec = NULL; #else Aes dec[1]; #endif - byte plain [WC_AES_BLOCK_SIZE * 4]; -#endif + byte plain[WC_AES_BLOCK_SIZE * 4]; +#endif /* HAVE_AES_DECRYPT || WOLFSSL_AES_192 */ wc_test_ret_t ret = 0; WOLFSSL_SMALL_STACK_STATIC const byte iv[] = { @@ -15255,12 +15258,10 @@ out: #else wc_AesFree(enc); #endif -#ifdef HAVE_AES_DECRYPT #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) wc_AesDelete(dec, &dec); #else wc_AesFree(dec); -#endif #endif return ret; } @@ -17562,10 +17563,12 @@ static wc_test_ret_t aes_xts_256_vector_test(XtsAes *aes) static wc_test_ret_t aes_xts_256_partial_test(XtsAes *aes) { wc_test_ret_t ret = 0; - byte buf[WC_AES_BLOCK_SIZE * 3]; byte cipher[WC_AES_BLOCK_SIZE * 3]; +#ifdef HAVE_AES_DECRYPT + byte buf[WC_AES_BLOCK_SIZE * 3]; #ifdef WOLFSSL_AESXTS_STREAM struct XtsAesStreamData stream; +#endif #endif WOLFSSL_SMALL_STACK_STATIC const unsigned char k1[] = { 0x1e, 0xa6, 0x61, 0xc5, 0x8d, 0x94, 0x3a, 0x0e, @@ -17587,6 +17590,7 @@ static wc_test_ret_t aes_xts_256_partial_test(XtsAes *aes) 0x6f, 0xb3, 0x50, 0x39, 0x07, 0x90, 0x31, 0x1c, 0x6e, 0x4b, 0x92, 0x01, 0x3e, 0x76, 0x8a, 0xd5 }; +#ifdef HAVE_AES_DECRYPT WOLFSSL_SMALL_STACK_STATIC const unsigned char p1[] = { 0x2e, 0xed, 0xea, 0x52, 0xcd, 0x82, 0x15, 0xe1, 0xac, 0xc6, 0x47, 0xe8, 0x10, 0xbb, 0xc3, 0x64, @@ -17629,6 +17633,7 @@ static wc_test_ret_t aes_xts_256_partial_test(XtsAes *aes) 0xe6, 0x6c, 0xdb, 0xb7, 0x9a, 0xb4, 0x28, 0x9b, 0xc3, 0xea, 0xd8, 0x10, 0xe9, 0xc0, 0xaf, 0x92 }; +#endif /* partial block encryption test */ XMEMSET(cipher, 0, sizeof(cipher)); @@ -19057,8 +19062,9 @@ static wc_test_ret_t aesgcm_setiv_test(Aes* enc, Aes* dec) wc_FreeRng(&rng); #else (void)enc; - (void)dec; #endif /* WOLFSSL_AES_256 && ... */ + + (void)dec; return ret; } @@ -19306,13 +19312,17 @@ static wc_test_ret_t aesgcm_non12iv_test(Aes* enc, Aes* dec) 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, 0xba, 0x63, 0x7b, 0x39 }; +#if defined(WOLFSSL_AES_192) || \ + (defined(WOLFSSL_AES_128) && defined(BENCH_AESGCM_LARGE)) WOLFSSL_SMALL_STACK_STATIC const byte a[] = { 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2 }; -#ifdef BENCH_AESGCM_LARGE +#endif +#if defined(BENCH_AESGCM_LARGE) && \ + (defined(WOLFSSL_AES_192) || defined(WOLFSSL_AES_128)) WOLFSSL_SMALL_STACK_STATIC const byte iv1[] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, @@ -19402,7 +19412,8 @@ static wc_test_ret_t aesgcm_non12iv_test(Aes* enc, Aes* dec) byte resultT[sizeof(t1) + WC_AES_BLOCK_SIZE]; byte resultP[sizeof(p) + WC_AES_BLOCK_SIZE]; byte resultC[sizeof(p) + WC_AES_BLOCK_SIZE]; -#ifdef BENCH_AESGCM_LARGE +#if defined(BENCH_AESGCM_LARGE) && \ + (defined(WOLFSSL_AES_192) || defined(WOLFSSL_AES_128)) int alen = 0; #endif #if !defined(BENCH_EMBEDDED) && !defined(HAVE_CAVIUM) @@ -19781,6 +19792,7 @@ static wc_test_ret_t aesgcm_aes128_vector_test(Aes* enc, Aes* dec) #endif /* HAVE_AES_DECRYPT */ out: + (void)dec; return ret; } #endif /* WOLFSSL_AES_128 && !WOLFSSL_AFALG_XILINX_AES */ @@ -19829,7 +19841,6 @@ static wc_test_ret_t aesgcm_aes256_vector_test(Aes* enc, Aes* dec) 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88 }; -#ifdef HAVE_AES_DECRYPT WOLFSSL_SMALL_STACK_STATIC const byte c1[] = { 0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07, @@ -19841,7 +19852,6 @@ static wc_test_ret_t aesgcm_aes256_vector_test(Aes* enc, Aes* dec) 0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a, 0xbc, 0xc9, 0xf6, 0x62 }; -#endif WOLFSSL_SMALL_STACK_STATIC const byte t1[] = { 0x76, 0xfc, 0x6e, 0xce, 0x0f, 0x4e, 0x17, 0x68, @@ -19891,6 +19901,7 @@ static wc_test_ret_t aesgcm_aes256_vector_test(Aes* enc, Aes* dec) #endif /* HAVE_AES_DECRYPT */ out: + (void)dec; return ret; } @@ -19932,6 +19943,7 @@ static wc_test_ret_t aesgcm_aes256_large_test(Aes* enc, Aes* dec) 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88 }; +#ifdef HAVE_AES_DECRYPT WOLFSSL_SMALL_STACK_STATIC const byte c1[] = { 0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07, @@ -19943,6 +19955,7 @@ static wc_test_ret_t aesgcm_aes256_large_test(Aes* enc, Aes* dec) 0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a, 0xbc, 0xc9, 0xf6, 0x62 }; +#endif WOLFSSL_SMALL_STACK_STATIC const byte t1[] = { 0x76, 0xfc, 0x6e, 0xce, 0x0f, 0x4e, 0x17, 0x68, @@ -20184,6 +20197,7 @@ static wc_test_ret_t aesgcm_aes256_large_test(Aes* enc, Aes* dec) #if defined(WOLFSSL_XILINX_CRYPT_VERSAL) XFREE(large_aad, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); #endif + (void)dec; return ret; } #endif /* WOLFSSL_AES_256 */ @@ -20962,7 +20976,9 @@ static wc_test_ret_t aesccm_128_large_test(Aes* enc) { 0x89, 0xd8, 0xd2, 0x02, 0xc5, 0xcf, 0xae, 0xf4 }; +#ifdef HAVE_AES_DECRYPT byte pl2[sizeof(pl)]; +#endif byte cl2[sizeof(cl)]; byte tl2[sizeof(tl)]; @@ -48597,23 +48613,23 @@ static wc_test_ret_t mlkem512_kat(void) #endif #ifdef WOLFSSL_MLKEM_KYBER - ret = wc_KyberKey_Init(KYBER512, key, HEAP_HINT, katDevId); + ret = wc_MlKemKey_Init(key, KYBER512, HEAP_HINT, katDevId); if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); else key_inited = 1; #ifndef WOLFSSL_MLKEM_NO_MAKE_KEY - ret = wc_KyberKey_MakeKeyWithRandom(key, kyber512_rand, + ret = wc_MlKemKey_MakeKeyWithRandom(key, kyber512_rand, sizeof(kyber512_rand)); if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); - ret = wc_KyberKey_EncodePublicKey(key, pub, KYBER512_PUBLIC_KEY_SIZE); + ret = wc_MlKemKey_EncodePublicKey(key, pub, KYBER512_PUBLIC_KEY_SIZE); if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); - ret = wc_KyberKey_EncodePrivateKey(key, priv, KYBER512_PRIVATE_KEY_SIZE); + ret = wc_MlKemKey_EncodePrivateKey(key, priv, KYBER512_PRIVATE_KEY_SIZE); if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); @@ -48625,14 +48641,14 @@ static wc_test_ret_t mlkem512_kat(void) #else (void)kyber512_rand; (void)kyber512_pk; - ret = wc_KyberKey_DecodePrivateKey(key, kyber512_sk, + ret = wc_MlKemKey_DecodePrivateKey(key, kyber512_sk, KYBER512_PRIVATE_KEY_SIZE); if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); #endif #ifndef WOLFSSL_MLKEM_NO_ENCAPSULATE - ret = wc_KyberKey_EncapsulateWithRandom(key, ct, ss, kyber512enc_rand, + ret = wc_MlKemKey_EncapsulateWithRandom(key, ct, ss, kyber512enc_rand, sizeof(kyber512enc_rand)); if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); @@ -48647,7 +48663,7 @@ static wc_test_ret_t mlkem512_kat(void) #endif #ifndef WOLFSSL_MLKEM_NO_DECAPSULATE - ret = wc_KyberKey_Decapsulate(key, ss_dec, kyber512_ct, + ret = wc_MlKemKey_Decapsulate(key, ss_dec, kyber512_ct, sizeof(kyber512_ct)); if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); @@ -50060,23 +50076,23 @@ static wc_test_ret_t mlkem768_kat(void) #endif #ifdef WOLFSSL_MLKEM_KYBER - ret = wc_KyberKey_Init(KYBER768, key, HEAP_HINT, katDevId); + ret = wc_MlKemKey_Init(key, KYBER768, HEAP_HINT, katDevId); if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); else key_inited = 1; #ifndef WOLFSSL_MLKEM_NO_MAKE_KEY - ret = wc_KyberKey_MakeKeyWithRandom(key, kyber768_rand, + ret = wc_MlKemKey_MakeKeyWithRandom(key, kyber768_rand, sizeof(kyber768_rand)); if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); - ret = wc_KyberKey_EncodePublicKey(key, pub, KYBER768_PUBLIC_KEY_SIZE); + ret = wc_MlKemKey_EncodePublicKey(key, pub, KYBER768_PUBLIC_KEY_SIZE); if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); - ret = wc_KyberKey_EncodePrivateKey(key, priv, KYBER768_PRIVATE_KEY_SIZE); + ret = wc_MlKemKey_EncodePrivateKey(key, priv, KYBER768_PRIVATE_KEY_SIZE); if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); @@ -50088,14 +50104,14 @@ static wc_test_ret_t mlkem768_kat(void) #else (void)kyber768_rand; (void)kyber768_pk; - ret = wc_KyberKey_DecodePrivateKey(key, kyber768_sk, + ret = wc_MlKemKey_DecodePrivateKey(key, kyber768_sk, KYBER768_PRIVATE_KEY_SIZE); if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); #endif #ifndef WOLFSSL_MLKEM_NO_ENCAPSULATE - ret = wc_KyberKey_EncapsulateWithRandom(key, ct, ss, kyber768enc_rand, + ret = wc_MlKemKey_EncapsulateWithRandom(key, ct, ss, kyber768enc_rand, sizeof(kyber768enc_rand)); if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); @@ -50110,7 +50126,7 @@ static wc_test_ret_t mlkem768_kat(void) #endif #ifndef WOLFSSL_MLKEM_NO_DECAPSULATE - ret = wc_KyberKey_Decapsulate(key, ss_dec, kyber768_ct, + ret = wc_MlKemKey_Decapsulate(key, ss_dec, kyber768_ct, sizeof(kyber768_ct)); if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); @@ -51907,23 +51923,23 @@ static wc_test_ret_t mlkem1024_kat(void) #endif #ifdef WOLFSSL_MLKEM_KYBER - ret = wc_KyberKey_Init(KYBER1024, key, HEAP_HINT, katDevId); + ret = wc_MlKemKey_Init(key, KYBER1024, HEAP_HINT, katDevId); if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); else key_inited = 1; #ifndef WOLFSSL_MLKEM_NO_MAKE_KEY - ret = wc_KyberKey_MakeKeyWithRandom(key, kyber1024_rand, + ret = wc_MlKemKey_MakeKeyWithRandom(key, kyber1024_rand, sizeof(kyber1024_rand)); if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); - ret = wc_KyberKey_EncodePublicKey(key, pub, KYBER_MAX_PUBLIC_KEY_SIZE); + ret = wc_MlKemKey_EncodePublicKey(key, pub, KYBER_MAX_PUBLIC_KEY_SIZE); if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); - ret = wc_KyberKey_EncodePrivateKey(key, priv, KYBER_MAX_PRIVATE_KEY_SIZE); + ret = wc_MlKemKey_EncodePrivateKey(key, priv, KYBER_MAX_PRIVATE_KEY_SIZE); if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); @@ -51935,14 +51951,14 @@ static wc_test_ret_t mlkem1024_kat(void) #else (void)kyber1024_rand; (void)kyber1024_pk; - ret = wc_KyberKey_DecodePrivateKey(key, kyber1024_sk, + ret = wc_MlKemKey_DecodePrivateKey(key, kyber1024_sk, KYBER1024_PRIVATE_KEY_SIZE); if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); #endif #ifndef WOLFSSL_MLKEM_NO_ENCAPSULATE - ret = wc_KyberKey_EncapsulateWithRandom(key, ct, ss, kyber1024enc_rand, + ret = wc_MlKemKey_EncapsulateWithRandom(key, ct, ss, kyber1024enc_rand, sizeof(kyber1024enc_rand)); if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); @@ -51957,7 +51973,7 @@ static wc_test_ret_t mlkem1024_kat(void) #endif #ifndef WOLFSSL_MLKEM_NO_DECAPSULATE - ret = wc_KyberKey_Decapsulate(key, ss_dec, kyber1024_ct, + ret = wc_MlKemKey_Decapsulate(key, ss_dec, kyber1024_ct, sizeof(kyber1024_ct)); if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); @@ -52097,7 +52113,8 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t mlkem_test(void) #endif #endif #endif -#if !defined(WOLFSSL_NO_MALLOC) && !defined(WOLFSSL_MLKEM_NO_MAKE_KEY) +#if !defined(WOLFSSL_NO_MALLOC) && !defined(WC_NO_CONSTRUCTORS) && \ + !defined(WOLFSSL_MLKEM_NO_MAKE_KEY) MlKemKey *tmpKey = NULL; #endif int key_inited = 0; @@ -52285,7 +52302,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t mlkem_test(void) if (XMEMCMP(priv, priv2, testData[i][2]) != 0) ERROR_OUT(WC_TEST_RET_ENC_I(i), out); -#if !defined(WOLFSSL_NO_MALLOC) +#if !defined(WOLFSSL_NO_MALLOC) && !defined(WC_NO_CONSTRUCTORS) tmpKey = wc_MlKemKey_New(testData[i][0], HEAP_HINT, devId); if (tmpKey == NULL) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); @@ -55708,25 +55725,21 @@ static wc_test_ret_t test_mldsa_decode_level(const byte* rawKey, { int ret = 0; #if !defined(WOLFSSL_MLDSA_NO_ASN1) && defined(WOLFSSL_ASN_TEMPLATE) - /* Size the buffer to accommodate the largest encoded key size */ - const word32 maxDerSz = MLDSA_MAX_PRV_KEY_DER_SIZE; word32 derSz; word32 idx; - #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) - byte* der = NULL; - #else - byte der[MLDSA_MAX_PRV_KEY_DER_SIZE]; - #endif #endif #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) + byte* der = NULL; wc_MlDsaKey *key = NULL; #else + byte der[MLDSA_MAX_PRV_KEY_DER_SIZE]; wc_MlDsaKey key[1]; #endif #if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC) /* Allocate DER buffer */ - der = (byte*)XMALLOC(maxDerSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + der = (byte*)XMALLOC(MLDSA_MAX_PRV_KEY_DER_SIZE, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER); key = (wc_MlDsaKey *)XMALLOC(sizeof(*key), HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); if (der == NULL || key == NULL) { @@ -55762,12 +55775,14 @@ static wc_test_ret_t test_mldsa_decode_level(const byte* rawKey, if (ret == 0) { #ifdef WOLFSSL_MLDSA_PUBLIC_KEY if (isPublicOnlyKey) { - ret = wc_MlDsaKey_PublicKeyToDer(key, der, maxDerSz, 1); + ret = wc_MlDsaKey_PublicKeyToDer(key, der, + MLDSA_MAX_PRV_KEY_DER_SIZE, 1); } #endif #ifdef WOLFSSL_MLDSA_PRIVATE_KEY if (!isPublicOnlyKey) { - ret = wc_MlDsaKey_PrivateKeyToDer(key, der, maxDerSz); + ret = wc_MlDsaKey_PrivateKeyToDer(key, der, + MLDSA_MAX_PRV_KEY_DER_SIZE); } #endif if (ret >= 0) { @@ -73290,6 +73305,15 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx) /* set devId to invalid, so software is used */ info->hash.sha384->devId = INVALID_DEVID; #endif + #if defined(WOLF_CRYPTO_CB_ONLY_SHA512) + #ifdef DEBUG_WOLFSSL + printf("CryptoDevCb: exampleVar %d\n", myCtx->exampleVar); + #endif + if (myCtx->exampleVar == 99) { + info->hash.sha384->devId = devIdArg; + return 0; + } + #endif if (info->hash.in != NULL) { ret = wc_Sha384Update( @@ -73319,6 +73343,15 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx) /* set devId to invalid, so software is used */ info->hash.sha512->devId = INVALID_DEVID; #endif + #if defined(WOLF_CRYPTO_CB_ONLY_SHA512) + #ifdef DEBUG_WOLFSSL + printf("CryptoDevCb: exampleVar %d\n", myCtx->exampleVar); + #endif + if (myCtx->exampleVar == 99) { + info->hash.sha512->devId = devIdArg; + return 0; + } + #endif if (info->hash.in != NULL) { ret = wc_Sha512Update( @@ -74502,6 +74535,18 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cryptocb_test(void) #ifdef WOLFSSL_SHA512 if (ret == 0) ret = sha512_test(); +#if !defined(WOLFSSL_NOSHA512_224) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5, 3)) && !defined(HAVE_SELFTEST) + /* exercises the SHA-512/224 fallback to the generic SHA-512 callback, + * including object reuse after Final */ + if (ret == 0) + ret = sha512_224_test(); +#endif +#if !defined(WOLFSSL_NOSHA512_256) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5, 3)) && !defined(HAVE_SELFTEST) + if (ret == 0) + ret = sha512_256_test(); +#endif #ifdef WOLFSSL_SHA3 if (ret == 0) ret = sha3_test(); diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 794808f38b..b7969241f0 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -3114,6 +3114,7 @@ typedef struct RpkState { #if defined(WOLFSSL_TLS13) && defined(HAVE_ECH) #define ECH_ACCEPT_CONFIRMATION_SZ 8 +#define ECH_PADDING_TO_32(length) (31 - (((length) - 1) % 32)) typedef enum { ECH_TYPE_OUTER = 0, @@ -3181,7 +3182,8 @@ typedef struct WOLFSSL_ECH { WOLFSSL_LOCAL int EchConfigGetSupportedCipherSuite(WOLFSSL_EchConfig* config); -WOLFSSL_LOCAL int TLSX_FinalizeEch(WOLFSSL_ECH* ech, byte* aad, word32 aadLen); +WOLFSSL_LOCAL int TLSX_FinalizeEch(WOLFSSL* ssl, WOLFSSL_ECH* ech, byte* aad, + word32 aadLen); WOLFSSL_LOCAL int SetEchConfigsEx(WOLFSSL_EchConfig** outputConfigs, void* heap, @@ -3462,11 +3464,16 @@ typedef struct PointFormat { WOLFSSL_LOCAL int TLSX_SupportedCurve_Copy(TLSX* src, TLSX** dst, void* heap); WOLFSSL_LOCAL int TLSX_UseSupportedCurve(TLSX** extensions, word16 name, - void* heap); + void* heap, int side); -WOLFSSL_LOCAL int TLSX_UsePointFormat(TLSX** extensions, byte point, +#ifdef WOLFSSL_API_PREFIX_MAP + #define TLSX_UsePointFormat wolfSSL_TLSX_UsePointFormat +#endif +/* WOLFSSL_TEST_VIS so the API tests can seed a client's ec_point_formats + * extension (the point-format negotiation has no public API). */ +WOLFSSL_TEST_VIS int TLSX_UsePointFormat(TLSX** extensions, byte point, void* heap); -WOLFSSL_LOCAL int TLSX_IsGroupSupported(int namedGroup); +WOLFSSL_LOCAL int TLSX_IsGroupSupported(int namedGroup, int side); #ifndef NO_WOLFSSL_SERVER WOLFSSL_LOCAL int TLSX_ValidateSupportedCurves(const WOLFSSL* ssl, byte first, @@ -4528,6 +4535,10 @@ enum ClientCertificateType { mldsa_sign = 68, }; +/* Maximum number of ClientCertificateType bytes the server emits in a + * CertificateRequest. Currently rsa_sign and ecdsa_sign. */ +#define MAX_CERT_REQ_CERT_TYPE_CNT 2 + #ifndef WOLFSSL_AEAD_ONLY enum CipherType { stream, block, aead }; @@ -5191,6 +5202,8 @@ struct Options { #endif /* WOLFSSL_DTLS */ #if defined(HAVE_TLS_EXTENSIONS) && defined(HAVE_SUPPORTED_CURVES) word16 userCurves:1; /* indicates user called wolfSSL_UseSupportedCurve */ + word16 peerNoUncompPF:1; /* peer sent ec_point_formats without + * the uncompressed (0) format */ #endif word16 keepResources:1; /* Keep resources after handshake */ word16 useClientOrder:1; /* Use client's cipher order */ @@ -5948,6 +5961,13 @@ enum { DTLS13_EPOCH_TRAFFIC0 = 3 }; +/* Sender-side DTLS 1.3 epoch ceiling: we MUST NOT advance our own epoch past + * 2^48-1 (RFC 9147 Section 4.2.1). This gates only the sending epoch; receivers + * MUST NOT enforce it on the peer epoch (RFC 9147 Section 8). Expressed as the + * high/low 32-bit halves of a w64wrapper. */ +#define DTLS13_EPOCH_MAX_HI32 0x0000FFFFU +#define DTLS13_EPOCH_MAX_LO32 0xFFFFFFFFU + /* 64-bit epoch + 64-bit sequence number */ #define DTLS13_RN_SIZE (OPAQUE64_LEN + OPAQUE64_LEN) /* Maximum number of ACK records allowed in an ACK message */ @@ -6615,6 +6635,10 @@ struct WOLFSSL { #endif #endif #endif + /* Cached BuildMessage(sizeOnly) overhead (recordSz - payloadSz) for AEAD + * ciphers; 0 means uncached and is never a valid AEAD overhead. EtM does + * not apply to AEAD. */ + word32 recordSzOverhead; }; #if defined(WOLFSSL_SYS_CRYPTO_POLICY) @@ -6829,9 +6853,21 @@ WOLFSSL_LOCAL int DoClientTicket_ex(const WOLFSSL* ssl, PreSharedKey* psk, #endif WOLFSSL_LOCAL int DoClientTicket(WOLFSSL* ssl, const byte* input, word32 len); +/* TicketSniHash, TicketAlpnHash, and VerifyTicketBinding are defined in + * internal.c only when !NO_WOLFSSL_SERVER && !NO_TLS - gate the + * declarations to match so client-only or no-TLS builds don't compile in + * call sites that would fail to link. */ +#if !defined(NO_WOLFSSL_SERVER) && !defined(NO_TLS) +#ifdef HAVE_SNI +WOLFSSL_LOCAL int TicketSniHash(WOLFSSL* ssl, byte* dst); +#endif +#ifdef HAVE_ALPN +WOLFSSL_LOCAL int TicketAlpnHash(WOLFSSL* ssl, byte* dst); +#endif #if defined(HAVE_SNI) || defined(HAVE_ALPN) WOLFSSL_LOCAL int VerifyTicketBinding(WOLFSSL* ssl); #endif +#endif /* !NO_WOLFSSL_SERVER && !NO_TLS */ #endif /* HAVE_SESSION_TICKET */ WOLFSSL_LOCAL int SendData(WOLFSSL* ssl, const void* data, size_t sz); #ifdef WOLFSSL_THREADED_CRYPT @@ -6889,7 +6925,7 @@ WOLFSSL_LOCAL int VerifyClientSuite(word16 havePSK, byte cipherSuite0, byte cipherSuite); WOLFSSL_LOCAL int SetTicket(WOLFSSL* ssl, const byte* ticket, word32 length); -WOLFSSL_LOCAL int wolfssl_local_GetRecordSize(WOLFSSL *ssl, int payloadSz, +WOLFSSL_TEST_VIS int wolfssl_local_GetRecordSize(WOLFSSL *ssl, int payloadSz, int isEncrypted); WOLFSSL_LOCAL int wolfssl_local_GetMaxPlaintextSize(WOLFSSL *ssl); WOLFSSL_LOCAL int wolfSSL_GetMaxFragSize(WOLFSSL* ssl); @@ -7180,8 +7216,12 @@ typedef struct CipherSuiteInfo { byte flags; } CipherSuiteInfo; -WOLFSSL_LOCAL const CipherSuiteInfo* GetCipherNames(void); -WOLFSSL_LOCAL int GetCipherNamesSize(void); +#ifdef WOLFSSL_API_PREFIX_MAP + #define GetCipherNames wolfSSL_GetCipherNames + #define GetCipherNamesSize wolfSSL_GetCipherNamesSize +#endif +WOLFSSL_TEST_VIS const CipherSuiteInfo* GetCipherNames(void); +WOLFSSL_TEST_VIS int GetCipherNamesSize(void); WOLFSSL_LOCAL const char* GetCipherNameInternal(byte cipherSuite0, byte cipherSuite); #if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) /* used in wolfSSL_sk_CIPHER_description */ @@ -7261,7 +7301,10 @@ WOLFSSL_LOCAL int InitHandshakeHashesAndCopy(WOLFSSL* ssl, HS_Hashes* source, #ifndef WOLFSSL_NO_TLS12 WOLFSSL_LOCAL void FreeBuildMsgArgs(WOLFSSL* ssl, BuildMsgArgs* args); #endif -WOLFSSL_LOCAL int BuildMessage(WOLFSSL* ssl, byte* output, int outSz, +#ifdef WOLFSSL_API_PREFIX_MAP + #define BuildMessage wolfSSL_BuildMessage +#endif +WOLFSSL_TEST_VIS int BuildMessage(WOLFSSL* ssl, byte* output, int outSz, const byte* input, int inSz, int type, int hashOutput, int sizeOnly, int asyncOkay, int epochOrder); diff --git a/wolfssl/ocsp.h b/wolfssl/ocsp.h index 8778a144ec..103475c0b8 100644 --- a/wolfssl/ocsp.h +++ b/wolfssl/ocsp.h @@ -76,7 +76,7 @@ WOLFSSL_LOCAL int CheckOcspResponse(WOLFSSL_OCSP *ocsp, byte *response, int resp WOLFSSL_LOCAL int CheckOcspResponder(OcspResponse *bs, byte* subjectNameHash, byte* subjectKeyHash, byte extExtKeyUsage, byte* issuerNameHash, - byte* issuerKeyHash, void* vp); + byte* issuerKeyHash); /* Allocates and initializes a WOLFSSL_OCSP object */ WOLFSSL_API WOLFSSL_OCSP* wc_NewOCSP(WOLFSSL_CERT_MANAGER* cm); diff --git a/wolfssl/openssl/rc4.h b/wolfssl/openssl/rc4.h index c53c47b6b6..53168c6f81 100644 --- a/wolfssl/openssl/rc4.h +++ b/wolfssl/openssl/rc4.h @@ -40,9 +40,9 @@ typedef struct WOLFSSL_RC4_KEY { /* big enough for Arc4 from wolfssl/wolfcrypt/arc4.h */ #ifdef WC_NO_PTR_INT_CAST - void* holder[(288 + WC_ASYNC_DEV_SIZE) / sizeof(void*)]; + void* holder[(296 + WC_ASYNC_DEV_SIZE) / sizeof(void*)]; #else - void* holder[(272 + WC_ASYNC_DEV_SIZE) / sizeof(void*)]; + void* holder[(280 + WC_ASYNC_DEV_SIZE) / sizeof(void*)]; #endif } WOLFSSL_RC4_KEY; diff --git a/wolfssl/openssl/sha.h b/wolfssl/openssl/sha.h index 1b863b17e9..e8a1678a14 100644 --- a/wolfssl/openssl/sha.h +++ b/wolfssl/openssl/sha.h @@ -254,8 +254,10 @@ WOLFSSL_API int wolfSSL_SHA512_Init(WOLFSSL_SHA512_CTX* sha); WOLFSSL_API int wolfSSL_SHA512_Update(WOLFSSL_SHA512_CTX* sha, const void* input, unsigned long sz); WOLFSSL_API int wolfSSL_SHA512_Final(byte* output, WOLFSSL_SHA512_CTX* sha); +#ifndef WOLF_CRYPTO_CB_ONLY_SHA512 /* no underlying wc_Sha512Transform */ WOLFSSL_API int wolfSSL_SHA512_Transform(WOLFSSL_SHA512_CTX* sha512, const unsigned char* data); +#endif #if !defined(OPENSSL_COEXIST) && (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) enum { SHA512_DIGEST_LENGTH = 64 @@ -266,7 +268,9 @@ typedef WOLFSSL_SHA512_CTX SHA512_CTX; #define SHA512_Init wolfSSL_SHA512_Init #define SHA512_Update wolfSSL_SHA512_Update #define SHA512_Final wolfSSL_SHA512_Final +#ifndef WOLF_CRYPTO_CB_ONLY_SHA512 /* no underlying wc_Sha512Transform */ #define SHA512_Transform wolfSSL_SHA512_Transform +#endif #if defined(NO_OLD_SHA_NAMES) && !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) /* SHA512 is only available in non-fips mode because of SHA512 enum in FIPS * build. */ @@ -283,14 +287,18 @@ WOLFSSL_API int wolfSSL_SHA512_224_Update(WOLFSSL_SHA512_224_CTX* sha, const void* input, unsigned long sz); WOLFSSL_API int wolfSSL_SHA512_224_Final(byte* output, WOLFSSL_SHA512_224_CTX* sha); +#ifndef WOLF_CRYPTO_CB_ONLY_SHA512 /* no underlying wc_Sha512_224Transform */ WOLFSSL_API int wolfSSL_SHA512_224_Transform(WOLFSSL_SHA512_CTX* sha512, const unsigned char* data); +#endif #if !defined(OPENSSL_COEXIST) && (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) #define SHA512_224_Init wolfSSL_SHA512_224_Init #define SHA512_224_Update wolfSSL_SHA512_224_Update #define SHA512_224_Final wolfSSL_SHA512_224_Final +#ifndef WOLF_CRYPTO_CB_ONLY_SHA512 /* no underlying wc_Sha512_224Transform */ #define SHA512_224_Transform wolfSSL_SHA512_224_Transform +#endif #if defined(NO_OLD_SHA_NAMES) && !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) #define SHA512_224 wolfSSL_SHA512_224 @@ -306,14 +314,18 @@ WOLFSSL_API int wolfSSL_SHA512_256_Init(WOLFSSL_SHA512_CTX* sha); WOLFSSL_API int wolfSSL_SHA512_256_Update(WOLFSSL_SHA512_256_CTX* sha, const void* input, unsigned long sz); WOLFSSL_API int wolfSSL_SHA512_256_Final(byte* output, WOLFSSL_SHA512_256_CTX* sha); +#ifndef WOLF_CRYPTO_CB_ONLY_SHA512 /* no underlying wc_Sha512_256Transform */ WOLFSSL_API int wolfSSL_SHA512_256_Transform(WOLFSSL_SHA512_CTX* sha512, const unsigned char* data); +#endif #if !defined(OPENSSL_COEXIST) && (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) #define SHA512_256_Init wolfSSL_SHA512_256_Init #define SHA512_256_Update wolfSSL_SHA512_256_Update #define SHA512_256_Final wolfSSL_SHA512_256_Final +#ifndef WOLF_CRYPTO_CB_ONLY_SHA512 /* no underlying wc_Sha512_256Transform */ #define SHA512_256_Transform wolfSSL_SHA512_256_Transform +#endif #if defined(NO_OLD_SHA_NAMES) && !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) #define SHA512_256 wolfSSL_SHA512_256 diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 2281bb2f26..713c5a55c0 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -1076,7 +1076,11 @@ enum Tls13Secret { CLIENT_TRAFFIC_SECRET, SERVER_TRAFFIC_SECRET, EARLY_EXPORTER_SECRET, - EXPORTER_SECRET + EXPORTER_SECRET, +#if defined(HAVE_ECH) + ECH_SECRET, + ECH_CONFIG, +#endif }; #endif @@ -2545,13 +2549,52 @@ WOLFSSL_API WOLFSSL_ASN1_INTEGER* wolfSSL_d2i_ASN1_INTEGER( WOLFSSL_API int wolfSSL_i2d_ASN1_INTEGER(const WOLFSSL_ASN1_INTEGER* a, unsigned char** pp); -WOLFSSL_API int wolfSSL_ASN1_TIME_print(WOLFSSL_BIO* bio, const WOLFSSL_ASN1_TIME* asnTime); +/* ASN1_TIME APIs */ +/* These ASN1_TIME APIs operate only on the object's stored data and do not + * use system time, so they remain available when NO_ASN_TIME is defined. */ +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) +WOLFSSL_API int wolfSSL_ASN1_TIME_get_length(const WOLFSSL_ASN1_TIME *t); +WOLFSSL_API unsigned char* wolfSSL_ASN1_TIME_get_data(const WOLFSSL_ASN1_TIME *t); +WOLFSSL_API WOLFSSL_ASN1_TIME *wolfSSL_ASN1_TIME_to_generalizedtime(WOLFSSL_ASN1_TIME *t, + WOLFSSL_ASN1_TIME **out); +#endif +#ifdef OPENSSL_EXTRA +WOLFSSL_API WOLFSSL_ASN1_TIME* wolfSSL_ASN1_TIME_new(void); +WOLFSSL_API void wolfSSL_ASN1_TIME_free(WOLFSSL_ASN1_TIME* t); +WOLFSSL_API WOLFSSL_ASN1_TIME *wolfSSL_ASN1_TIME_set(WOLFSSL_ASN1_TIME *s, time_t t); +WOLFSSL_API int wolfSSL_ASN1_TIME_set_string(WOLFSSL_ASN1_TIME *s, const char *str); +#endif + +/* These ASN1_TIME APIs use system time or call APIs that are disabled when + * NO_ASN_TIME is defined. */ +#ifndef NO_ASN_TIME +WOLFSSL_API int wolfSSL_ASN1_TIME_print(WOLFSSL_BIO* bio, + const WOLFSSL_ASN1_TIME* asnTime); WOLFSSL_API char* wolfSSL_ASN1_TIME_to_string(WOLFSSL_ASN1_TIME* t, char* buf, int len); -#ifndef NO_ASN_TIME -WOLFSSL_API int wolfSSL_ASN1_TIME_to_tm(const WOLFSSL_ASN1_TIME* asnTime, struct tm* tm); +WOLFSSL_API int wolfSSL_ASN1_TIME_to_tm(const WOLFSSL_ASN1_TIME* asnTime, + struct tm* tm); + +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) +WOLFSSL_API WOLFSSL_ASN1_TIME* wolfSSL_ASN1_UTCTIME_set(WOLFSSL_ASN1_TIME *s, + time_t t); #endif + +#ifdef OPENSSL_EXTRA +WOLFSSL_API WOLFSSL_ASN1_TIME* wolfSSL_ASN1_TIME_adj(WOLFSSL_ASN1_TIME* s, + time_t t, int offset_day, + long offset_sec); +WOLFSSL_API int wolfSSL_ASN1_TIME_check(const WOLFSSL_ASN1_TIME* a); +WOLFSSL_API int wolfSSL_ASN1_TIME_diff(int* days, int* secs, const WOLFSSL_ASN1_TIME* from, + const WOLFSSL_ASN1_TIME* to); +WOLFSSL_API int wolfSSL_ASN1_TIME_compare(const WOLFSSL_ASN1_TIME *a, + const WOLFSSL_ASN1_TIME *b); +WOLFSSL_API int wolfSSL_ASN1_TIME_set_string_X509(WOLFSSL_ASN1_TIME *t, + const char *str); +#endif +#endif /* !NO_ASN_TIME */ + WOLFSSL_API int wolfSSL_ASN1_INTEGER_cmp(const WOLFSSL_ASN1_INTEGER* a, const WOLFSSL_ASN1_INTEGER* b); WOLFSSL_API long wolfSSL_ASN1_INTEGER_get(const WOLFSSL_ASN1_INTEGER* a); @@ -2559,10 +2602,6 @@ WOLFSSL_API long wolfSSL_ASN1_INTEGER_get(const WOLFSSL_ASN1_INTEGER* a); #ifdef OPENSSL_EXTRA WOLFSSL_API WOLFSSL_BIGNUM *wolfSSL_ASN1_INTEGER_to_BN(const WOLFSSL_ASN1_INTEGER *ai, WOLFSSL_BIGNUM *bn); -WOLFSSL_API WOLFSSL_ASN1_TIME* wolfSSL_ASN1_TIME_adj(WOLFSSL_ASN1_TIME* s, time_t t, - int offset_day, long offset_sec); -WOLFSSL_API WOLFSSL_ASN1_TIME* wolfSSL_ASN1_TIME_new(void); -WOLFSSL_API void wolfSSL_ASN1_TIME_free(WOLFSSL_ASN1_TIME* t); #endif WOLFSSL_API WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_load_client_CA_file(const char* fname); @@ -2732,6 +2771,7 @@ enum { WOLFSSL_X509_V_ERR_PATH_LENGTH_EXCEEDED = 25, WOLFSSL_X509_V_ERR_CERT_REJECTED = 28, WOLFSSL_X509_V_ERR_SUBJECT_ISSUER_MISMATCH = 29, + WOLFSSL_X509_V_ERR_APPLICATION_VERIFICATION = 50, WOLFSSL_X509_V_ERR_HOSTNAME_MISMATCH = 62, WOLFSSL_X509_V_ERR_IP_ADDRESS_MISMATCH = 64, WOLFSSL_X509_V_ERR_INVALID_CA = 79, @@ -3369,15 +3409,6 @@ WOLFSSL_API int wolfSSL_ASN1_UTCTIME_print(WOLFSSL_BIO* bio, WOLFSSL_API int wolfSSL_ASN1_GENERALIZEDTIME_print(WOLFSSL_BIO* bio, const WOLFSSL_ASN1_GENERALIZEDTIME* asnTime); WOLFSSL_API void wolfSSL_ASN1_GENERALIZEDTIME_free(WOLFSSL_ASN1_GENERALIZEDTIME*); -WOLFSSL_API int wolfSSL_ASN1_TIME_check(const WOLFSSL_ASN1_TIME* a); -WOLFSSL_API int wolfSSL_ASN1_TIME_diff(int* days, int* secs, const WOLFSSL_ASN1_TIME* from, - const WOLFSSL_ASN1_TIME* to); -WOLFSSL_API int wolfSSL_ASN1_TIME_compare(const WOLFSSL_ASN1_TIME *a, - const WOLFSSL_ASN1_TIME *b); -WOLFSSL_API WOLFSSL_ASN1_TIME *wolfSSL_ASN1_TIME_set(WOLFSSL_ASN1_TIME *s, time_t t); -WOLFSSL_API int wolfSSL_ASN1_TIME_set_string(WOLFSSL_ASN1_TIME *s, const char *str); -WOLFSSL_API int wolfSSL_ASN1_TIME_set_string_X509(WOLFSSL_ASN1_TIME *t, - const char *str); #endif /* OPENSSL_EXTRA */ @@ -6091,11 +6122,6 @@ WOLFSSL_API void wolfSSL_EC_POINT_dump(const char *msg, const WOLFSSL_EC_POINT * WOLFSSL_API const char *wolfSSL_ASN1_tag2str(int tag); WOLFSSL_API int wolfSSL_ASN1_STRING_print_ex(WOLFSSL_BIO *out, WOLFSSL_ASN1_STRING *str, unsigned long flags); WOLFSSL_API int wolfSSL_ASN1_STRING_print(WOLFSSL_BIO *out, WOLFSSL_ASN1_STRING *str); -WOLFSSL_API int wolfSSL_ASN1_TIME_get_length(const WOLFSSL_ASN1_TIME *t); -WOLFSSL_API unsigned char* wolfSSL_ASN1_TIME_get_data(const WOLFSSL_ASN1_TIME *t); -WOLFSSL_API WOLFSSL_ASN1_TIME *wolfSSL_ASN1_TIME_to_generalizedtime(WOLFSSL_ASN1_TIME *t, - WOLFSSL_ASN1_TIME **out); -WOLFSSL_API WOLFSSL_ASN1_TIME* wolfSSL_ASN1_UTCTIME_set(WOLFSSL_ASN1_TIME *s, time_t t); WOLFSSL_API int wolfSSL_i2c_ASN1_INTEGER(WOLFSSL_ASN1_INTEGER *a, unsigned char **pp); WOLFSSL_API int wolfSSL_a2i_ASN1_INTEGER(WOLFSSL_BIO *bio, WOLFSSL_ASN1_INTEGER *asn1, char *buf, int size); diff --git a/wolfssl/wolfcrypt/arc4.h b/wolfssl/wolfcrypt/arc4.h index 041ee71213..059014d544 100644 --- a/wolfssl/wolfcrypt/arc4.h +++ b/wolfssl/wolfcrypt/arc4.h @@ -51,6 +51,7 @@ typedef struct Arc4 { WC_ASYNC_DEV asyncDev; #endif void* heap; + WC_BITFIELD keySet:1; /* set to 1 once a key has been configured */ } Arc4; WOLFSSL_API int wc_Arc4Process(Arc4* arc4, byte* out, const byte* in, diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index 70f823fc80..8c82294d12 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -1541,7 +1541,9 @@ struct SignatureCtx { #endif #if !defined(NO_RSA) || !defined(NO_DSA) #ifdef WOLFSSL_NO_MALLOC - byte sigCpy[MAX_ENCODED_SIG_SZ]; + /* Holds a copy of the RSA/DSA signature being verified, which is at most + * an RSA-modulus-sized value -- never a (much larger) PQC signature. */ + byte sigCpy[MAX_ENCODED_CLASSIC_SIG_SZ]; #else byte* sigCpy; #endif @@ -2773,7 +2775,10 @@ enum cert_enums { SLH_DSA_SHAKE_192S_KEY = 32, SLH_DSA_SHAKE_192F_KEY = 33, SLH_DSA_SHAKE_256S_KEY = 34, - SLH_DSA_SHAKE_256F_KEY = 35 + SLH_DSA_SHAKE_256F_KEY = 35, + LMS_KEY = 36, + XMSS_KEY = 37, + XMSSMT_KEY = 38 }; #ifndef WOLFSSL_NO_DILITHIUM_LEGACY_NAMES diff --git a/wolfssl/wolfcrypt/asn_public.h b/wolfssl/wolfcrypt/asn_public.h index 4fd5f7ba27..1c6bfc3853 100644 --- a/wolfssl/wolfcrypt/asn_public.h +++ b/wolfssl/wolfcrypt/asn_public.h @@ -99,6 +99,14 @@ This library defines the interface APIs for X509 certificates. typedef struct SlhDsaKey SlhDsaKey; #define WC_SLHDSAKEY_TYPE_DEFINED #endif +#ifndef WC_LMSKEY_TYPE_DEFINED + typedef struct LmsKey LmsKey; + #define WC_LMSKEY_TYPE_DEFINED +#endif +#ifndef WC_XMSSKEY_TYPE_DEFINED + typedef struct XmssKey XmssKey; + #define WC_XMSSKEY_TYPE_DEFINED +#endif enum EncPkcs8Types { ENC_PKCS8_VER_PKCS12 = 1, @@ -172,7 +180,10 @@ enum CertType { ECC_PARAM_TYPE, CHAIN_CERT_TYPE, PKCS7_TYPE, - TRUSTED_CERT_TYPE + TRUSTED_CERT_TYPE, + LMS_TYPE, + XMSS_TYPE, + XMSSMT_TYPE }; #ifndef WOLFSSL_NO_DILITHIUM_LEGACY_NAMES diff --git a/wolfssl/wolfcrypt/des3.h b/wolfssl/wolfcrypt/des3.h index 4ff912fc8b..117abeb97f 100644 --- a/wolfssl/wolfcrypt/des3.h +++ b/wolfssl/wolfcrypt/des3.h @@ -113,6 +113,7 @@ struct Des3 { void* devCtx; #endif void* heap; + WC_BITFIELD keySet:1; /* set to 1 once a key has been configured */ }; #ifndef WC_DES3_TYPE_DEFINED diff --git a/wolfssl/wolfcrypt/hpke.h b/wolfssl/wolfcrypt/hpke.h index c71619ccf7..6b1f75edee 100644 --- a/wolfssl/wolfcrypt/hpke.h +++ b/wolfssl/wolfcrypt/hpke.h @@ -96,6 +96,9 @@ typedef struct { word16 aead; byte kem_suite_id[KEM_SUITE_ID_LEN]; byte hpke_suite_id[HPKE_SUITE_ID_LEN]; +#if defined(HAVE_SECRET_CALLBACK) && defined(HAVE_ECH) + byte* echSecret; +#endif } Hpke; typedef struct { @@ -135,6 +138,11 @@ WOLFSSL_LOCAL int wc_HpkeKemIsSupported(word16 kemId); WOLFSSL_LOCAL int wc_HpkeKdfIsSupported(word16 kdfId); WOLFSSL_LOCAL int wc_HpkeAeadIsSupported(word16 aeadId); +#if defined(HAVE_SECRET_CALLBACK) && defined(HAVE_ECH) +WOLFSSL_LOCAL int wc_HpkeInitEchSecret(Hpke* hpke); +WOLFSSL_LOCAL void wc_HpkeFreeEchSecret(Hpke* hpke); +#endif + #endif #endif /* HAVE_HPKE && (HAVE_ECC || HAVE_CURVE25519) && HAVE_AESGCM */ diff --git a/wolfssl/wolfcrypt/integer.h b/wolfssl/wolfcrypt/integer.h index 7e4792a6d5..3773c290bb 100644 --- a/wolfssl/wolfcrypt/integer.h +++ b/wolfssl/wolfcrypt/integer.h @@ -213,6 +213,10 @@ typedef int mp_err; /* Type to cast to when using size marcos. */ #define MP_INT_SIZE mp_int +/* integer.h allocates full-sized mp_int buffers, so DECL_MP_INT_SIZE_DYN + * cannot be undersized for any 'bits' value -- no check is needed. */ +#define MP_BITS_OVER_MAX(bits, max) 0 + #ifdef HAVE_WOLF_BIGINT /* raw big integer */ typedef struct WC_BIGINT { diff --git a/wolfssl/wolfcrypt/port/maxim/max3266x.h b/wolfssl/wolfcrypt/port/maxim/max3266x.h index 9acc799c75..67c5c2fe39 100644 --- a/wolfssl/wolfcrypt/port/maxim/max3266x.h +++ b/wolfssl/wolfcrypt/port/maxim/max3266x.h @@ -57,13 +57,16 @@ #endif #endif -/* Enable copy/free callbacks when using callback mode */ +/* Enable copy callback when using callback mode (SHA Copy needs it) */ #if defined(MAX3266X_SHA_CB) #ifndef WOLF_CRYPTO_CB_COPY #define WOLF_CRYPTO_CB_COPY #endif - #ifndef WOLF_CRYPTO_CB_FREE - #define WOLF_CRYPTO_CB_FREE + /* One-shot mode buffers the whole message, so Free is needed too */ + #ifdef WOLFSSL_MAX3266X_SHA_ONESHOT + #ifndef WOLF_CRYPTO_CB_FREE + #define WOLF_CRYPTO_CB_FREE + #endif #endif #endif @@ -246,6 +249,20 @@ #if defined(MAX3266X_SHA) || defined(MAX3266X_SHA_CB) + #if defined(WOLFSSL_SHA512) + /* Does not support these SHA512 Macros */ + #ifndef WOLFSSL_NOSHA512_224 + #warning "MAX3266X Port does not support SHA-512/224" + #define WOLFSSL_NOSHA512_224 + #endif + #ifndef WOLFSSL_NOSHA512_256 + #warning "MAX3266X Port does not support SHA-512/256" + #define WOLFSSL_NOSHA512_256 + #endif + #endif /* WOLFSSL_SHA512 */ + +#ifdef WOLFSSL_MAX3266X_SHA_ONESHOT + /* Use HASH_KEEP to accumulate message data for one-shot TPU hardware */ #ifndef WOLFSSL_HASH_KEEP #define WOLFSSL_HASH_KEEP @@ -293,16 +310,6 @@ #endif /* WOLFSSL_SHA384 */ #if defined(WOLFSSL_SHA512) - /* Does not support these SHA512 Macros */ - #ifndef WOLFSSL_NOSHA512_224 - #warning "MAX3266X Port does not support SHA-512/224" - #define WOLFSSL_NOSHA512_224 - #endif - #ifndef WOLFSSL_NOSHA512_256 - #warning "MAX3266X Port does not support SHA-512/256" - #define WOLFSSL_NOSHA512_256 - #endif - /* Define the SHA-512 digest for an empty string */ /* as a constant byte array */ static const unsigned char MXC_EMPTY_DIGEST_SHA512[64] = { @@ -354,6 +361,54 @@ unsigned char* digest, MXC_TPU_HASH_TYPE algo); +#else /* WOLFSSL_MAX3266X_SHA_ONESHOT */ + + /* Number of HASH_DIGEST register words for each algorithm's state */ + #define MXC_SHA1_STATE_WORDS 5 /* 160-bit state */ + #define MXC_SHA224_STATE_WORDS 8 /* 256-bit internal state */ + #define MXC_SHA256_STATE_WORDS 8 /* 256-bit state */ + #define MXC_SHA384_STATE_WORDS 16 /* 512-bit internal state (word32) */ + #define MXC_SHA512_STATE_WORDS 16 /* 512-bit state (word32) */ + + /* TPU hash helpers - bare-metal SHA acceleration */ + WOLFSSL_LOCAL void wc_MXC_TPU_Hash_Setup(MXC_TPU_HASH_TYPE algo, + const unsigned int* state, int stateWords); + WOLFSSL_LOCAL void wc_MXC_TPU_Hash_Feed_Block(const unsigned char* data, + unsigned int blockSz); + WOLFSSL_LOCAL void wc_MXC_TPU_Hash_Feed_Last(const unsigned char* data, + unsigned int dataLen, + unsigned int totalLenLo, + unsigned int totalLenHi); + WOLFSSL_LOCAL void wc_MXC_TPU_Hash_Save_State(unsigned int* state, + int stateWords); + WOLFSSL_LOCAL void wc_MXC_TPU_Hash_Read_Digest(unsigned char* digest, + unsigned int digestSz); + + /* Generic SHA Update/Final/GetHash */ + WOLFSSL_LOCAL int wc_MXC_TPU_SHA_Update(unsigned int* digest, + unsigned int* buffer, + unsigned int* buffLen, + unsigned int* loLen, unsigned int* hiLen, + int stateWords, unsigned int blockSz, + MXC_TPU_HASH_TYPE algo, + const unsigned char* data, + unsigned int len); + WOLFSSL_LOCAL int wc_MXC_TPU_SHA_Final(unsigned int* digest, + unsigned int* buffer, + unsigned int* buffLen, + unsigned int loLen, unsigned int hiLen, + int stateWords, unsigned int digestSz, + MXC_TPU_HASH_TYPE algo, + unsigned char* hash); + WOLFSSL_LOCAL int wc_MXC_TPU_SHA_GetHash(unsigned int* digest, + unsigned int* buffer, + unsigned int buffLen, + unsigned int loLen, unsigned int hiLen, + int stateWords, unsigned int digestSz, + MXC_TPU_HASH_TYPE algo, + unsigned char* hash); + +#endif /* WOLFSSL_MAX3266X_SHA_ONESHOT */ #endif /* defined(MAX3266X_SHA) || defined(MAX3266X_SHA_CB) */ diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index e7d9b568f6..e574273d74 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -1189,6 +1189,19 @@ /* settings in user_settings.h */ #endif +#if defined(WOLFSSL_RENESAS_RSIP) && !defined(NO_WOLFSSL_RENESAS_FSPSM_HASH) + /* The Renesas FSPSM hash context has no software digest[] state field and + * the device computes each SHA-512 variant (SHA-384, SHA-512/224, + * SHA-512/256) natively. Disable the cryptocb fallback that reuses the + * generic SHA-512 callback for the variants: it relies on a digest[] IV in + * the context (absent here, so it would not compile) and assumes the + * backend exposes its hash state, which a device that keeps state + * internally does not. */ + #ifndef WOLF_CRYPTO_CB_NO_SHA512_FALLBACK + #define WOLF_CRYPTO_CB_NO_SHA512_FALLBACK + #endif +#endif + #if defined(WOLFSSL_LWIP_NATIVE) || \ defined(HAVE_LWIP_NATIVE) /* using LwIP native TCP socket */ #undef WOLFSSL_USER_IO @@ -1539,18 +1552,17 @@ #endif #if defined(WOLFSSL_uITRON4) + #define XMALLOC_USER + #include + #define ITRON_POOL_SIZE 1024*20 + extern int uITRON4_minit(size_t poolsz) ; + extern void *uITRON4_malloc(size_t sz) ; + extern void *uITRON4_realloc(void *p, size_t sz) ; + extern void uITRON4_free(void *p) ; -#define XMALLOC_USER -#include -#define ITRON_POOL_SIZE 1024*20 -extern int uITRON4_minit(size_t poolsz) ; -extern void *uITRON4_malloc(size_t sz) ; -extern void *uITRON4_realloc(void *p, size_t sz) ; -extern void uITRON4_free(void *p) ; - -#define XMALLOC(sz, heap, type) ((void)(heap), (void)(type), uITRON4_malloc(sz)) -#define XREALLOC(p, sz, heap, type) ((void)(heap), (void)(type), uITRON4_realloc(p, sz)) -#define XFREE(p, heap, type) ((void)(heap), (void)(type), uITRON4_free(p)) + #define XMALLOC(sz, heap, type) ((void)(heap), (void)(type), uITRON4_malloc(sz)) + #define XREALLOC(p, sz, heap, type) ((void)(heap), (void)(type), uITRON4_realloc(p, sz)) + #define XFREE(p, heap, type) ((void)(heap), (void)(type), uITRON4_free(p)) #endif #if defined(WOLFSSL_uTKERNEL2) @@ -3367,7 +3379,9 @@ extern void uITRON4_free(void *p) ; (defined(HAVE_ED448) && defined(HAVE_ED448_KEY_EXPORT)) || \ (defined(HAVE_CURVE448) && defined(HAVE_CURVE448_KEY_EXPORT)) || \ defined(HAVE_FALCON) || defined(HAVE_DILITHIUM) || \ - defined(WOLFSSL_HAVE_SLHDSA) || defined(HAVE_LIBOQS)) + defined(WOLFSSL_HAVE_SLHDSA) || defined(HAVE_LIBOQS) || \ + (defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY)) || \ + (defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY))) #define WC_ENABLE_ASYM_KEY_EXPORT #endif @@ -3377,7 +3391,9 @@ extern void uITRON4_free(void *p) ; (defined(HAVE_ED448) && defined(HAVE_ED448_KEY_IMPORT)) || \ (defined(HAVE_CURVE448) && defined(HAVE_CURVE448_KEY_IMPORT)) || \ defined(HAVE_FALCON) || defined(HAVE_DILITHIUM) || \ - defined(WOLFSSL_HAVE_SLHDSA) || defined(HAVE_LIBOQS)) + defined(WOLFSSL_HAVE_SLHDSA) || defined(HAVE_LIBOQS) || \ + (defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY)) || \ + (defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY))) #define WC_ENABLE_ASYM_KEY_IMPORT #endif @@ -3925,6 +3941,12 @@ extern void uITRON4_free(void *p) ; #ifndef NO_CTYPE_H #define NO_CTYPE_H #endif + /* Linux kernel includes linux/stddef.h. The gcc stddef.h conflicts with it + * (e.g. offsetof()) and needs to be inhibited. + */ + #ifndef NO_STDDEF_H + #define NO_STDDEF_H + #endif #undef HAVE_ERRNO_H #undef HAVE_THREAD_LS #undef HAVE_ATEXIT @@ -5211,6 +5233,12 @@ blinding by defining WC_BLINDING_NO_RNG_ACKNOWLEDGE_WEAKNESS." #if defined(WOLF_CRYPTO_CB_ONLY_SHA256) && !defined(WOLF_CRYPTO_CB) #error "WOLF_CRYPTO_CB_ONLY_SHA256 requires WOLF_CRYPTO_CB" #endif +#if defined(WOLF_CRYPTO_CB_ONLY_SHA512) && !defined(WOLF_CRYPTO_CB) + #error "WOLF_CRYPTO_CB_ONLY_SHA512 requires WOLF_CRYPTO_CB" +#endif +#if defined(WOLF_CRYPTO_CB_ONLY_SHA512) && defined(HAVE_FIPS) + #error "WOLF_CRYPTO_CB_ONLY_SHA512 is incompatible with FIPS builds" +#endif #if defined(WOLF_CRYPTO_CB_ONLY_AES) && !defined(WOLF_CRYPTO_CB) #error "WOLF_CRYPTO_CB_ONLY_AES requires WOLF_CRYPTO_CB" #endif @@ -5248,6 +5276,13 @@ blinding by defining WC_BLINDING_NO_RNG_ACKNOWLEDGE_WEAKNESS." #undef WC_RNG_BANK_SUPPORT #endif +/* The OCSP responder time-stamps every response it generates (producedAt, + * thisUpdate and, for revoked certs, revocationDate), so it needs ASN time + * support. */ +#if defined(HAVE_OCSP_RESPONDER) && defined(NO_ASN_TIME) + #undef HAVE_OCSP_RESPONDER +#endif + #ifdef HAVE_OCSP_RESPONDER #ifndef HAVE_OCSP #error "HAVE_OCSP_RESPONDER requires HAVE_OCSP" diff --git a/wolfssl/wolfcrypt/sha512.h b/wolfssl/wolfcrypt/sha512.h index 292021c44b..4491700a2f 100644 --- a/wolfssl/wolfcrypt/sha512.h +++ b/wolfssl/wolfcrypt/sha512.h @@ -80,6 +80,12 @@ #include #endif +/* no raw hash access when software transform is stripped */ +#if defined(WOLF_CRYPTO_CB_ONLY_SHA512) +#undef WOLFSSL_NO_HASH_RAW +#define WOLFSSL_NO_HASH_RAW +#endif + #define SHA512_NOINLINE WC_NO_INLINE #ifdef WOLFSSL_SHA512 @@ -238,7 +244,9 @@ WOLFSSL_LOCAL void Transform_Sha512_Len_base(wc_Sha512* sha512, WOLFSSL_API int wc_InitSha512(wc_Sha512* sha); WOLFSSL_API int wc_InitSha512_ex(wc_Sha512* sha, void* heap, int devId); WOLFSSL_API int wc_Sha512Update(wc_Sha512* sha, const byte* data, word32 len); +#if !defined(WOLF_CRYPTO_CB_ONLY_SHA512) WOLFSSL_API int wc_Sha512FinalRaw(wc_Sha512* sha512, byte* hash); +#endif WOLFSSL_API int wc_Sha512Final(wc_Sha512* sha512, byte* hash); WOLFSSL_API void wc_Sha512Free(wc_Sha512* sha); @@ -253,7 +261,8 @@ WOLFSSL_API int wc_Sha512Copy(wc_Sha512* src, wc_Sha512* dst); WOLFSSL_API int wc_Sha512GetFlags(wc_Sha512* sha512, word32* flags); #endif -#if defined(OPENSSL_EXTRA) || defined(HAVE_CURL) +#if (defined(OPENSSL_EXTRA) || defined(HAVE_CURL)) && \ + !defined(WOLF_CRYPTO_CB_ONLY_SHA512) WOLFSSL_API int wc_Sha512Transform(wc_Sha512* sha, const unsigned char* data); #endif @@ -262,7 +271,9 @@ WOLFSSL_API int wc_Sha512Transform(wc_Sha512* sha, const unsigned char* data); WOLFSSL_API int wc_InitSha512_224(wc_Sha512* sha); WOLFSSL_API int wc_InitSha512_224_ex(wc_Sha512* sha, void* heap, int devId); WOLFSSL_API int wc_Sha512_224Update(wc_Sha512* sha, const byte* data, word32 len); +#if !defined(WOLF_CRYPTO_CB_ONLY_SHA512) WOLFSSL_API int wc_Sha512_224FinalRaw(wc_Sha512* sha512, byte* hash); +#endif WOLFSSL_API int wc_Sha512_224Final(wc_Sha512* sha512, byte* hash); WOLFSSL_API void wc_Sha512_224Free(wc_Sha512* sha); WOLFSSL_API int wc_Sha512_224GetHash(wc_Sha512* sha512, byte* hash); @@ -272,7 +283,8 @@ WOLFSSL_API int wc_Sha512_224Copy(wc_Sha512* src, wc_Sha512* dst); WOLFSSL_API int wc_Sha512_224GetFlags(wc_Sha512* sha512, word32* flags); #endif -#if defined(OPENSSL_EXTRA) || defined(HAVE_CURL) +#if (defined(OPENSSL_EXTRA) || defined(HAVE_CURL)) && \ + !defined(WOLF_CRYPTO_CB_ONLY_SHA512) WOLFSSL_API int wc_Sha512_224Transform(wc_Sha512* sha, const unsigned char* data); #endif /* OPENSSL_EXTRA */ @@ -283,7 +295,9 @@ WOLFSSL_API int wc_Sha512_224Transform(wc_Sha512* sha, WOLFSSL_API int wc_InitSha512_256(wc_Sha512* sha); WOLFSSL_API int wc_InitSha512_256_ex(wc_Sha512* sha, void* heap, int devId); WOLFSSL_API int wc_Sha512_256Update(wc_Sha512* sha, const byte* data, word32 len); +#if !defined(WOLF_CRYPTO_CB_ONLY_SHA512) WOLFSSL_API int wc_Sha512_256FinalRaw(wc_Sha512* sha512, byte* hash); +#endif WOLFSSL_API int wc_Sha512_256Final(wc_Sha512* sha512, byte* hash); WOLFSSL_API void wc_Sha512_256Free(wc_Sha512* sha); WOLFSSL_API int wc_Sha512_256GetHash(wc_Sha512* sha512, byte* hash); @@ -293,7 +307,8 @@ WOLFSSL_API int wc_Sha512_256Copy(wc_Sha512* src, wc_Sha512* dst); WOLFSSL_API int wc_Sha512_256GetFlags(wc_Sha512* sha512, word32* flags); #endif -#if defined(OPENSSL_EXTRA) || defined(HAVE_CURL) +#if (defined(OPENSSL_EXTRA) || defined(HAVE_CURL)) && \ + !defined(WOLF_CRYPTO_CB_ONLY_SHA512) WOLFSSL_API int wc_Sha512_256Transform(wc_Sha512* sha, const unsigned char* data); #endif /* OPENSSL_EXTRA */ @@ -334,7 +349,9 @@ WOLFSSL_API int wc_Sha512_256Transform(wc_Sha512* sha, WOLFSSL_API int wc_InitSha384(wc_Sha384* sha); WOLFSSL_API int wc_InitSha384_ex(wc_Sha384* sha, void* heap, int devId); WOLFSSL_API int wc_Sha384Update(wc_Sha384* sha, const byte* data, word32 len); +#if !defined(WOLF_CRYPTO_CB_ONLY_SHA512) WOLFSSL_API int wc_Sha384FinalRaw(wc_Sha384* sha384, byte* hash); +#endif WOLFSSL_API int wc_Sha384Final(wc_Sha384* sha384, byte* hash); WOLFSSL_API void wc_Sha384Free(wc_Sha384* sha); diff --git a/wolfssl/wolfcrypt/sp_int.h b/wolfssl/wolfcrypt/sp_int.h index af33e540ee..31936d4075 100644 --- a/wolfssl/wolfcrypt/sp_int.h +++ b/wolfssl/wolfcrypt/sp_int.h @@ -838,6 +838,17 @@ typedef struct sp_dh_ctx { #define MP_BITS_CNT(bits) \ ((unsigned int)(((((bits) + SP_WORD_SIZE - 1) / SP_WORD_SIZE) * 2 + 1))) +/* True when 'bits' would require more digit storage than 'max'. + * + * Pairs with DECL_MP_INT_SIZE_DYN(name, bits, max) to guard against the + * static buffer (sized for 'max' digits) being undersized for 'bits' when + * the caller's 'bits' value can carry digit/byte alignment slack + * (e.g. mp_bitsused() returns used*SP_WORD_SIZE; dp->size*8 rounds up to a + * full byte). Compare digit-rounded counts so curves like P-521 (521 bits, + * 17 32-bit digits) are not falsely rejected when max == 521. */ +#define MP_BITS_OVER_MAX(bits, max) \ + (MP_BITS_CNT(bits) > MP_BITS_CNT(max)) + #if !defined(WOLFSSL_SP_NO_DYN_STACK) && defined(__STDC_VERSION__) && \ (__STDC_VERSION__ >= 199901L) && \ (defined(WOLFSSL_SP_NO_MALLOC) || \ @@ -895,9 +906,13 @@ while (0) #define DECL_MP_INT_SIZE(name, bits) \ sp_int_digit name##d[MP_INT_SIZEOF_DIGITS(MP_BITS_CNT(bits))]; \ sp_int* (name) = (sp_int*)name##d -/* Zero out mp_int of minimal size. */ +/* Bytes to zero for a static mp_int: min(requested bits size, declared buffer). */ +#define MP_INT_ZERO_SIZE(name, bits) \ + ((sizeof(name##d) < MP_INT_SIZEOF(MP_BITS_CNT(bits))) ? \ + sizeof(name##d) : MP_INT_SIZEOF(MP_BITS_CNT(bits))) +/* Zero out mp_int without clearing more than the declared digit buffer. */ #define NEW_MP_INT_SIZE(name, bits, heap, type) \ - XMEMSET(name, 0, MP_INT_SIZEOF(MP_BITS_CNT(bits))) + XMEMSET((name), 0, MP_INT_ZERO_SIZE(name, bits)) /* Dispose of static mp_int. */ #define FREE_MP_INT_SIZE(name, heap, type) WC_DO_NOTHING /* Type to force compiler to not complain about size. */ diff --git a/wolfssl/wolfcrypt/tfm.h b/wolfssl/wolfcrypt/tfm.h index 3868ca6402..0a89b049e3 100644 --- a/wolfssl/wolfcrypt/tfm.h +++ b/wolfssl/wolfcrypt/tfm.h @@ -371,6 +371,10 @@ while (0) /* Type to cast to when using size macros. */ #define MP_INT_SIZE mp_int +/* tfm.h allocates full-sized mp_int buffers, so DECL_MP_INT_SIZE_DYN cannot + * be undersized for any 'bits' value -- no check is needed. */ +#define MP_BITS_OVER_MAX(bits, max) 0 + #ifdef HAVE_WOLF_BIGINT /* raw big integer */ diff --git a/wolfssl/wolfcrypt/types.h b/wolfssl/wolfcrypt/types.h index eb11f8436e..cf8900f6ee 100644 --- a/wolfssl/wolfcrypt/types.h +++ b/wolfssl/wolfcrypt/types.h @@ -2375,29 +2375,39 @@ enum Max_ASN { DSA_INTS = 5, /* DSA ints in private key */ MAX_SALT_SIZE = 64, /* MAX PKCS Salt length */ MAX_IV_SIZE = 64, /* MAX PKCS Iv length */ + /* Max classic sig (RSA/DSA/ECC); separate from MAX_ENCODED_SIG_SZ so + * PKCS#1/verify buffers stay small when PQC is enabled for verify-only. */ +#if !defined(NO_RSA) +#if defined(USE_FAST_MATH) && defined(FP_MAX_BITS) + MAX_ENCODED_CLASSIC_SIG_SZ = FP_MAX_BITS / 16, +#elif (defined(WOLFSSL_SP_MATH_ALL) || defined(WOLFSSL_SP_MATH)) && \ + defined(SP_INT_BITS) + MAX_ENCODED_CLASSIC_SIG_SZ = WC_BITS_TO_BYTES(SP_INT_BITS), +#elif defined(WOLFSSL_HAPROXY) + MAX_ENCODED_CLASSIC_SIG_SZ = 1024, /* Supports 8192 bit keys */ +#else + MAX_ENCODED_CLASSIC_SIG_SZ = 512, /* Supports 4096 bit keys */ +#endif +#elif defined(HAVE_ECC) + MAX_ENCODED_CLASSIC_SIG_SZ = 140, +#elif defined(HAVE_ED448) + MAX_ENCODED_CLASSIC_SIG_SZ = 114, /* Ed448 signature is 114 bytes */ +#else + MAX_ENCODED_CLASSIC_SIG_SZ = 64, /* Ed25519 signature is 64 bytes */ +#endif + + /* Largest signature any enabled algorithm can produce. Used to size the + * actual signature-output buffers. PQC signatures are large, so prefer + * runtime sizing (see GetSignatureBufferSz in asn.c) where the key is + * available. */ #ifdef WOLFSSL_HAVE_SLHDSA /* Largest raw SLH-DSA signature (SHAKE-256f) is 49856 bytes; round up * to leave headroom for ASN.1 wrapping (BIT STRING tag + length). */ MAX_ENCODED_SIG_SZ = 51200, #elif defined(HAVE_FALCON) || defined(WOLFSSL_HAVE_MLDSA) MAX_ENCODED_SIG_SZ = 5120, -#elif !defined(NO_RSA) -#if defined(USE_FAST_MATH) && defined(FP_MAX_BITS) - MAX_ENCODED_SIG_SZ = FP_MAX_BITS / 16, -#elif (defined(WOLFSSL_SP_MATH_ALL) || defined(WOLFSSL_SP_MATH)) && \ - defined(SP_INT_BITS) - MAX_ENCODED_SIG_SZ = WC_BITS_TO_BYTES(SP_INT_BITS), -#elif defined(WOLFSSL_HAPROXY) - MAX_ENCODED_SIG_SZ = 1024, /* Supports 8192 bit keys */ #else - MAX_ENCODED_SIG_SZ = 512, /* Supports 4096 bit keys */ -#endif -#elif defined(HAVE_ECC) - MAX_ENCODED_SIG_SZ = 140, -#elif defined(HAVE_CURVE448) - MAX_ENCODED_SIG_SZ = 114, -#else - MAX_ENCODED_SIG_SZ = 64, + MAX_ENCODED_SIG_SZ = MAX_ENCODED_CLASSIC_SIG_SZ, #endif MAX_ALGO_SZ = 20, MAX_LENGTH_SZ = WOLFSSL_ASN_MAX_LENGTH_SZ, /* Max length size for DER encoding */ @@ -2457,6 +2467,16 @@ enum Max_ASN { #define MAX_SIG_SZ MAX_ENCODED_SIG_SZ +/* Size of the fixed signature buffer embedded in CertSignCtx under + * WOLFSSL_NO_MALLOC, and the reject threshold used by the cert/CSR signing + * paths when dynamic memory is unavailable. Defaults to the largest signature + * any enabled algorithm can produce. Override (e.g. via user_settings.h) to + * fit a specific LMS/XMSS parameter set, or to shrink builds that only sign + * with classic/compact algorithms. */ +#ifndef WOLFSSL_MAX_SIG_SZ +#define WOLFSSL_MAX_SIG_SZ MAX_ENCODED_SIG_SZ +#endif + #if defined(WOLFSSL_CERT_GEN) || defined(HAVE_OCSP_RESPONDER) /* Used in asn.c MakeSignature for ECC and RSA non-blocking/async */ enum CertSignState { @@ -2468,7 +2488,7 @@ enum Max_ASN { typedef struct CertSignCtx { #ifdef WOLFSSL_NO_MALLOC - byte sig[MAX_ENCODED_SIG_SZ]; + byte sig[WOLFSSL_MAX_SIG_SZ]; byte digest[WC_MAX_DIGEST_SIZE]; #ifndef NO_RSA byte encSig[MAX_DER_DIGEST_SZ]; diff --git a/wolfssl/wolfcrypt/wc_lms.h b/wolfssl/wolfcrypt/wc_lms.h index a8d898c6c6..40860356e3 100644 --- a/wolfssl/wolfcrypt/wc_lms.h +++ b/wolfssl/wolfcrypt/wc_lms.h @@ -749,7 +749,7 @@ typedef struct HssPrivKey { #define LMS_MAX_LABEL_LEN 32 #endif -typedef struct LmsKey { +struct LmsKey { /* Public key. */ ALIGN16 byte pub[HSS_PUBLIC_KEY_LEN(LMS_MAX_NODE_LEN)]; #ifndef WOLFSSL_LMS_VERIFY_ONLY @@ -788,7 +788,12 @@ typedef struct LmsKey { char label[LMS_MAX_LABEL_LEN]; int labelLen; #endif -} LmsKey; +}; + +#ifndef WC_LMSKEY_TYPE_DEFINED + typedef struct LmsKey LmsKey; + #define WC_LMSKEY_TYPE_DEFINED +#endif #ifdef __cplusplus extern "C" { @@ -822,6 +827,8 @@ WOLFSSL_API int wc_LmsKey_GetPrivLen(const LmsKey* key, word32* len); WOLFSSL_API int wc_LmsKey_Sign(LmsKey* key, byte* sig, word32* sigSz, const byte* msg, int msgSz); WOLFSSL_API int wc_LmsKey_SigsLeft(LmsKey* key); +WOLFSSL_API int wc_LmsKey_PublicKeyToDer(const LmsKey* key, byte* output, + word32 inLen, int withAlg); #endif /* ifndef WOLFSSL_LMS_VERIFY_ONLY */ WOLFSSL_API void wc_LmsKey_Free(LmsKey* key); WOLFSSL_API int wc_LmsKey_GetSigLen(const LmsKey* key, word32* len); diff --git a/wolfssl/wolfcrypt/wc_port.h b/wolfssl/wolfcrypt/wc_port.h index 775794ae1f..0bd5f793a2 100644 --- a/wolfssl/wolfcrypt/wc_port.h +++ b/wolfssl/wolfcrypt/wc_port.h @@ -516,6 +516,14 @@ typedef wolfSSL_Mutex wolfSSL_RwLock; #endif +#ifdef WC_16BIT_CPU + #define WC_ATOMIC_INT_ARG long int + #define WC_ATOMIC_UINT_ARG long unsigned int +#else + #define WC_ATOMIC_INT_ARG int + #define WC_ATOMIC_UINT_ARG unsigned int +#endif + #ifndef WOLFSSL_NO_ATOMICS #if defined(WOLFSSL_USER_DEFINED_ATOMICS) /* user-supplied bindings for wolfSSL_Atomic_Int etc. */ @@ -527,11 +535,11 @@ #define WOLFSSL_ATOMIC_OPS #endif #elif defined(SINGLE_THREADED) - typedef int wolfSSL_Atomic_Int; - typedef unsigned int wolfSSL_Atomic_Uint; + typedef WC_ATOMIC_INT_ARG wolfSSL_Atomic_Int; + typedef WC_ATOMIC_UINT_ARG wolfSSL_Atomic_Uint; #define WOLFSSL_ATOMIC_INITIALIZER(x) (x) #define WOLFSSL_ATOMIC_LOAD(x) (x) - #define WOLFSSL_ATOMIC_STORE(x, val) (x) = (val) + #define WOLFSSL_ATOMIC_STORE(x, val) (void)((x) = (val)) #define WOLFSSL_ATOMIC_OPS #elif defined(WOLFSSL_BSDKM) /* Note: can be safely included in both linux kernel and @@ -559,7 +567,8 @@ #define WOLFSSL_ATOMIC_STORE(x, val) __atomic_store_n(&(x), \ val, __ATOMIC_RELEASE) #define WOLFSSL_ATOMIC_OPS - #elif defined(_MSC_VER) && !defined(WOLFSSL_NOT_WINDOWS_API) + #elif defined(_MSC_VER) && defined(USE_WINDOWS_API) && \ + !defined(WOLFSSL_NOT_WINDOWS_API) /* Use MSVC compiler intrinsics for atomic ops */ #ifdef _WIN32_WCE #include @@ -569,8 +578,15 @@ typedef volatile long wolfSSL_Atomic_Int; typedef volatile unsigned long wolfSSL_Atomic_Uint; #define WOLFSSL_ATOMIC_INITIALIZER(x) (x) - #define WOLFSSL_ATOMIC_LOAD(x) (x) - #define WOLFSSL_ATOMIC_STORE(x, val) (x) = (val) + /* Acquire-ordered load via idempotent RMW: OR-with-0 leaves the value + * unchanged but provides atomicity + acquire ordering. On cl.exe this + * is a locked RMW; LLVM (clang-cl) may lower it to a plain acquire + * load. + */ + #define WOLFSSL_ATOMIC_LOAD(x) \ + InterlockedOrAcquire((volatile long *)&(x), 0) + #define WOLFSSL_ATOMIC_STORE(x, val) \ + (void)InterlockedExchange((volatile long *)&(x), (long)(val)) #define WOLFSSL_ATOMIC_OPS #endif @@ -581,6 +597,8 @@ #endif /* !WOLFSSL_NO_ATOMICS */ #ifdef WOLFSSL_NO_ATOMICS + typedef volatile int wolfSSL_Atomic_Int; + typedef volatile unsigned int wolfSSL_Atomic_Uint; #define WOLFSSL_ATOMIC_INITIALIZER(x) (x) #define WOLFSSL_ATOMIC_LOAD(x) (x) #define WOLFSSL_ATOMIC_STORE(x, val) (x) = (val) @@ -591,10 +609,10 @@ * Allows a user-supplied override definition with type introspection. */ #ifndef WOLFSSL_ATOMIC_COERCE_INT - #define WOLFSSL_ATOMIC_COERCE_INT(x) ((int)(x)) + #define WOLFSSL_ATOMIC_COERCE_INT(x) ((WC_ATOMIC_INT_ARG)(x)) #endif #ifndef WOLFSSL_ATOMIC_COERCE_UINT - #define WOLFSSL_ATOMIC_COERCE_UINT(x) ((unsigned int)(x)) + #define WOLFSSL_ATOMIC_COERCE_UINT(x) ((WC_ATOMIC_UINT_ARG)(x)) #endif #ifdef WOLFSSL_USER_DEFINED_ATOMICS @@ -602,32 +620,39 @@ * wolfSSL_Atomic_Int_FetchAdd(), etc. */ #elif defined(WOLFSSL_ATOMIC_OPS) && !defined(SINGLE_THREADED) - WOLFSSL_API void wolfSSL_Atomic_Int_Init(wolfSSL_Atomic_Int* c, int i); + WOLFSSL_API void wolfSSL_Atomic_Int_Init(wolfSSL_Atomic_Int* c, + WC_ATOMIC_INT_ARG i); WOLFSSL_API void wolfSSL_Atomic_Uint_Init( - wolfSSL_Atomic_Uint* c, unsigned int i); + wolfSSL_Atomic_Uint* c, WC_ATOMIC_UINT_ARG i); /* FetchOp functions return the value of the counter immediately preceding * the effects of the operation. * OpFetch functions return the value of the counter immediately after * the effects of the operation. */ - WOLFSSL_API int wolfSSL_Atomic_Int_FetchAdd(wolfSSL_Atomic_Int* c, int i); - WOLFSSL_API int wolfSSL_Atomic_Int_FetchSub(wolfSSL_Atomic_Int* c, int i); - WOLFSSL_API int wolfSSL_Atomic_Int_AddFetch(wolfSSL_Atomic_Int* c, int i); - WOLFSSL_API int wolfSSL_Atomic_Int_SubFetch(wolfSSL_Atomic_Int* c, int i); - WOLFSSL_API int wolfSSL_Atomic_Int_Exchange( - wolfSSL_Atomic_Int* c, int new_i); + WOLFSSL_API WC_ATOMIC_INT_ARG wolfSSL_Atomic_Int_FetchAdd( + wolfSSL_Atomic_Int* c, WC_ATOMIC_INT_ARG i); + WOLFSSL_API WC_ATOMIC_INT_ARG wolfSSL_Atomic_Int_FetchSub( + wolfSSL_Atomic_Int* c, WC_ATOMIC_INT_ARG i); + WOLFSSL_API WC_ATOMIC_INT_ARG wolfSSL_Atomic_Int_AddFetch( + wolfSSL_Atomic_Int* c, WC_ATOMIC_INT_ARG i); + WOLFSSL_API WC_ATOMIC_INT_ARG wolfSSL_Atomic_Int_SubFetch( + wolfSSL_Atomic_Int* c, WC_ATOMIC_INT_ARG i); + WOLFSSL_API WC_ATOMIC_INT_ARG wolfSSL_Atomic_Int_Exchange( + wolfSSL_Atomic_Int* c, WC_ATOMIC_INT_ARG new_i); WOLFSSL_API int wolfSSL_Atomic_Int_CompareExchange( - wolfSSL_Atomic_Int* c, int *expected_i, int new_i); - WOLFSSL_API unsigned int wolfSSL_Atomic_Uint_FetchAdd( - wolfSSL_Atomic_Uint* c, unsigned int i); - WOLFSSL_API unsigned int wolfSSL_Atomic_Uint_FetchSub( - wolfSSL_Atomic_Uint* c, unsigned int i); - WOLFSSL_API unsigned int wolfSSL_Atomic_Uint_AddFetch( - wolfSSL_Atomic_Uint* c, unsigned int i); - WOLFSSL_API unsigned int wolfSSL_Atomic_Uint_SubFetch( - wolfSSL_Atomic_Uint* c, unsigned int i); + wolfSSL_Atomic_Int* c, WC_ATOMIC_INT_ARG *expected_i, + WC_ATOMIC_INT_ARG new_i); + WOLFSSL_API WC_ATOMIC_UINT_ARG wolfSSL_Atomic_Uint_FetchAdd( + wolfSSL_Atomic_Uint* c, WC_ATOMIC_UINT_ARG i); + WOLFSSL_API WC_ATOMIC_UINT_ARG wolfSSL_Atomic_Uint_FetchSub( + wolfSSL_Atomic_Uint* c, WC_ATOMIC_UINT_ARG i); + WOLFSSL_API WC_ATOMIC_UINT_ARG wolfSSL_Atomic_Uint_AddFetch( + wolfSSL_Atomic_Uint* c, WC_ATOMIC_UINT_ARG i); + WOLFSSL_API WC_ATOMIC_UINT_ARG wolfSSL_Atomic_Uint_SubFetch( + wolfSSL_Atomic_Uint* c, WC_ATOMIC_UINT_ARG i); WOLFSSL_API int wolfSSL_Atomic_Uint_CompareExchange( - wolfSSL_Atomic_Uint* c, unsigned int *expected_i, unsigned int new_i); + wolfSSL_Atomic_Uint* c, WC_ATOMIC_UINT_ARG *expected_i, + WC_ATOMIC_UINT_ARG new_i); WOLFSSL_API int wolfSSL_Atomic_Ptr_CompareExchange( void* volatile * c, void **expected_ptr, void *new_ptr); #else @@ -637,33 +662,47 @@ * !defined(WOLFSSL_ATOMIC_OPS) && !defined(SINGLE_THREADED). This forces * local awareness of thread-unsafe semantics. */ + #define wolfSSL_Atomic_Int_Init(c, i) (*(c) = (i)) #define wolfSSL_Atomic_Uint_Init(c, i) (*(c) = (i)) - static WC_INLINE int wolfSSL_Atomic_Int_FetchAdd(int *c, int i) { - int ret = *c; + static WC_INLINE WC_ATOMIC_INT_ARG wolfSSL_Atomic_Int_FetchAdd( + WC_ATOMIC_INT_ARG *c, + WC_ATOMIC_INT_ARG i) + { + WC_ATOMIC_INT_ARG ret = *c; *c += i; return ret; } - static WC_INLINE int wolfSSL_Atomic_Int_FetchSub(int *c, int i) { - int ret = *c; + static WC_INLINE WC_ATOMIC_INT_ARG wolfSSL_Atomic_Int_FetchSub( + WC_ATOMIC_INT_ARG *c, + WC_ATOMIC_INT_ARG i) + { + WC_ATOMIC_INT_ARG ret = *c; *c -= i; return ret; } - static WC_INLINE int wolfSSL_Atomic_Int_AddFetch(int *c, int i) { + static WC_INLINE WC_ATOMIC_INT_ARG wolfSSL_Atomic_Int_AddFetch( + WC_ATOMIC_INT_ARG *c, + WC_ATOMIC_INT_ARG i) + { return (*c += i); } - static WC_INLINE int wolfSSL_Atomic_Int_SubFetch(int *c, int i) { + static WC_INLINE WC_ATOMIC_INT_ARG wolfSSL_Atomic_Int_SubFetch( + WC_ATOMIC_INT_ARG *c, + WC_ATOMIC_INT_ARG i) + { return (*c -= i); } - static WC_INLINE int wolfSSL_Atomic_Int_Exchange( - int *c, int new_i) + static WC_INLINE WC_ATOMIC_INT_ARG wolfSSL_Atomic_Int_Exchange( + WC_ATOMIC_INT_ARG *c, WC_ATOMIC_INT_ARG new_i) { - int ret = *c; + WC_ATOMIC_INT_ARG ret = *c; *c = new_i; return ret; } - static WC_INLINE int wolfSSL_Atomic_Int_CompareExchange( - int *c, int *expected_i, int new_i) + static WC_INLINE WC_ATOMIC_INT_ARG wolfSSL_Atomic_Int_CompareExchange( + WC_ATOMIC_INT_ARG *c, WC_ATOMIC_INT_ARG *expected_i, + WC_ATOMIC_INT_ARG new_i) { if (*c == *expected_i) { *c = new_i; @@ -686,32 +725,33 @@ return 0; } } - static WC_INLINE unsigned int wolfSSL_Atomic_Uint_FetchAdd( - unsigned int *c, unsigned int i) + static WC_INLINE WC_ATOMIC_UINT_ARG wolfSSL_Atomic_Uint_FetchAdd( + WC_ATOMIC_UINT_ARG *c, WC_ATOMIC_UINT_ARG i) { - unsigned int ret = *c; + WC_ATOMIC_UINT_ARG ret = *c; *c += i; return ret; } - static WC_INLINE unsigned int wolfSSL_Atomic_Uint_FetchSub( - unsigned int *c, unsigned int i) + static WC_INLINE WC_ATOMIC_UINT_ARG wolfSSL_Atomic_Uint_FetchSub( + WC_ATOMIC_UINT_ARG *c, WC_ATOMIC_UINT_ARG i) { - unsigned int ret = *c; + WC_ATOMIC_UINT_ARG ret = *c; *c -= i; return ret; } - static WC_INLINE unsigned int wolfSSL_Atomic_Uint_AddFetch( - unsigned int *c, unsigned int i) + static WC_INLINE WC_ATOMIC_UINT_ARG wolfSSL_Atomic_Uint_AddFetch( + WC_ATOMIC_UINT_ARG *c, WC_ATOMIC_UINT_ARG i) { return (*c += i); } - static WC_INLINE unsigned int wolfSSL_Atomic_Uint_SubFetch( - unsigned int *c, unsigned int i) + static WC_INLINE WC_ATOMIC_UINT_ARG wolfSSL_Atomic_Uint_SubFetch( + WC_ATOMIC_UINT_ARG *c, WC_ATOMIC_UINT_ARG i) { return (*c -= i); } static WC_INLINE int wolfSSL_Atomic_Uint_CompareExchange( - unsigned int *c, unsigned int *expected_i, unsigned int new_i) + WC_ATOMIC_UINT_ARG *c, WC_ATOMIC_UINT_ARG *expected_i, + WC_ATOMIC_UINT_ARG new_i) { if (*c == *expected_i) { *c = new_i; @@ -941,6 +981,52 @@ WOLFSSL_API int wc_SetMutexCb(mutex_cb* cb); WOLFSSL_API mutex_cb* wc_GetMutexCb(void); #endif +/* Internal APIs for counting initialization depth, with deallocation races + * fully mitigated. Used by wolfCrypt_Init() and wolfCrypt_Cleanup(). + */ +#ifdef WOLFSSL_ATOMIC_OPS + typedef wolfSSL_Atomic_Uint wc_init_state_t; + #define WC_INIT_STATE_INITIALIZER WOLFSSL_ATOMIC_INITIALIZER(0) +#else + typedef WC_ATOMIC_UINT_ARG wc_init_state_t; + #define WC_INIT_STATE_INITIALIZER 0 +#endif +#define WC_DECLARE_INIT_STATE(x) wc_init_state_t x = WC_INIT_STATE_INITIALIZER +#define WC_INIT_STATE_UNINITED 0U +#define WC_INIT_STATE_INITING 1U +#define WC_INIT_STATE_INITED 2U +#define WC_INIT_STATE_CLEANING_UP 3U +#define WC_INIT_STATE_BAD_STATE 4U +#define WC_INIT_STATE_STATE_BITS 3 +#define WC_INIT_STATE_COUNT_BITS 29 +union wc_init_state_bitfields { + WC_ATOMIC_UINT_ARG u; + struct { + WC_ATOMIC_UINT_ARG state:WC_INIT_STATE_STATE_BITS; + WC_ATOMIC_UINT_ARG count:WC_INIT_STATE_COUNT_BITS; + } c; +}; +/* Modules with no provisions for cleanup after a partially successful init need + * to enter a degraded state, returning BAD_STATE_E to the caller, signaling + * that restart is needed. This macro should only be called while + * _STATE_INITING (after wc_local_InitUp() returns _STATE_INITING and before + * wc_local_InitUpDone()), to assure the store is uncontended. + */ +#define WC_INIT_STATE_RAISE_BAD_STATE(x) do { \ + union wc_init_state_bitfields _x; \ + _x.u = WOLFSSL_ATOMIC_LOAD(x); \ + _x.c.state = WC_INIT_STATE_BAD_STATE; \ + WOLFSSL_ATOMIC_STORE(x, _x.u); \ + } while (0) +/* wc_local_InitUp() opens the critical span of an init sequence. */ +WOLFSSL_LOCAL int wc_local_InitUp(wc_init_state_t *s); +/* wc_local_InitUpDone() closes the critical span of an init sequence. */ +WOLFSSL_LOCAL int wc_local_InitUpDone(wc_init_state_t *s); +/* wc_local_InitDown() opens the critical span of a cleanup sequence. */ +WOLFSSL_LOCAL int wc_local_InitDown(wc_init_state_t *s); +/* wc_local_InitDownDone() closes the critical span of a cleanup sequence. */ +WOLFSSL_LOCAL int wc_local_InitDownDone(wc_init_state_t *s); + /* main crypto initialization function */ WOLFSSL_ABI WOLFSSL_API int wolfCrypt_Init(void); WOLFSSL_ABI WOLFSSL_API int wolfCrypt_Cleanup(void); diff --git a/wolfssl/wolfcrypt/wc_xmss.h b/wolfssl/wolfcrypt/wc_xmss.h index 277d85524a..a46826100c 100644 --- a/wolfssl/wolfcrypt/wc_xmss.h +++ b/wolfssl/wolfcrypt/wc_xmss.h @@ -346,7 +346,7 @@ typedef struct XmssParams { #define XMSS_MAX_LABEL_LEN 32 #endif -typedef struct XmssKey { +struct XmssKey { /* Public key. */ unsigned char pk[2 * WC_XMSS_MAX_N]; /* OID that identifies parameters. */ @@ -385,7 +385,12 @@ typedef struct XmssKey { char label[XMSS_MAX_LABEL_LEN]; int labelLen; #endif -} XmssKey; +}; + +#ifndef WC_XMSSKEY_TYPE_DEFINED + typedef struct XmssKey XmssKey; + #define WC_XMSSKEY_TYPE_DEFINED +#endif typedef struct XmssState { const XmssParams* params; @@ -446,6 +451,8 @@ WOLFSSL_API int wc_XmssKey_GetPrivLen(const XmssKey* key, word32* len); WOLFSSL_API int wc_XmssKey_Sign(XmssKey* key, byte* sig, word32* sigSz, const byte* msg, int msgSz); WOLFSSL_API int wc_XmssKey_SigsLeft(XmssKey* key); +WOLFSSL_API int wc_XmssKey_PublicKeyToDer(const XmssKey* key, byte* output, + word32 inLen, int withAlg); #endif /* ifndef WOLFSSL_XMSS_VERIFY_ONLY */ WOLFSSL_API void wc_XmssKey_Free(XmssKey* key); WOLFSSL_API int wc_XmssKey_GetSigLen(const XmssKey* key, word32* len); diff --git a/wrapper/rust/include.am b/wrapper/rust/include.am index 6c620b3317..4c3df1d122 100644 --- a/wrapper/rust/include.am +++ b/wrapper/rust/include.am @@ -13,44 +13,66 @@ EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/build.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/headers.h EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/aes.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/blake2.rs +EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/blake2_digest.rs +EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/blake2_mac.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/chacha20_poly1305.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/cmac.rs +EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/cmac_mac.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/curve25519.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/dh.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/dilithium.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/ecc.rs +EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/ecdsa.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/ed25519.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/ed448.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/fips.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/hkdf.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/hmac.rs +EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/hmac_mac.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/kdf.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/lib.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/lms.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/mlkem.rs +EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/mlkem_kem.rs +EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/pbkdf2_password_hash.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/prf.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/random.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/rsa.rs +EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/rsa_oaep.rs +EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/rsa_pkcs1v15.rs +EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/scrypt_password_hash.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/sha.rs +EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/sha_digest.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/src/sys.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/tests/common/mod.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/tests/test_aes.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/tests/test_blake2.rs +EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/tests/test_blake2_digest.rs +EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/tests/test_blake2_mac.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/tests/test_chacha20_poly1305.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/tests/test_cmac.rs +EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/tests/test_cmac_mac.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/tests/test_curve25519.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/tests/test_dh.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/tests/test_dilithium.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/tests/test_ecc.rs +EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/tests/test_ecdsa.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/tests/test_ed25519.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/tests/test_ed448.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/tests/test_hkdf.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/tests/test_hmac.rs +EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/tests/test_hmac_mac.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/tests/test_kdf.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/tests/test_lms.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/tests/test_mlkem.rs +EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/tests/test_mlkem_kem.rs +EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/tests/test_pbkdf2_password_hash.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/tests/test_prf.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/tests/test_random.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/tests/test_rsa.rs +EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/tests/test_rsa_oaep.rs +EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/tests/test_rsa_pkcs1v15.rs +EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/tests/test_scrypt_password_hash.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/tests/test_sha.rs +EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/tests/test_sha_digest.rs EXTRA_DIST += wrapper/rust/wolfssl-wolfcrypt/tests/test_wolfcrypt.rs diff --git a/wrapper/rust/wolfssl-wolfcrypt/CHANGELOG.md b/wrapper/rust/wolfssl-wolfcrypt/CHANGELOG.md index 8109b0de9d..620bbee02f 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/CHANGELOG.md +++ b/wrapper/rust/wolfssl-wolfcrypt/CHANGELOG.md @@ -1,5 +1,31 @@ # wolfssl-wolfcrypt Change Log +## v2.0.0 + +New features: + +- Add RustCrypto trait support: digest, signature, mac, cipher, aead, rand_core, + kem, and password-hash traits +- Add RSA-OAEP API +- Add scrypt KDF support and scrypt password-hash trait implementation +- Add BLAKE2 digest module (blake2_digest) +- Add BLAKE2 MAC module (blake2_mac) +- Add Aes192Ccm and Aes192Gcm +- Implement Clone for HMAC types +- Improve cross-compilation and bare-metal target support in build.rs + +Fixes and improvements: + +- LMS fixes and improvements +- Replace Lms::sigs_left() with Lms::has_sigs_left() +- Fix CFB::encrypt1 and CFB::decrypt1 to take size in bits +- Dilithium: fix context-length API to take length in bytes +- Handle MAC_CMP_FAILED_E from CMAC::verify{,_ex}() +- Numerous memory-safety, zeroization, and buffer-length validation hardening + fixes (zeroize structs on drop, check slice/buffer length conversions, avoid + uninitialized and overlapping buffers, fix possible ECC resource leaks) +- Document minimum wolfSSL version requirement + ## v1.2.0 - Add LMS wrapper (wolfssl_wolfcrypt::lms module) diff --git a/wrapper/rust/wolfssl-wolfcrypt/Cargo.lock b/wrapper/rust/wolfssl-wolfcrypt/Cargo.lock index 12bfd102df..7cd14f34df 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/Cargo.lock +++ b/wrapper/rust/wolfssl-wolfcrypt/Cargo.lock @@ -485,7 +485,7 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "wolfssl-wolfcrypt" -version = "1.2.0" +version = "2.0.0" dependencies = [ "aead", "bindgen", diff --git a/wrapper/rust/wolfssl-wolfcrypt/Cargo.toml b/wrapper/rust/wolfssl-wolfcrypt/Cargo.toml index 6a38933619..c4a095078f 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/Cargo.toml +++ b/wrapper/rust/wolfssl-wolfcrypt/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wolfssl-wolfcrypt" -version = "1.2.0" +version = "2.0.0" edition = "2024" description = "Rust wrapper for wolfssl C library cryptographic functionality" license = "GPL-3.0" diff --git a/wrapper/rust/wolfssl-wolfcrypt/README.md b/wrapper/rust/wolfssl-wolfcrypt/README.md index ec4fea9221..ad57b33ec3 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/README.md +++ b/wrapper/rust/wolfssl-wolfcrypt/README.md @@ -5,6 +5,12 @@ algorithms portion of the wolfSSL C library. This crate requires wolfSSL version 5.9.0 or newer. +The crate uses `no_std` so that no Rust standard library is required. +This makes it well-suited for embedded/bare-metal environments. + +There is an optional `alloc` feature that enables APIs which require heap +allocation. + ## Installation The `wolfssl` C library must be installed to be used by the Rust crate. @@ -16,7 +22,7 @@ For example: ``` [dependencies] -wolfssl-wolfcrypt = "1.0" +wolfssl-wolfcrypt = "2.0" ``` ## API Coverage @@ -44,6 +50,7 @@ functionality: * PRF * RNG * RSA + * scrypt * SHA * SHA-1, SHA-224, SHA-256, SHA-384, SHA-512, SHA3-224, SHA3-256, SHA3-384, SHA3-512, SHAKE128, SHAKE256 @@ -51,6 +58,35 @@ functionality: * SSH KDF * TLSv1.3 HKDF +## RustCrypto Trait Support + +In addition to its native API, this crate can implement the common +[RustCrypto](https://github.com/RustCrypto) traits for wolfCrypt-backed types. +Each set of trait implementations is gated behind a Cargo feature so that +projects only pull in the dependencies they need. All features are off by +default. + +| Feature | RustCrypto crate | wolfCrypt types | +| --------------- | ---------------- | ------------------------------------- | +| `digest` | `digest` | SHA (sha_digest), BLAKE2 (blake2_digest) | +| `mac` | `digest` (mac) | HMAC (hmac_mac), CMAC (cmac_mac), BLAKE2 (blake2_mac) | +| `signature` | `signature` | ECDSA (ecdsa), RSA PKCS#1 v1.5 (rsa_pkcs1v15) | +| `cipher` | `cipher` | AES (aes) | +| `aead` | `aead` | AES-GCM/CCM/EAX (aes), ChaCha20-Poly1305 | +| `rand_core` | `rand_core` | RNG (random) | +| `kem` | `kem` | ML-KEM (mlkem_kem) | +| `password-hash` | `password-hash` | PBKDF2 (pbkdf2_password_hash), scrypt (scrypt_password_hash) | + +The BLAKE2, CMAC, and HMAC trait modules additionally require the corresponding +algorithm support to be enabled in the wolfSSL C library. + +Enable features in your `Cargo.toml`, for example: + +``` +[dependencies] +wolfssl-wolfcrypt = { version = "2.0", features = ["digest", "signature"] } +``` + ## Build Notes ### WOLFSSL_PREFIX diff --git a/wrapper/rust/wolfssl-wolfcrypt/build.rs b/wrapper/rust/wolfssl-wolfcrypt/build.rs index 3d0c7ea6b1..646932366b 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/build.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/build.rs @@ -425,6 +425,7 @@ fn scan_cfg() -> Result<()> { /* kdf */ check_cfg(&binding, "wc_PBKDF2", "kdf_pbkdf2"); check_cfg(&binding, "wc_PKCS12_PBKDF_ex", "kdf_pkcs12"); + check_cfg(&binding, "wc_scrypt", "kdf_scrypt"); check_cfg(&binding, "wc_SRTP_KDF", "kdf_srtp"); check_cfg(&binding, "wc_SSH_KDF", "kdf_ssh"); check_cfg(&binding, "wc_Tls13_HKDF_Extract_ex", "kdf_tls13"); @@ -457,6 +458,7 @@ fn scan_cfg() -> Result<()> { check_cfg(&binding, "wc_RsaDirect", "rsa_direct"); check_cfg(&binding, "wc_MakeRsaKey", "rsa_keygen"); check_cfg(&binding, "wc_RsaPSS_Sign", "rsa_pss"); + check_cfg(&binding, "wc_RsaPublicEncrypt_ex", "rsa_oaep"); check_cfg(&binding, "wc_RsaSetRNG", "rsa_setrng"); check_cfg(&binding, "WC_MGF1SHA512_224", "rsa_mgf1sha512_224"); check_cfg(&binding, "WC_MGF1SHA512_256", "rsa_mgf1sha512_256"); diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/aes.rs b/wrapper/rust/wolfssl-wolfcrypt/src/aes.rs index 7d954d2164..d58250b857 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/aes.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/aes.rs @@ -806,19 +806,23 @@ impl CFB { /// * `din`: Data to encrypt. /// * `dout`: Buffer in which to store the encrypted data. The size of /// the buffer must match that of the `din` buffer. + /// * `size`: Number of bits to encrypt. The `din` and `dout` buffers must + /// each be large enough to hold this number of bits. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. - pub fn encrypt1(&mut self, din: &[u8], dout: &mut [u8]) -> Result<(), i32> { - let in_size = crate::buffer_len_to_u32(din.len())?; - let out_size = crate::buffer_len_to_u32(dout.len())?; - if in_size != out_size { + pub fn encrypt1(&mut self, din: &[u8], dout: &mut [u8], size: usize) -> Result<(), i32> { + if din.len() != dout.len() { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } + if din.len() < size.div_ceil(8) { + return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); + } + let bit_size = crate::buffer_len_to_u32(size)?; let rc = unsafe { - sys::wc_AesCfb1Encrypt(&mut self.ws_aes, dout.as_mut_ptr(), din.as_ptr(), in_size) + sys::wc_AesCfb1Encrypt(&mut self.ws_aes, dout.as_mut_ptr(), din.as_ptr(), bit_size) }; if rc != 0 { return Err(rc); @@ -894,20 +898,24 @@ impl CFB { /// * `din`: Data to decrypt. /// * `dout`: Buffer in which to store the decrypted data. The size of /// the buffer must match that of the `din` buffer. + /// * `size`: Number of bits to decrypt. The `din` and `dout` buffers must + /// each be large enough to hold this number of bits. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. #[cfg(aes_decrypt)] - pub fn decrypt1(&mut self, din: &[u8], dout: &mut [u8]) -> Result<(), i32> { - let in_size = crate::buffer_len_to_u32(din.len())?; - let out_size = crate::buffer_len_to_u32(dout.len())?; - if in_size != out_size { + pub fn decrypt1(&mut self, din: &[u8], dout: &mut [u8], size: usize) -> Result<(), i32> { + if din.len() != dout.len() { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } + if din.len() < size.div_ceil(8) { + return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); + } + let bit_size = crate::buffer_len_to_u32(size)?; let rc = unsafe { - sys::wc_AesCfb1Decrypt(&mut self.ws_aes, dout.as_mut_ptr(), din.as_ptr(), in_size) + sys::wc_AesCfb1Decrypt(&mut self.ws_aes, dout.as_mut_ptr(), din.as_ptr(), bit_size) }; if rc != 0 { return Err(rc); @@ -2993,7 +3001,10 @@ impl XTSStream { #[cfg(aes_xts_stream)] impl XTSStream { fn zeroize(&mut self) { - unsafe { crate::zeroize_raw(&mut self.ws_xtsaes); } + unsafe { + crate::zeroize_raw(&mut self.ws_xtsaes); + crate::zeroize_raw(&mut self.ws_xtsaesstreamdata); + } } } #[cfg(aes_xts_stream)] diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/cmac.rs b/wrapper/rust/wolfssl-wolfcrypt/src/cmac.rs index f99c7c9687..b7ac1bc774 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/cmac.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/cmac.rs @@ -201,6 +201,9 @@ impl CMAC { data.as_ptr(), data_size, key.as_ptr(), key_size) }; + if rc == sys::wolfCrypt_ErrorCodes_MAC_CMP_FAILED_E { + return Ok(false); + } if rc < 0 { return Err(rc); } @@ -402,6 +405,9 @@ impl CMAC { data.as_ptr(), data_size, key.as_ptr(), key_size, heap, dev_id) }; + if rc == sys::wolfCrypt_ErrorCodes_MAC_CMP_FAILED_E { + return Ok(false); + } if rc < 0 { return Err(rc); } diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/kdf.rs b/wrapper/rust/wolfssl-wolfcrypt/src/kdf.rs index ab294f1a50..578779e357 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/kdf.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/kdf.rs @@ -269,6 +269,114 @@ pub fn pkcs12_pbkdf_ex(password: &[u8], salt: &[u8], iterations: i32, typ: i32, Ok(()) } +/// Implement the scrypt password-based key derivation function as defined +/// in RFC 7914. +/// +/// # Parameters +/// +/// * `password`: Password to use for key derivation. +/// * `salt`: Salt value to use for key derivation. +/// * `cost`: log base 2 of the iteration count (`N = 1 << cost`). Must +/// satisfy `1 <= cost < 128 * block_size / 8`. +/// * `block_size`: Number of 128-byte octets in a working block (the `r` +/// parameter from RFC 7914). Must be in `1..=8`. +/// * `parallel`: Number of parallel mix operations to perform (the `p` +/// parameter from RFC 7914). This implementation does not use threads. +/// * `out`: Output buffer in which to store the derived key. +/// +/// # Returns +/// +/// Returns either Ok(()) on success or Err(e) containing the wolfSSL +/// library error code value. +/// +/// # Example +/// +/// ```rust +/// #[cfg(kdf_scrypt)] +/// { +/// use wolfssl_wolfcrypt::kdf::scrypt; +/// let password = b"password"; +/// let salt = b"NaCl"; +/// let expected_key = [ +/// 0xfdu8, 0xba, 0xbe, 0x1c, 0x9d, 0x34, 0x72, 0x00, +/// 0x78, 0x56, 0xe7, 0x19, 0x0d, 0x01, 0xe9, 0xfe, +/// 0x7c, 0x6a, 0xd7, 0xcb, 0xc8, 0x23, 0x78, 0x30, +/// 0xe7, 0x73, 0x76, 0x63, 0x4b, 0x37, 0x31, 0x62, +/// 0x2e, 0xaf, 0x30, 0xd9, 0x2e, 0x22, 0xa3, 0x88, +/// 0x6f, 0xf1, 0x09, 0x27, 0x9d, 0x98, 0x30, 0xda, +/// 0xc7, 0x27, 0xaf, 0xb9, 0x4a, 0x83, 0xee, 0x6d, +/// 0x83, 0x60, 0xcb, 0xdf, 0xa2, 0xcc, 0x06, 0x40 +/// ]; +/// let mut keyout = [0u8; 64]; +/// scrypt(password, salt, 10, 8, 16, &mut keyout).expect("Error with scrypt()"); +/// assert_eq!(keyout, expected_key); +/// } +/// ``` +#[cfg(kdf_scrypt)] +pub fn scrypt(password: &[u8], salt: &[u8], cost: i32, block_size: i32, + parallel: i32, out: &mut [u8]) -> Result<(), i32> { + let password_size = crate::buffer_len_to_i32(password.len())?; + let salt_size = crate::buffer_len_to_i32(salt.len())?; + let out_size = crate::buffer_len_to_i32(out.len())?; + let rc = unsafe { + sys::wc_scrypt(out.as_mut_ptr(), password.as_ptr(), password_size, + salt.as_ptr(), salt_size, cost, block_size, parallel, out_size) + }; + if rc != 0 { + return Err(rc); + } + Ok(()) +} + +/// Implement the scrypt password-based key derivation function as defined +/// in RFC 7914. This variant takes the iteration count `N` directly +/// instead of `log2(N)`. +/// +/// # Parameters +/// +/// * `password`: Password to use for key derivation. +/// * `salt`: Salt value to use for key derivation. +/// * `iterations`: Iteration count (`N`). Must be a power of two greater +/// than 1. +/// * `block_size`: Number of 128-byte octets in a working block (the `r` +/// parameter from RFC 7914). Must be in `1..=8`. +/// * `parallel`: Number of parallel mix operations to perform (the `p` +/// parameter from RFC 7914). This implementation does not use threads. +/// * `out`: Output buffer in which to store the derived key. +/// +/// # Returns +/// +/// Returns either Ok(()) on success or Err(e) containing the wolfSSL +/// library error code value. +/// +/// # Example +/// +/// ```rust +/// #[cfg(kdf_scrypt)] +/// { +/// use wolfssl_wolfcrypt::kdf::scrypt_ex; +/// let password = b"password"; +/// let salt = b"NaCl"; +/// let mut keyout = [0u8; 64]; +/// scrypt_ex(password, salt, 1024, 8, 16, &mut keyout).expect("Error with scrypt_ex()"); +/// } +/// ``` +#[cfg(kdf_scrypt)] +pub fn scrypt_ex(password: &[u8], salt: &[u8], iterations: u32, + block_size: i32, parallel: i32, out: &mut [u8]) -> Result<(), i32> { + let password_size = crate::buffer_len_to_i32(password.len())?; + let salt_size = crate::buffer_len_to_i32(salt.len())?; + let out_size = crate::buffer_len_to_i32(out.len())?; + let rc = unsafe { + sys::wc_scrypt_ex(out.as_mut_ptr(), password.as_ptr(), password_size, + salt.as_ptr(), salt_size, iterations, block_size, parallel, out_size) + }; + if rc != 0 { + return Err(rc); + } + Ok(()) +} + /// Perform RFC 5869 HKDF-Extract operation for TLS v1.3 key derivation. /// /// # Parameters diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/lib.rs b/wrapper/rust/wolfssl-wolfcrypt/src/lib.rs index 36dc42bd94..f25e42a574 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/lib.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/lib.rs @@ -74,11 +74,15 @@ pub mod mlkem_kem; pub mod prf; pub mod random; pub mod rsa; +#[cfg(rsa_oaep)] +pub mod rsa_oaep; #[cfg(feature = "signature")] pub mod rsa_pkcs1v15; pub mod sha; #[cfg(all(feature = "password-hash", hmac, kdf_pbkdf2))] pub mod pbkdf2_password_hash; +#[cfg(all(feature = "password-hash", kdf_scrypt))] +pub mod scrypt_password_hash; #[cfg(feature = "digest")] pub mod sha_digest; diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/lms.rs b/wrapper/rust/wolfssl-wolfcrypt/src/lms.rs index 4eca40433c..d6f7b3288d 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/lms.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/lms.rs @@ -774,6 +774,9 @@ impl Lms { if rc != 0 { return Err(rc); } + if kid_ptr.is_null() { + return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); + } let src = unsafe { core::slice::from_raw_parts(kid_ptr, kid_sz as usize) }; if kid.len() < src.len() { return Err(sys::wolfCrypt_ErrorCodes_BUFFER_E); diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/mlkem_kem.rs b/wrapper/rust/wolfssl-wolfcrypt/src/mlkem_kem.rs index 177c13558f..4bd91e3691 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/mlkem_kem.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/mlkem_kem.rs @@ -135,6 +135,7 @@ macro_rules! impl_mlkem_kem { let mut ss = [0u8; crate::mlkem::MlKem::SHARED_SECRET_SIZE]; wc_key.encapsulate_with_random(&mut ct, &mut ss, &rand) .expect("encapsulate_with_random failed"); + zeroize::Zeroize::zeroize(&mut rand[..]); (ct.into(), ss.into()) } @@ -184,6 +185,7 @@ macro_rules! impl_mlkem_kem { let wc_key = crate::mlkem::MlKem::generate_with_random( $key_type, &rand, ).expect("generate_with_random failed"); + zeroize::Zeroize::zeroize(&mut rand[..]); let mut pk = [0u8; $pk_len]; let mut sk = [0u8; $sk_len]; diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/pbkdf2_password_hash.rs b/wrapper/rust/wolfssl-wolfcrypt/src/pbkdf2_password_hash.rs index 42bbbcca3c..7f86ab9518 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/pbkdf2_password_hash.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/pbkdf2_password_hash.rs @@ -217,10 +217,14 @@ impl password_hash::CustomizedPasswordHasher for Pbkdf2 { None => self.algorithm, }; - if params.rounds < MIN_ROUNDS || params.output_len > Output::MAX_LENGTH { + if params.rounds < MIN_ROUNDS { return Err(Error::ParamInvalid { name: "i" }); } + if params.output_len > Output::MAX_LENGTH { + return Err(Error::ParamInvalid { name: "l" }); + } + let iterations = i32::try_from(params.rounds) .map_err(|_| Error::ParamInvalid { name: "i" })?; diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/rsa.rs b/wrapper/rust/wolfssl-wolfcrypt/src/rsa.rs index da9dc765d1..d7c422ee35 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/rsa.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/rsa.rs @@ -847,6 +847,168 @@ impl RSA { Ok(rc as usize) } + /// Encrypt data using an RSA public key with RSAES-OAEP padding (PKCS#1 + /// v2.2). + /// + /// # Parameters + /// + /// * `din`: Data to encrypt. + /// * `dout`: Buffer in which to store encrypted data. + /// * `hash_algo`: Hash algorithm type used by OAEP, one of + /// `RSA::HASH_TYPE_*`. + /// * `mgf`: Mask generation function to use, one of `RSA::MGF*`. + /// * `rng`: Reference to a `RNG` struct to use for random number + /// generation while encrypting. + /// + /// # Returns + /// + /// Returns Ok(size) on success or Err(e) containing the wolfSSL library + /// error code value. + /// The size returned specifies the number of bytes written to the `dout` + /// buffer. + /// + /// # Example + /// + /// ```rust + /// # extern crate std; + /// #[cfg(all(random, sha256, rsa_oaep, feature = "alloc"))] + /// { + /// use std::fs; + /// use wolfssl_wolfcrypt::random::RNG; + /// use wolfssl_wolfcrypt::rsa::RSA; + /// + /// let rng = std::rc::Rc::new(RNG::new().expect("Error creating RNG")); + /// let key_path = "../../../certs/client-keyPub.der"; + /// let der: Vec = fs::read(key_path).expect("Error reading key file"); + /// let mut rsa = RSA::new_public_from_der(&der).expect("Error with new_public_from_der()"); + /// rsa.set_shared_rng(std::rc::Rc::clone(&rng)).expect("Error with set_shared_rng()"); + /// let plain: &[u8] = b"Test message"; + /// let mut enc: [u8; 512] = [0; 512]; + /// let enc_len = rsa.public_encrypt_oaep(plain, &mut enc, RSA::HASH_TYPE_SHA256, RSA::MGF1SHA256, &rng).expect("Error with public_encrypt_oaep()"); + /// assert!(enc_len > 0 && enc_len <= 512); + /// + /// let key_path = "../../../certs/client-key.der"; + /// let der: Vec = fs::read(key_path).expect("Error reading key file"); + /// let mut rsa = RSA::new_from_der(&der).expect("Error with new_from_der()"); + /// rsa.set_shared_rng(std::rc::Rc::clone(&rng)).expect("Error with set_shared_rng()"); + /// let mut plain_out: [u8; 512] = [0; 512]; + /// let dec_len = rsa.private_decrypt_oaep(&enc[0..enc_len], &mut plain_out, RSA::HASH_TYPE_SHA256, RSA::MGF1SHA256).expect("Error with private_decrypt_oaep()"); + /// assert_eq!(dec_len, plain.len()); + /// assert_eq!(plain_out[0..dec_len], *plain); + /// } + /// ``` + #[cfg(all(random, rsa_oaep))] + pub fn public_encrypt_oaep(&mut self, din: &[u8], dout: &mut [u8], hash_algo: u32, mgf: i32, rng: &RNG) -> Result { + self.public_encrypt_oaep_ex(din, dout, hash_algo, mgf, None, rng) + } + + /// Encrypt data using an RSA public key with RSAES-OAEP padding and an + /// optional label. + /// + /// # Parameters + /// + /// * `din`: Data to encrypt. + /// * `dout`: Buffer in which to store encrypted data. + /// * `hash_algo`: Hash algorithm type used by OAEP, one of + /// `RSA::HASH_TYPE_*`. + /// * `mgf`: Mask generation function to use, one of `RSA::MGF*`. + /// * `label`: Optional OAEP label (must be supplied identically when + /// decrypting). + /// * `rng`: Reference to a `RNG` struct to use for random number + /// generation while encrypting. + /// + /// # Returns + /// + /// Returns Ok(size) on success or Err(e) containing the wolfSSL library + /// error code value. + /// The size returned specifies the number of bytes written to the `dout` + /// buffer. + #[cfg(all(random, rsa_oaep))] + pub fn public_encrypt_oaep_ex(&mut self, din: &[u8], dout: &mut [u8], hash_algo: u32, mgf: i32, label: Option<&[u8]>, rng: &RNG) -> Result { + let din_size = crate::buffer_len_to_u32(din.len())?; + let dout_size = crate::buffer_len_to_u32(dout.len())?; + let (label_ptr, label_size) = match label { + // wolfSSL C API takes label as `byte *` but only reads from it. + Some(label) => (label.as_ptr() as *mut u8, crate::buffer_len_to_u32(label.len())?), + None => (core::ptr::null_mut(), 0), + }; + let rc = unsafe { + // SAFETY: label_ptr is declared as a mutable pointer but is only + // read from. + sys::wc_RsaPublicEncrypt_ex(din.as_ptr(), din_size, + dout.as_mut_ptr(), dout_size, &mut self.wc_rsakey, + rng.wc_rng, sys::WC_RSA_OAEP_PAD as i32, + hash_algo, mgf, label_ptr, label_size) + }; + if rc < 0 { + return Err(rc); + } + Ok(rc as usize) + } + + /// Decrypt data using an RSA private key with RSAES-OAEP padding (PKCS#1 + /// v2.2). + /// + /// # Parameters + /// + /// * `din`: Data to decrypt. + /// * `dout`: Buffer in which to store decrypted data. + /// * `hash_algo`: Hash algorithm type used by OAEP, one of + /// `RSA::HASH_TYPE_*`. + /// * `mgf`: Mask generation function to use, one of `RSA::MGF*`. + /// + /// # Returns + /// + /// Returns Ok(size) on success or Err(e) containing the wolfSSL library + /// error code value. + /// The size returned specifies the number of bytes written to the `dout` + /// buffer. + #[cfg(rsa_oaep)] + pub fn private_decrypt_oaep(&mut self, din: &[u8], dout: &mut [u8], hash_algo: u32, mgf: i32) -> Result { + self.private_decrypt_oaep_ex(din, dout, hash_algo, mgf, None) + } + + /// Decrypt data using an RSA private key with RSAES-OAEP padding and an + /// optional label. + /// + /// # Parameters + /// + /// * `din`: Data to decrypt. + /// * `dout`: Buffer in which to store decrypted data. + /// * `hash_algo`: Hash algorithm type used by OAEP, one of + /// `RSA::HASH_TYPE_*`. + /// * `mgf`: Mask generation function to use, one of `RSA::MGF*`. + /// * `label`: Optional OAEP label that was supplied when encrypting. + /// + /// # Returns + /// + /// Returns Ok(size) on success or Err(e) containing the wolfSSL library + /// error code value. + /// The size returned specifies the number of bytes written to the `dout` + /// buffer. + #[cfg(rsa_oaep)] + pub fn private_decrypt_oaep_ex(&mut self, din: &[u8], dout: &mut [u8], hash_algo: u32, mgf: i32, label: Option<&[u8]>) -> Result { + let din_size = crate::buffer_len_to_u32(din.len())?; + let dout_size = crate::buffer_len_to_u32(dout.len())?; + let (label_ptr, label_size) = match label { + // wolfSSL C API takes label as `byte *` but only reads from it. + Some(label) => (label.as_ptr() as *mut u8, crate::buffer_len_to_u32(label.len())?), + None => (core::ptr::null_mut(), 0), + }; + let rc = unsafe { + // SAFETY: label_ptr is declared as a mutable pointer but is only + // read from. + sys::wc_RsaPrivateDecrypt_ex(din.as_ptr(), din_size, + dout.as_mut_ptr(), dout_size, &mut self.wc_rsakey, + sys::WC_RSA_OAEP_PAD as i32, + hash_algo, mgf, label_ptr, label_size) + }; + if rc < 0 { + return Err(rc); + } + Ok(rc as usize) + } + /// Sign the provided data with the private key using RSA-PSS signature /// scheme. /// diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/rsa_oaep.rs b/wrapper/rust/wolfssl-wolfcrypt/src/rsa_oaep.rs new file mode 100644 index 0000000000..a1c8e371d6 --- /dev/null +++ b/wrapper/rust/wolfssl-wolfcrypt/src/rsa_oaep.rs @@ -0,0 +1,386 @@ +/* + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL 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. + * + * wolfSSL 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 + */ + +/*! +RSA OAEP (PKCS#1 v2.2) encryption / decryption with const-generic wrapper +types over [`crate::rsa::RSA`]. + +This module mirrors the style of [`crate::rsa_pkcs1v15`]: a [`Hash`] marker +selects the digest algorithm used by OAEP and its MGF1, and `N` is the +modulus size in bytes (e.g. `256` for RSA-2048, `384` for RSA-3072). + +- [`EncryptingKey`] / [`DecryptingKey`] — RSA public/private key + wrappers parameterised by the OAEP hash and modulus size. +- [`Ciphertext`] — fixed-size `[u8; N]` ciphertext wrapper. + +# RustCrypto traits + +The widely-used encryption / decryption traits in the RustCrypto ecosystem +(`rsa::traits::RandomizedEncryptor`, `rsa::traits::Decryptor`) live in the +`rsa` crate and are sealed, so external crates cannot implement them. This +module therefore provides only the natural inherent-method API, matching the +shape of those traits without claiming conformance. + +# Example + +```rust +#[cfg(all(random, sha256, rsa_keygen, rsa_oaep))] +{ +use wolfssl_wolfcrypt::random::RNG; +use wolfssl_wolfcrypt::rsa_oaep::{Sha256, EncryptingKey, DecryptingKey}; + +let pad_rng = RNG::new().expect("RNG"); +let mut dk: DecryptingKey = DecryptingKey::generate(RNG::new().expect("RNG")).expect("dk"); +let ek: EncryptingKey = dk.encrypting_key().expect("ek"); + +let msg = b"hello, OAEP"; +let ct = ek.encrypt(&pad_rng, msg).expect("encrypt"); +let mut buf = [0u8; 256]; +let n = dk.decrypt(&ct, &mut buf).expect("decrypt"); +assert_eq!(&buf[..n], msg); +} +``` +*/ + +#![cfg(all(rsa, rsa_oaep))] + +use core::marker::PhantomData; + +use crate::rsa::RSA; +use crate::sys; +#[cfg(random)] +use crate::random::RNG; + +mod private { + pub trait Sealed {} +} + +/// Marker trait selecting the digest algorithm used by OAEP (both the label +/// hash and the MGF1 hash). +pub trait Hash: private::Sealed { + /// wolfCrypt hash algorithm identifier (one of `WC_HASH_TYPE_*`). + const HASH_TYPE: u32; + /// wolfCrypt MGF1 identifier matching `HASH_TYPE`. + const MGF: i32; +} + +/// SHA-1 digest selection for OAEP / MGF1. +/// +/// SHA-1 is included for interoperability only and is **not recommended** for +/// new designs. +#[cfg(sha)] +pub enum Sha1 {} +#[cfg(sha)] +impl private::Sealed for Sha1 {} +#[cfg(sha)] +impl Hash for Sha1 { + const HASH_TYPE: u32 = sys::wc_HashType_WC_HASH_TYPE_SHA; + const MGF: i32 = sys::WC_MGF1SHA1 as i32; +} + +/// SHA-224 digest selection for OAEP / MGF1. +#[cfg(sha224)] +pub enum Sha224 {} +#[cfg(sha224)] +impl private::Sealed for Sha224 {} +#[cfg(sha224)] +impl Hash for Sha224 { + const HASH_TYPE: u32 = sys::wc_HashType_WC_HASH_TYPE_SHA224; + const MGF: i32 = sys::WC_MGF1SHA224 as i32; +} + +/// SHA-256 digest selection for OAEP / MGF1. +#[cfg(sha256)] +pub enum Sha256 {} +#[cfg(sha256)] +impl private::Sealed for Sha256 {} +#[cfg(sha256)] +impl Hash for Sha256 { + const HASH_TYPE: u32 = sys::wc_HashType_WC_HASH_TYPE_SHA256; + const MGF: i32 = sys::WC_MGF1SHA256 as i32; +} + +/// SHA-384 digest selection for OAEP / MGF1. +#[cfg(sha384)] +pub enum Sha384 {} +#[cfg(sha384)] +impl private::Sealed for Sha384 {} +#[cfg(sha384)] +impl Hash for Sha384 { + const HASH_TYPE: u32 = sys::wc_HashType_WC_HASH_TYPE_SHA384; + const MGF: i32 = sys::WC_MGF1SHA384 as i32; +} + +/// SHA-512 digest selection for OAEP / MGF1. +#[cfg(sha512)] +pub enum Sha512 {} +#[cfg(sha512)] +impl private::Sealed for Sha512 {} +#[cfg(sha512)] +impl Hash for Sha512 { + const HASH_TYPE: u32 = sys::wc_HashType_WC_HASH_TYPE_SHA512; + const MGF: i32 = sys::WC_MGF1SHA512 as i32; +} + +/// Fixed-size RSAES-OAEP ciphertext. `N` is the modulus size in bytes. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct Ciphertext([u8; N]); + +impl Ciphertext { + /// Construct a ciphertext from its raw bytes. + pub const fn from_bytes(bytes: [u8; N]) -> Self { + Self(bytes) + } + + /// Return the raw ciphertext bytes. + pub const fn to_bytes(&self) -> [u8; N] { + self.0 + } +} + +impl AsRef<[u8]> for Ciphertext { + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + +impl TryFrom<&[u8]> for Ciphertext { + type Error = i32; + fn try_from(bytes: &[u8]) -> Result { + let arr: [u8; N] = bytes.try_into() + .map_err(|_| sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG)?; + Ok(Self(arr)) + } +} + +impl From> for [u8; N] { + fn from(ct: Ciphertext) -> Self { + ct.0 + } +} + +fn check_modulus_size(rsa: &RSA, expected: usize) -> Result<(), i32> { + let actual = rsa.get_encrypt_size()?; + if actual != expected { + return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); + } + Ok(()) +} + +/// Maximum number of bytes that the public exponent `e` can occupy. +const MAX_E_LEN: usize = 8; + +/// RSA OAEP encrypting (public) key. +/// +/// Owns a copy of the public key as raw `(n, e)` bytes and instantiates a +/// short-lived [`RSA`] on each encryption. `H` selects the OAEP hash; `N` is +/// the modulus size in bytes. +pub struct EncryptingKey { + n: [u8; N], + e: [u8; MAX_E_LEN], + e_len: u8, + _hash: PhantomData, +} + +impl Clone for EncryptingKey { + fn clone(&self) -> Self { *self } +} +impl Copy for EncryptingKey {} +impl core::fmt::Debug for EncryptingKey { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("EncryptingKey") + .field("n", &&self.n[..]) + .field("e", &self.exponent()) + .finish() + } +} +impl PartialEq for EncryptingKey { + fn eq(&self, other: &Self) -> bool { + self.n == other.n && self.exponent() == other.exponent() + } +} +impl Eq for EncryptingKey {} + +impl EncryptingKey { + /// Construct an encrypting key from raw big-endian modulus (`n`) and + /// public exponent (`e`) bytes. + pub fn from_components(n: &[u8], e: &[u8]) -> Result { + if n.len() != N || e.is_empty() || e.len() > MAX_E_LEN { + return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); + } + let mut n_arr = [0u8; N]; + n_arr.copy_from_slice(n); + let mut e_arr = [0u8; MAX_E_LEN]; + e_arr[..e.len()].copy_from_slice(e); + Ok(Self { + n: n_arr, + e: e_arr, + e_len: e.len() as u8, + _hash: PhantomData, + }) + } + + /// Adopt the public part of an existing [`RSA`] key, verifying its + /// modulus size in bytes matches `N`. + pub fn from_rsa(rsa: &RSA) -> Result { + check_modulus_size(rsa, N)?; + let mut n = [0u8; N]; + let mut e = [0u8; MAX_E_LEN]; + let mut n_len: u32 = n.len() as u32; + let mut e_len: u32 = e.len() as u32; + #[cfg(rsa_const_api)] + let key = &rsa.wc_rsakey; + // SAFETY: older wolfSSL declared the first arg as non-const, but the + // function only reads from the key (newer versions declare it const). + #[cfg(not(rsa_const_api))] + let key = core::ptr::addr_of!(rsa.wc_rsakey) as *mut sys::RsaKey; + let rc = unsafe { + sys::wc_RsaFlattenPublicKey( + key, + e.as_mut_ptr(), &mut e_len, + n.as_mut_ptr(), &mut n_len, + ) + }; + if rc != 0 { + return Err(rc); + } + if (n_len as usize) != N || e_len == 0 || (e_len as usize) > MAX_E_LEN { + return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); + } + Ok(Self { + n, + e, + e_len: e_len as u8, + _hash: PhantomData, + }) + } + + /// Construct an encrypting key from a DER-encoded `SubjectPublicKeyInfo` + /// / PKCS#1 public key. + pub fn from_public_der(der: &[u8]) -> Result { + let rsa = RSA::new_public_from_der(der)?; + Self::from_rsa(&rsa) + } + + /// Return the raw modulus bytes. + pub const fn modulus(&self) -> &[u8; N] { + &self.n + } + + /// Return the raw public exponent bytes. + pub fn exponent(&self) -> &[u8] { + &self.e[..self.e_len as usize] + } + + /// Encrypt `msg` with RSAES-OAEP, returning the fixed-size ciphertext. + #[cfg(random)] + pub fn encrypt(&self, rng: &RNG, msg: &[u8]) -> Result, i32> { + self.encrypt_inner(rng, msg, None) + } + + /// Encrypt `msg` with RSAES-OAEP using an associated `label`, returning + /// the fixed-size ciphertext. + #[cfg(random)] + pub fn encrypt_with_label(&self, rng: &RNG, msg: &[u8], label: &[u8]) -> Result, i32> { + self.encrypt_inner(rng, msg, Some(label)) + } + + #[cfg(random)] + fn encrypt_inner(&self, rng: &RNG, msg: &[u8], label: Option<&[u8]>) -> Result, i32> { + let mut rsa = RSA::new_public_from_raw(&self.n, self.exponent())?; + let mut out = [0u8; N]; + let len = rsa.public_encrypt_oaep_ex(msg, &mut out, H::HASH_TYPE, H::MGF, label, rng)?; + if len != N { + return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); + } + Ok(Ciphertext(out)) + } +} + +/// RSA OAEP decrypting (private) key. +/// +/// `H` selects the OAEP hash; `N` is the expected modulus size in bytes +/// (e.g. `256` for RSA-2048, `384` for RSA-3072). +pub struct DecryptingKey { + inner: RSA, + _hash: PhantomData, +} + +impl DecryptingKey { + /// Generate a fresh `N * 8`-bit RSA key with public exponent 65537. The + /// `rng` is consumed and bound to the key for blinding during decryption. + #[cfg(all(random, rsa_keygen))] + pub fn generate(rng: RNG) -> Result { + let bits: i32 = (N * 8).try_into().map_err(|_| sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG)?; + let mut rsa = RSA::generate(bits, 65537, &rng)?; + rsa.set_rng(rng)?; + Ok(Self { inner: rsa, _hash: PhantomData }) + } + + /// Adopt an existing [`RSA`] key, verifying its modulus size in bytes + /// matches `N`. The `rng` is consumed and bound to the key for blinding + /// during decryption. + #[cfg(random)] + pub fn from_rsa(rsa: RSA, rng: RNG) -> Result { + check_modulus_size(&rsa, N)?; + let mut rsa = rsa; + rsa.set_rng(rng)?; + Ok(Self { inner: rsa, _hash: PhantomData }) + } + + /// Construct a decrypting key from a DER-encoded PKCS#1 private key. The + /// `rng` is consumed and bound to the key for blinding during decryption. + #[cfg(random)] + pub fn from_private_der(der: &[u8], rng: RNG) -> Result { + let rsa = RSA::new_from_der(der)?; + Self::from_rsa(rsa, rng) + } + + /// Borrow the inner [`RSA`] key. + pub fn as_rsa(&self) -> &RSA { + &self.inner + } + + /// Consume the decrypting key and return its inner [`RSA`]. + pub fn into_rsa(self) -> RSA { + self.inner + } + + /// Derive the matching [`EncryptingKey`] from this decrypting key. + pub fn encrypting_key(&self) -> Result, i32> { + EncryptingKey::from_rsa(&self.inner) + } + + /// Decrypt `ciphertext` and write the recovered plaintext into `out`, + /// returning the plaintext length. + pub fn decrypt(&mut self, ciphertext: &Ciphertext, out: &mut [u8]) -> Result { + self.decrypt_inner(ciphertext, out, None) + } + + /// Decrypt `ciphertext` with an associated `label` and write the + /// recovered plaintext into `out`, returning the plaintext length. + pub fn decrypt_with_label(&mut self, ciphertext: &Ciphertext, out: &mut [u8], label: &[u8]) -> Result { + self.decrypt_inner(ciphertext, out, Some(label)) + } + + fn decrypt_inner(&mut self, ciphertext: &Ciphertext, out: &mut [u8], label: Option<&[u8]>) -> Result { + self.inner.private_decrypt_oaep_ex(&ciphertext.0, out, H::HASH_TYPE, H::MGF, label) + } +} diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/rsa_pkcs1v15.rs b/wrapper/rust/wolfssl-wolfcrypt/src/rsa_pkcs1v15.rs index 576f63e222..c174bf5d5a 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/rsa_pkcs1v15.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/rsa_pkcs1v15.rs @@ -260,9 +260,15 @@ impl VerifyingKey { let mut e = [0u8; MAX_E_LEN]; let mut n_len: u32 = n.len() as u32; let mut e_len: u32 = e.len() as u32; + #[cfg(rsa_const_api)] + let key = &rsa.wc_rsakey; + // SAFETY: older wolfSSL declared the first arg as non-const, but the + // function only reads from the key (newer versions declare it const). + #[cfg(not(rsa_const_api))] + let key = core::ptr::addr_of!(rsa.wc_rsakey) as *mut sys::RsaKey; let rc = unsafe { sys::wc_RsaFlattenPublicKey( - &rsa.wc_rsakey, + key, e.as_mut_ptr(), &mut e_len, n.as_mut_ptr(), &mut n_len, ) @@ -328,9 +334,15 @@ impl Keypair for SigningKey { let mut e = [0u8; MAX_E_LEN]; let mut n_len: u32 = n.len() as u32; let mut e_len: u32 = e.len() as u32; + #[cfg(rsa_const_api)] + let key = &self.inner.wc_rsakey; + // SAFETY: older wolfSSL declared the first arg as non-const, but the + // function only reads from the key (newer versions declare it const). + #[cfg(not(rsa_const_api))] + let key = core::ptr::addr_of!(self.inner.wc_rsakey) as *mut sys::RsaKey; let rc = unsafe { sys::wc_RsaFlattenPublicKey( - &self.inner.wc_rsakey, + key, e.as_mut_ptr(), &mut e_len, n.as_mut_ptr(), &mut n_len, ) diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/scrypt_password_hash.rs b/wrapper/rust/wolfssl-wolfcrypt/src/scrypt_password_hash.rs new file mode 100644 index 0000000000..64770fb9ee --- /dev/null +++ b/wrapper/rust/wolfssl-wolfcrypt/src/scrypt_password_hash.rs @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL 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. + * + * wolfSSL 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 + */ + +/*! +RustCrypto `password-hash` trait implementations for wolfCrypt scrypt. + +This module provides [`Scrypt`], a type that implements the +[`PasswordHasher`] and [`CustomizedPasswordHasher`] traits from the +`password-hash` crate, backed by the wolfCrypt scrypt implementation. The +blanket [`PasswordVerifier`] implementation is also available, allowing +verification of existing password hashes. + +Password hashes are represented in the +[PHC string format](https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md): + +```text +$scrypt$ln=,r=,p=

$$ +``` + +This is the same encoding used by the RustCrypto `scrypt` crate. + +[`PasswordHasher`]: password_hash::PasswordHasher +[`CustomizedPasswordHasher`]: password_hash::CustomizedPasswordHasher +[`PasswordVerifier`]: password_hash::PasswordVerifier +*/ + +#![cfg(all(feature = "password-hash", kdf_scrypt))] + +use password_hash::phc::{Ident, Output, ParamsString, PasswordHash, Salt}; +use password_hash::{CustomizedPasswordHasher, Error, Result, Version}; + +use crate::kdf; + +const SCRYPT_IDENT: Ident = Ident::new_unwrap("scrypt"); + +/// Recommended `log_n` (cost) parameter. +pub const RECOMMENDED_LOG_N: u8 = 17; + +/// Recommended `r` (block size) parameter. +pub const RECOMMENDED_R: u32 = 8; + +/// Recommended `p` (parallelism) parameter. +pub const RECOMMENDED_P: u32 = 1; + +/// Default output length in bytes. +pub const DEFAULT_OUTPUT_LEN: usize = 32; + +/// scrypt parameters. +#[derive(Clone, Debug)] +pub struct Params { + /// `log_n` (cost): log base 2 of the iteration count. Iterations = + /// `1 << log_n`. + pub log_n: u8, + /// `r`: block size in 128-byte octets. + pub r: u32, + /// `p`: parallelism factor. + pub p: u32, + /// Desired output hash length in bytes. + pub output_len: usize, +} + +impl Default for Params { + fn default() -> Self { + Params { + log_n: RECOMMENDED_LOG_N, + r: RECOMMENDED_R, + p: RECOMMENDED_P, + output_len: DEFAULT_OUTPUT_LEN, + } + } +} + +impl Params { + /// Validate the parameters against wolfCrypt's accepted ranges. + fn validate(&self) -> Result<()> { + if self.r == 0 || self.r > 8 { + return Err(Error::ParamInvalid { name: "r" }); + } + if self.p == 0 { + return Err(Error::ParamInvalid { name: "p" }); + } + + // wolfCrypt: cost < 128 * r / 8. + let log_n_cutoff = (128u32 * self.r) / 8; + if self.log_n == 0 || u32::from(self.log_n) >= log_n_cutoff { + return Err(Error::ParamInvalid { name: "ln" }); + } + if self.output_len == 0 || self.output_len > Output::MAX_LENGTH { + return Err(Error::ParamInvalid { name: "l" }); + } + + // wolfCrypt additionally validates that (1 << cost) * (128 * r) fits in a 32-bit word. + let max_n = u32::MAX / (128 * self.r); + let n = 1u32 + .checked_shl(self.log_n as u32) + .ok_or(Error::ParamInvalid { name: "ln" })?; + if n > max_n { + return Err(Error::ParamInvalid { name: "ln" }); + } + + // wolfCrypt: limit p to avoid 32-bit overflow in internal buffer sizing. + let max_p1 = (u32::MAX / 4) / self.r; + let max_p2 = u32::MAX / (128 * self.r); + let max_p = max_p1.min(max_p2); + if self.p > max_p { + return Err(Error::ParamInvalid { name: "p" }); + } + Ok(()) + } +} + +impl TryFrom<&PasswordHash> for Params { + type Error = Error; + + fn try_from(hash: &PasswordHash) -> Result { + let log_n = hash + .params + .get_decimal("ln") + .ok_or(Error::ParamInvalid { name: "ln" })?; + let log_n = u8::try_from(log_n) + .map_err(|_| Error::ParamInvalid { name: "ln" })?; + + let r = hash + .params + .get_decimal("r") + .ok_or(Error::ParamInvalid { name: "r" })?; + + let p = hash + .params + .get_decimal("p") + .ok_or(Error::ParamInvalid { name: "p" })?; + + let output_len = if let Some(ref h) = hash.hash { + h.len() + } else if let Some(l) = hash.params.get_decimal("l") && + 0 < l && (l as usize) <= Output::MAX_LENGTH { + l as usize + } else { + return Err(Error::ParamInvalid { name: "l" }); + }; + + let params = Params { log_n, r, p, output_len }; + params.validate()?; + Ok(params) + } +} + +/// scrypt password hasher backed by wolfCrypt. +/// +/// Implements the [`PasswordHasher`](password_hash::PasswordHasher) and +/// [`CustomizedPasswordHasher`] traits. A blanket +/// [`PasswordVerifier`](password_hash::PasswordVerifier) implementation is +/// provided by the `password-hash` crate. +/// +/// # Example +/// +/// ```rust +/// #[cfg(kdf_scrypt)] +/// { +/// use password_hash::PasswordHasher; +/// use wolfssl_wolfcrypt::scrypt_password_hash::{Params, Scrypt}; +/// +/// // Use smaller parameters in the doc test to keep it fast. +/// let hasher = Scrypt { +/// params: Params { log_n: 10, r: 8, p: 1, output_len: 32 }, +/// }; +/// let salt = b"0123456789abcdef"; // 16 bytes +/// let hash = hasher.hash_password_with_salt(b"password", salt) +/// .expect("hashing failed"); +/// } +/// ``` +#[derive(Clone, Debug, Default)] +pub struct Scrypt { + /// Default parameters. + pub params: Params, +} + +impl password_hash::PasswordHasher for Scrypt { + fn hash_password_with_salt(&self, password: &[u8], salt: &[u8]) -> Result { + self.hash_password_customized(password, salt, None, None, self.params.clone()) + } +} + +impl CustomizedPasswordHasher for Scrypt { + type Params = Params; + + fn hash_password_customized( + &self, + password: &[u8], + salt: &[u8], + algorithm: Option<&str>, + version: Option, + params: Params, + ) -> Result { + if version.is_some() { + return Err(Error::Version); + } + + if let Some(s) = algorithm { + let ident = Ident::new(s).map_err(|_| Error::Algorithm)?; + if ident != SCRYPT_IDENT { + return Err(Error::Algorithm); + } + } + + params.validate()?; + + let block_size = i32::try_from(params.r) + .map_err(|_| Error::ParamInvalid { name: "r" })?; + let parallel = i32::try_from(params.p) + .map_err(|_| Error::ParamInvalid { name: "p" })?; + + let salt = Salt::new(salt)?; + + let mut out_buf = [0u8; Output::MAX_LENGTH]; + let out_slice = &mut out_buf[..params.output_len]; + kdf::scrypt(password, salt.as_ref(), i32::from(params.log_n), + block_size, parallel, out_slice) + .map_err(|_| Error::Crypto)?; + let output = Output::new(out_slice)?; + + let mut phc_params = ParamsString::new(); + phc_params.add_decimal("ln", u32::from(params.log_n))?; + phc_params.add_decimal("r", params.r)?; + phc_params.add_decimal("p", params.p)?; + + Ok(PasswordHash { + algorithm: SCRYPT_IDENT, + version: None, + params: phc_params, + salt: Some(salt), + hash: Some(output), + }) + } +} diff --git a/wrapper/rust/wolfssl-wolfcrypt/tests/test_aes.rs b/wrapper/rust/wolfssl-wolfcrypt/tests/test_aes.rs index d5a171fd9e..05ceedc78b 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/tests/test_aes.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/tests/test_aes.rs @@ -256,6 +256,34 @@ fn test_cfb_big_msg() { assert_eq!(big_plain, BIG_MSG); } +#[test] +#[cfg(aes_cfb)] +fn test_cfb_encrypt1() { + /* Test vector taken from wolfcrypt aescfb1_test() (AES-128). */ + let key: [u8; 16] = [ + 0xcd,0xef,0x9d,0x06,0x61,0xba,0xe4,0x73, + 0x8d,0x1a,0x58,0xa2,0xa6,0x22,0x8b,0x66 + ]; + let iv: [u8; 16] = [ + 0x4d,0xbb,0xdc,0xaa,0x59,0xf3,0x63,0xc9, + 0x2a,0x3b,0x98,0x43,0xad,0x20,0xe2,0xb7 + ]; + let msg: [u8; 1] = [0xC0]; + let mut enc = CFB::new().expect("Failed to create CFB"); + let mut dec = CFB::new().expect("Failed to create CFB"); + enc.init(&key, &iv).expect("Error with init()"); + dec.init(&key, &iv).expect("Error with init()"); + let mut cipher: [u8; 1] = [0]; + enc.encrypt1(&msg, &mut cipher, 2).expect("Error with encrypt1()"); + assert_eq!(cipher[0], 0x00); + let mut plain: [u8; 1] = [0]; + dec.decrypt1(&cipher, &mut plain, 2).expect("Error with decrypt1()"); + assert_eq!(plain[0], 0xC0); + cipher[0] = 0; + enc.encrypt1(&msg, &mut cipher, 7).expect("Error with encrypt1()"); + assert_eq!(cipher[0], 0x1C); +} + #[test] #[cfg(aes_ctr)] fn test_ctr_encrypt_decrypt() { diff --git a/wrapper/rust/wolfssl-wolfcrypt/tests/test_cmac.rs b/wrapper/rust/wolfssl-wolfcrypt/tests/test_cmac.rs index 09dabcb8b8..9db8d13e3e 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/tests/test_cmac.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/tests/test_cmac.rs @@ -17,6 +17,10 @@ fn test_cmac() { 0x07u8, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44, 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c ]; + let incorrect_cmac = [ + 0x06u8, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44, + 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c + ]; let mut cmac = CMAC::new(&key).expect("Error with new()"); cmac.update(&message).expect("Error with update()"); let mut finalize_out = [0u8; 16]; @@ -28,6 +32,8 @@ fn test_cmac() { assert_eq!(generate_out, finalize_out); let valid = CMAC::verify(&key, &message, &generate_out).expect("Error with verify()"); assert!(valid); + let valid = CMAC::verify(&key, &message, &incorrect_cmac).expect("Error with verify()"); + assert!(!valid); let mut cmac = CMAC::new(&key).expect("Error with new()"); let mut generate_out = [0u8; 16]; @@ -35,4 +41,6 @@ fn test_cmac() { assert_eq!(generate_out, finalize_out); let valid = cmac.verify_ex(&key, &message, &generate_out, None, None).expect("Error with verify_ex()"); assert!(valid); + let valid = cmac.verify_ex(&key, &message, &incorrect_cmac, None, None).expect("Error with verify_ex()"); + assert!(!valid); } diff --git a/wrapper/rust/wolfssl-wolfcrypt/tests/test_rsa.rs b/wrapper/rust/wolfssl-wolfcrypt/tests/test_rsa.rs index c935113433..6914a83baa 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/tests/test_rsa.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/tests/test_rsa.rs @@ -127,6 +127,70 @@ fn test_rsa_direct() { assert_eq!(plain_out, plain); } +#[test] +#[cfg(all(sha256, random, rsa_oaep))] +fn test_rsa_oaep() { + common::setup(); + + let rng = Rc::new(RNG::new().expect("Error creating RNG")); + + let key_path = "../../../certs/client-keyPub.der"; + let der: Vec = fs::read(key_path).expect("Error reading key file"); + let mut rsa = RSA::new_public_from_der(&der).expect("Error with new_public_from_der()"); + rsa.set_shared_rng(Rc::clone(&rng)).expect("Error with set_shared_rng()"); + let plain: &[u8] = b"OAEP plain text test message"; + let mut enc: [u8; 512] = [0; 512]; + let enc_len = rsa.public_encrypt_oaep(plain, &mut enc, RSA::HASH_TYPE_SHA256, RSA::MGF1SHA256, &rng).expect("Error with public_encrypt_oaep()"); + assert!(enc_len > 0 && enc_len <= 512); + + let key_path = "../../../certs/client-key.der"; + let der: Vec = fs::read(key_path).expect("Error reading key file"); + let mut rsa = RSA::new_from_der(&der).expect("Error with new_from_der()"); + rsa.set_shared_rng(Rc::clone(&rng)).expect("Error with set_shared_rng()"); + let mut plain_out: [u8; 512] = [0; 512]; + let dec_len = rsa.private_decrypt_oaep(&enc[0..enc_len], &mut plain_out, RSA::HASH_TYPE_SHA256, RSA::MGF1SHA256).expect("Error with private_decrypt_oaep()"); + assert_eq!(dec_len, plain.len()); + assert_eq!(plain_out[0..dec_len], *plain); + + // Tampered ciphertext should fail to decrypt. + let mut bad = enc; + bad[0] ^= 0xFF; + assert!(rsa.private_decrypt_oaep(&bad[0..enc_len], &mut plain_out, RSA::HASH_TYPE_SHA256, RSA::MGF1SHA256).is_err()); +} + +#[test] +#[cfg(all(sha256, random, rsa_oaep))] +fn test_rsa_oaep_with_label() { + common::setup(); + + let rng = Rc::new(RNG::new().expect("Error creating RNG")); + let label: &[u8] = b"a non-empty OAEP label"; + + let key_path = "../../../certs/client-keyPub.der"; + let der: Vec = fs::read(key_path).expect("Error reading key file"); + let mut rsa = RSA::new_public_from_der(&der).expect("Error with new_public_from_der()"); + rsa.set_shared_rng(Rc::clone(&rng)).expect("Error with set_shared_rng()"); + let plain: &[u8] = b"OAEP with label"; + let mut enc: [u8; 512] = [0; 512]; + let enc_len = rsa.public_encrypt_oaep_ex(plain, &mut enc, RSA::HASH_TYPE_SHA256, RSA::MGF1SHA256, Some(label), &rng).expect("Error with public_encrypt_oaep_ex()"); + assert!(enc_len > 0 && enc_len <= 512); + + let key_path = "../../../certs/client-key.der"; + let der: Vec = fs::read(key_path).expect("Error reading key file"); + let mut rsa = RSA::new_from_der(&der).expect("Error with new_from_der()"); + rsa.set_shared_rng(Rc::clone(&rng)).expect("Error with set_shared_rng()"); + + // Wrong label must fail. + let mut plain_out: [u8; 512] = [0; 512]; + let wrong_label: &[u8] = b"wrong label"; + assert!(rsa.private_decrypt_oaep_ex(&enc[0..enc_len], &mut plain_out, RSA::HASH_TYPE_SHA256, RSA::MGF1SHA256, Some(wrong_label)).is_err()); + + // Correct label succeeds. + let dec_len = rsa.private_decrypt_oaep_ex(&enc[0..enc_len], &mut plain_out, RSA::HASH_TYPE_SHA256, RSA::MGF1SHA256, Some(label)).expect("Error with private_decrypt_oaep_ex()"); + assert_eq!(dec_len, plain.len()); + assert_eq!(plain_out[0..dec_len], *plain); +} + #[test] #[cfg(random)] fn test_rsa_ssl() { diff --git a/wrapper/rust/wolfssl-wolfcrypt/tests/test_rsa_oaep.rs b/wrapper/rust/wolfssl-wolfcrypt/tests/test_rsa_oaep.rs new file mode 100644 index 0000000000..58b853ec68 --- /dev/null +++ b/wrapper/rust/wolfssl-wolfcrypt/tests/test_rsa_oaep.rs @@ -0,0 +1,139 @@ +#![cfg(all(rsa, rsa_oaep, random))] + +mod common; + +use std::fs; +use wolfssl_wolfcrypt::random::RNG; + +#[test] +#[cfg(all(sha256, rsa_keygen))] +fn test_rsa2048_sha256_oaep_round_trip() { + use wolfssl_wolfcrypt::rsa_oaep::{Ciphertext, DecryptingKey, EncryptingKey, Sha256}; + + common::setup(); + + let pad_rng = RNG::new().expect("RNG"); + let mut dk: DecryptingKey = + DecryptingKey::generate(RNG::new().expect("RNG")).expect("generate 2048"); + let ek: EncryptingKey = dk.encrypting_key().expect("encrypting_key"); + + let msg = b"rsa oaep sha256 round trip test"; + let ct: Ciphertext<256> = ek.encrypt(&pad_rng, msg).expect("encrypt"); + + // Encoding round-trip. + let bytes = ct.to_bytes(); + assert_eq!(bytes.len(), 256); + let ct2 = Ciphertext::<256>::try_from(bytes.as_ref()).expect("parse ct"); + assert_eq!(ct, ct2); + + // Wrong length must fail. + assert!(Ciphertext::<256>::try_from(&bytes[..255]).is_err()); + + let mut out = [0u8; 256]; + let n = dk.decrypt(&ct, &mut out).expect("decrypt"); + assert_eq!(&out[..n], msg); + + // EncryptingKey rebuilt from raw components is equivalent. + let ek_copy = EncryptingKey::::from_components(ek.modulus(), ek.exponent()) + .expect("from_components"); + assert_eq!(ek, ek_copy); + let ct3: Ciphertext<256> = ek_copy.encrypt(&pad_rng, msg).expect("encrypt via rebuilt ek"); + let n2 = dk.decrypt(&ct3, &mut out).expect("decrypt via rebuilt ek"); + assert_eq!(&out[..n2], msg); +} + +#[test] +#[cfg(sha384)] +fn test_rsa2048_sha384_oaep_with_der_keys() { + use wolfssl_wolfcrypt::rsa_oaep::{DecryptingKey, EncryptingKey, Sha384}; + + common::setup(); + + let pad_rng = RNG::new().expect("RNG"); + + let pub_der: Vec = fs::read("../../../certs/client-keyPub.der") + .expect("read client-keyPub.der"); + let priv_der: Vec = fs::read("../../../certs/client-key.der") + .expect("read client-key.der"); + + let ek: EncryptingKey = EncryptingKey::from_public_der(&pub_der) + .expect("EncryptingKey::from_public_der"); + let mut dk: DecryptingKey = DecryptingKey::from_private_der(&priv_der, RNG::new().expect("RNG")) + .expect("DecryptingKey::from_private_der"); + + let msg = b"oaep sha384 + der keys"; + let ct = ek.encrypt(&pad_rng, msg).expect("encrypt"); + let mut out = [0u8; 256]; + let n = dk.decrypt(&ct, &mut out).expect("decrypt"); + assert_eq!(&out[..n], msg); +} + +#[test] +#[cfg(all(sha256, rsa_keygen))] +fn test_oaep_label_round_trip_and_mismatch() { + use wolfssl_wolfcrypt::rsa_oaep::{DecryptingKey, EncryptingKey, Sha256}; + + common::setup(); + + let pad_rng = RNG::new().expect("RNG"); + let mut dk: DecryptingKey = + DecryptingKey::generate(RNG::new().expect("RNG")).expect("generate 2048"); + let ek: EncryptingKey = dk.encrypting_key().expect("encrypting_key"); + + let msg = b"oaep with label"; + let label: &[u8] = b"context-info"; + let ct = ek.encrypt_with_label(&pad_rng, msg, label).expect("encrypt_with_label"); + + let mut out = [0u8; 256]; + + // Correct label succeeds. + let n = dk.decrypt_with_label(&ct, &mut out, label).expect("decrypt_with_label"); + assert_eq!(&out[..n], msg); + + // Wrong label must fail. + assert!(dk.decrypt_with_label(&ct, &mut out, b"other-label").is_err()); + + // Missing label must fail. + assert!(dk.decrypt(&ct, &mut out).is_err()); +} + +#[test] +#[cfg(all(sha256, rsa_keygen))] +fn test_oaep_modulus_size_mismatch_rejected() { + use wolfssl_wolfcrypt::rsa::RSA; + use wolfssl_wolfcrypt::rsa_oaep::{DecryptingKey, EncryptingKey, Sha256}; + + common::setup(); + + let rng = RNG::new().expect("RNG"); + let rsa2048 = RSA::generate(2048, 65537, &rng).expect("generate"); + + let ek_result: Result, _> = EncryptingKey::from_rsa(&rsa2048); + assert!(ek_result.is_err(), "encrypting key modulus mismatch must be rejected"); + + let dk_rng = RNG::new().expect("RNG"); + let dk_result: Result, _> = DecryptingKey::from_rsa(rsa2048, dk_rng); + assert!(dk_result.is_err(), "decrypting key modulus mismatch must be rejected"); +} + +#[test] +#[cfg(all(sha256, rsa_keygen))] +fn test_oaep_tampered_ciphertext_rejected() { + use wolfssl_wolfcrypt::rsa_oaep::{DecryptingKey, Sha256}; + + common::setup(); + + let pad_rng = RNG::new().expect("RNG"); + let mut dk: DecryptingKey = + DecryptingKey::generate(RNG::new().expect("RNG")).expect("generate 2048"); + let ek = dk.encrypting_key().expect("encrypting_key"); + + let msg = b"some bytes"; + let mut ct = ek.encrypt(&pad_rng, msg).expect("encrypt"); + let mut bytes = ct.to_bytes(); + bytes[0] ^= 0x01; + ct = wolfssl_wolfcrypt::rsa_oaep::Ciphertext::from_bytes(bytes); + + let mut out = [0u8; 256]; + assert!(dk.decrypt(&ct, &mut out).is_err()); +} diff --git a/wrapper/rust/wolfssl-wolfcrypt/tests/test_scrypt_password_hash.rs b/wrapper/rust/wolfssl-wolfcrypt/tests/test_scrypt_password_hash.rs new file mode 100644 index 0000000000..bbaec331cc --- /dev/null +++ b/wrapper/rust/wolfssl-wolfcrypt/tests/test_scrypt_password_hash.rs @@ -0,0 +1,164 @@ +#![cfg(all(feature = "password-hash", kdf_scrypt))] + +mod common; + +use password_hash::phc::PasswordHash; +use password_hash::{CustomizedPasswordHasher, PasswordHasher, PasswordVerifier}; +use wolfssl_wolfcrypt::scrypt_password_hash::*; + +/// Use modest scrypt parameters in tests to keep them fast while still +/// exercising the full code path. +fn test_params() -> Params { + Params { log_n: 10, r: 8, p: 1, output_len: 32 } +} + +#[test] +fn test_hash_and_verify() { + common::setup(); + + let hasher = Scrypt { params: test_params() }; + let salt = b"0123456789abcdef"; + let password = b"hunter2"; + + let hash = hasher + .hash_password_with_salt(password, salt) + .expect("hashing failed"); + + assert!(hash.salt.is_some()); + assert!(hash.hash.is_some()); + assert_eq!(hash.hash.as_ref().unwrap().len(), 32); + + hasher + .verify_password(password, &hash) + .expect("verification of correct password failed"); + + assert!(hasher.verify_password(b"wrong_password", &hash).is_err()); +} + +#[test] +fn test_hash_roundtrip_phc_string() { + common::setup(); + + let hasher = Scrypt { params: test_params() }; + let salt = b"0123456789abcdef"; + let password = b"password"; + + let hash = hasher + .hash_password_with_salt(password, salt) + .expect("hashing failed"); + + let phc_string = hash.to_string(); + assert!(phc_string.starts_with("$scrypt$")); + assert!(phc_string.contains("ln=10")); + assert!(phc_string.contains("r=8")); + assert!(phc_string.contains("p=1")); + + let parsed = PasswordHash::new(&phc_string).expect("parsing PHC string failed"); + + hasher + .verify_password(password, &parsed) + .expect("verification of parsed hash failed"); +} + +#[test] +fn test_default_params() { + common::setup(); + + let hasher = Scrypt::default(); + assert_eq!(hasher.params.log_n, RECOMMENDED_LOG_N); + assert_eq!(hasher.params.r, RECOMMENDED_R); + assert_eq!(hasher.params.p, RECOMMENDED_P); + assert_eq!(hasher.params.output_len, DEFAULT_OUTPUT_LEN); +} + +#[test] +fn test_customized_hash() { + common::setup(); + + let hasher = Scrypt::default(); + let salt = b"0123456789abcdef"; + let password = b"password"; + let custom = Params { log_n: 11, r: 8, p: 2, output_len: 48 }; + + let hash = hasher + .hash_password_with_params(password, salt, custom) + .expect("customized hashing failed"); + + assert_eq!(hash.hash.as_ref().unwrap().len(), 48); + assert_eq!(hash.params.get_decimal("ln"), Some(11)); + assert_eq!(hash.params.get_decimal("r"), Some(8)); + assert_eq!(hash.params.get_decimal("p"), Some(2)); + + hasher + .verify_password(password, &hash) + .expect("customized hash verification failed"); +} + +#[test] +fn test_version_rejected() { + common::setup(); + + let hasher = Scrypt { params: test_params() }; + let salt = b"0123456789abcdef"; + + let result = hasher.hash_password_customized( + b"password", salt, None, Some(1), test_params()); + assert!(result.is_err()); +} + +#[test] +fn test_unknown_algorithm_rejected() { + common::setup(); + + let hasher = Scrypt { params: test_params() }; + let salt = b"0123456789abcdef"; + + let result = hasher.hash_password_customized( + b"password", salt, Some("argon2id"), None, test_params()); + assert!(result.is_err()); +} + +#[test] +fn test_invalid_params_rejected() { + common::setup(); + + let hasher = Scrypt { params: test_params() }; + let salt = b"0123456789abcdef"; + + // r out of range + let bad = Params { log_n: 10, r: 9, p: 1, output_len: 32 }; + assert!(hasher.hash_password_with_params(b"pw", salt, bad).is_err()); + + // p must be > 0 + let bad = Params { log_n: 10, r: 8, p: 0, output_len: 32 }; + assert!(hasher.hash_password_with_params(b"pw", salt, bad).is_err()); + + // log_n must be > 0 + let bad = Params { log_n: 0, r: 8, p: 1, output_len: 32 }; + assert!(hasher.hash_password_with_params(b"pw", salt, bad).is_err()); +} + +#[test] +fn test_deterministic_output() { + common::setup(); + + let hasher = Scrypt { params: test_params() }; + let salt = b"0123456789abcdef"; + let password = b"password"; + + let h1 = hasher.hash_password_with_salt(password, salt).unwrap(); + let h2 = hasher.hash_password_with_salt(password, salt).unwrap(); + assert_eq!(h1.hash, h2.hash); +} + +#[test] +fn test_different_salts_produce_different_hashes() { + common::setup(); + + let hasher = Scrypt { params: test_params() }; + let password = b"password"; + + let h1 = hasher.hash_password_with_salt(password, b"salt_aaaaaaaaaa01").unwrap(); + let h2 = hasher.hash_password_with_salt(password, b"salt_aaaaaaaaaa02").unwrap(); + assert_ne!(h1.hash, h2.hash); +} diff --git a/zephyr/Kconfig b/zephyr/Kconfig index fb6084893a..e6cb1cb060 100644 --- a/zephyr/Kconfig +++ b/zephyr/Kconfig @@ -113,6 +113,13 @@ config WOLFSSL_ALWAYS_VERIFY_CB help Invoke verify callback on success as well as failure (WOLFSSL_ALWAYS_VERIFY_CB) +config WOLFSSL_OPENSSL_EXTRA_X509_SMALL + bool "wolfSSL minimal X509 compat APIs" + help + Define OPENSSL_EXTRA_X509_SMALL. Exposes a small subset of X509 + helpers (wolfSSL_X509_free, wolfSSL_get_verify_result, ...) without + the rest of OPENSSL_EXTRA. + config WOLFCRYPT_ARMASM bool "wolfCrypt ARM Assembly support" depends on WOLFSSL_BUILTIN diff --git a/zephyr/samples/wolfssl_tls_sock/prj-no-malloc.conf b/zephyr/samples/wolfssl_tls_sock/prj-no-malloc.conf index 830b1944db..d14a77e3b5 100644 --- a/zephyr/samples/wolfssl_tls_sock/prj-no-malloc.conf +++ b/zephyr/samples/wolfssl_tls_sock/prj-no-malloc.conf @@ -3,22 +3,12 @@ CONFIG_MAIN_STACK_SIZE=655360 CONFIG_ENTROPY_GENERATOR=y CONFIG_INIT_STACKS=y -# General config -CONFIG_NEWLIB_LIBC=y - -# Pthreads -CONFIG_PTHREAD_IPC=y - -# Clock for time() -CONFIG_POSIX_CLOCK=y - # Networking config CONFIG_NETWORKING=y CONFIG_NET_IPV4=y CONFIG_NET_IPV6=n CONFIG_NET_TCP=y CONFIG_NET_SOCKETS=y -CONFIG_NET_SOCKETS_POSIX_NAMES=y CONFIG_NET_TEST=y CONFIG_NET_LOOPBACK=y diff --git a/zephyr/user_settings.h b/zephyr/user_settings.h index 13c689da6d..5198ad5eab 100644 --- a/zephyr/user_settings.h +++ b/zephyr/user_settings.h @@ -148,6 +148,15 @@ extern "C" { #define WOLFSSL_ALWAYS_VERIFY_CB #endif +/* Lightweight X509 helpers (wolfSSL_X509_free, wolfSSL_get_verify_result, + * wolfSSL_X509_load_certificate_buffer) without pulling in the full + * OPENSSL_EXTRA surface. Apps needing full OpenSSL compat can override + * user_settings.h via CONFIG_WOLFSSL_SETTINGS_FILE. + */ +#if defined(CONFIG_WOLFSSL_OPENSSL_EXTRA_X509_SMALL) + #define OPENSSL_EXTRA_X509_SMALL +#endif + /* DTLS */ #if defined(CONFIG_WOLFSSL_DTLS) #define WOLFSSL_DTLS