From 58d3d8428095dc184f0455092f88e757116014b8 Mon Sep 17 00:00:00 2001 From: Mark Atwood Date: Thu, 30 Apr 2026 11:04:27 -0700 Subject: [PATCH 001/118] fix: EVP_CIPHER_iv_length returns 0 for CFB/OFB modes --- tests/api/test_evp_cipher.c | 44 +++++++++++++++++++++++++++++ wolfcrypt/src/evp.c | 55 +++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) diff --git a/tests/api/test_evp_cipher.c b/tests/api/test_evp_cipher.c index 1e88da9979..13649c8882 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/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index 40bca5578f..5fc22650e0 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -9960,6 +9960,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) From f9d6a0339ff176bbf6d881c0b6655a7ace3cb633 Mon Sep 17 00:00:00 2001 From: Mark Atwood Date: Thu, 30 Apr 2026 13:57:51 -0700 Subject: [PATCH 002/118] fix: add CFB128 and OFB cases to wolfSSL_EVP_get_cipherbynid The iv_length test used EVP_get_cipherbynid(NID_aes_128_cfb128) which returned NULL because the switch had no CFB128 or OFB cases, causing a segfault in EVP_CIPHER_iv_length(NULL). --- wolfcrypt/src/evp.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index 5fc22650e0..a4b5ac4365 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -5674,6 +5674,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 From ecdf170a917300d838fbbe0e7db90d0bfa5d3f2e Mon Sep 17 00:00:00 2001 From: Andrew Hutchings Date: Mon, 18 May 2026 14:28:17 -0700 Subject: [PATCH 003/118] Fix SHAKE with STM32MP13 and add simulator This fixes the fact that you can't compile SHAKE when SHA-3 hardware acceleration is enabled for STM32. It also adds the STM32MP13 emulator with hardware support from the simulators repo. --- .github/workflows/stm32-sim.yml | 33 ++++++++++++++++++++++++++++++--- wolfcrypt/src/sha3.c | 30 ++++++++++++++++++++++++------ 2 files changed, 54 insertions(+), 9 deletions(-) diff --git a/.github/workflows/stm32-sim.yml b/.github/workflows/stm32-sim.yml index 8beb42921c..392820bad4 100644 --- a/.github/workflows/stm32-sim.yml +++ b/.github/workflows/stm32-sim.yml @@ -14,12 +14,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: @@ -35,6 +43,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 @@ -42,7 +52,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/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 */ From 1fb8cf0d619ea50de99b797e12e927cbd597d108 Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Thu, 9 Apr 2026 16:53:39 +0200 Subject: [PATCH 004/118] MAX32666 bare-metal SHA accelerator --- wolfcrypt/src/port/maxim/max3266x.c | 873 ++++++++++++++---------- wolfssl/wolfcrypt/port/maxim/max3266x.h | 141 ++-- 2 files changed, 553 insertions(+), 461 deletions(-) diff --git a/wolfcrypt/src/port/maxim/max3266x.c b/wolfcrypt/src/port/maxim/max3266x.c index e326ecadbe..efbec9424a 100644 --- a/wolfcrypt/src/port/maxim/max3266x.c +++ b/wolfcrypt/src/port/maxim/max3266x.c @@ -136,67 +136,126 @@ int wc_MxcAesCryptoCb(wc_CryptoInfo* info) #ifdef MAX3266X_SHA_CB -/* 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, - byte* digest, MXC_TPU_HASH_TYPE algo) +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, int stateWords, + unsigned int blockSz, unsigned int digestSz, + MXC_TPU_HASH_TYPE algo, + const unsigned char* in, unsigned int inSz, + unsigned char* outDigest) { - if (in != NULL && digest == NULL) { + if (in != NULL && outDigest == NULL) { MAX3266X_MSG("Update CB"); - return _wc_Hash_Grow(msg, used, len, in, (int)inSz, heap); + return wc_MXC_TPU_SHA_Update(digest, buffer, buffLen, loLen, hiLen, + stateWords, blockSz, algo, in, inSz); } - if (in == NULL && digest != NULL) { + if (in == NULL && outDigest != NULL) { + int ret; MAX3266X_MSG("Final CB"); - return wc_MXC_TPU_SHA_Final(msg, used, len, heap, digest, algo); + 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 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, + 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->msg, - &info->hash.sha1->used, &info->hash.sha1->len, - info->hash.sha1->heap, info->hash.in, - info->hash.inSz, info->hash.digest, - MXC_TPU_HASH_SHA1); + return wc_MxcShaCbDispatch( + info->hash.sha1->digest, + info->hash.sha1->buffer, + &info->hash.sha1->buffLen, + &info->hash.sha1->loLen, &info->hash.sha1->hiLen, + 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->msg, - &info->hash.sha224->used, &info->hash.sha224->len, - info->hash.sha224->heap, info->hash.in, - info->hash.inSz, info->hash.digest, - MXC_TPU_HASH_SHA224); + return wc_MxcShaCbDispatch( + info->hash.sha224->digest, + info->hash.sha224->buffer, + &info->hash.sha224->buffLen, + &info->hash.sha224->loLen, &info->hash.sha224->hiLen, + 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->msg, - &info->hash.sha256->used, &info->hash.sha256->len, - info->hash.sha256->heap, info->hash.in, - info->hash.inSz, info->hash.digest, - MXC_TPU_HASH_SHA256); + return wc_MxcShaCbDispatch( + info->hash.sha256->digest, + info->hash.sha256->buffer, + &info->hash.sha256->buffLen, + &info->hash.sha256->loLen, &info->hash.sha256->hiLen, + 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_MxcShaCbDispatch(&info->hash.sha384->msg, - &info->hash.sha384->used, &info->hash.sha384->len, - info->hash.sha384->heap, info->hash.in, - info->hash.inSz, info->hash.digest, - MXC_TPU_HASH_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_MxcShaCbDispatch(&info->hash.sha512->msg, - &info->hash.sha512->used, &info->hash.sha512->len, - info->hash.sha512->heap, info->hash.in, - info->hash.inSz, info->hash.digest, - MXC_TPU_HASH_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); @@ -207,6 +266,8 @@ int wc_MxcShaCryptoCb(wc_CryptoInfo* info) #ifdef WOLF_CRYPTO_CB_COPY static int wc_MxcCopyCb(wc_CryptoInfo* info) { + word32 sz; + if (info == NULL || info->copy.src == NULL || info->copy.dst == NULL) { return BAD_FUNC_ARG; } @@ -214,123 +275,29 @@ static int wc_MxcCopyCb(wc_CryptoInfo* info) switch (info->copy.type) { #ifdef MAX3266X_SHA_CB #ifndef NO_SHA - case WC_HASH_TYPE_SHA: - return wc_MXC_TPU_SHA_Copy(info->copy.src, info->copy.dst, - sizeof(wc_Sha), - &((wc_Sha*)info->copy.dst)->msg, - &((wc_Sha*)info->copy.dst)->used, - &((wc_Sha*)info->copy.dst)->len, - ((wc_Sha*)info->copy.dst)->heap, - ((wc_Sha*)info->copy.src)->heap); + case WC_HASH_TYPE_SHA: sz = sizeof(wc_Sha); break; #endif #ifdef WOLFSSL_SHA224 - case WC_HASH_TYPE_SHA224: - return wc_MXC_TPU_SHA_Copy(info->copy.src, info->copy.dst, - sizeof(wc_Sha224), - &((wc_Sha224*)info->copy.dst)->msg, - &((wc_Sha224*)info->copy.dst)->used, - &((wc_Sha224*)info->copy.dst)->len, - ((wc_Sha224*)info->copy.dst)->heap, - ((wc_Sha224*)info->copy.src)->heap); + case WC_HASH_TYPE_SHA224: sz = sizeof(wc_Sha224); break; #endif #ifndef NO_SHA256 - case WC_HASH_TYPE_SHA256: - return wc_MXC_TPU_SHA_Copy(info->copy.src, info->copy.dst, - sizeof(wc_Sha256), - &((wc_Sha256*)info->copy.dst)->msg, - &((wc_Sha256*)info->copy.dst)->used, - &((wc_Sha256*)info->copy.dst)->len, - ((wc_Sha256*)info->copy.dst)->heap, - ((wc_Sha256*)info->copy.src)->heap); + case WC_HASH_TYPE_SHA256: sz = sizeof(wc_Sha256); break; #endif #ifdef WOLFSSL_SHA384 - case WC_HASH_TYPE_SHA384: - return wc_MXC_TPU_SHA_Copy(info->copy.src, info->copy.dst, - sizeof(wc_Sha384), - &((wc_Sha384*)info->copy.dst)->msg, - &((wc_Sha384*)info->copy.dst)->used, - &((wc_Sha384*)info->copy.dst)->len, - ((wc_Sha384*)info->copy.dst)->heap, - ((wc_Sha384*)info->copy.src)->heap); + case WC_HASH_TYPE_SHA384: sz = sizeof(wc_Sha384); break; #endif #ifdef WOLFSSL_SHA512 - case WC_HASH_TYPE_SHA512: - return wc_MXC_TPU_SHA_Copy(info->copy.src, info->copy.dst, - sizeof(wc_Sha512), - &((wc_Sha512*)info->copy.dst)->msg, - &((wc_Sha512*)info->copy.dst)->used, - &((wc_Sha512*)info->copy.dst)->len, - ((wc_Sha512*)info->copy.dst)->heap, - ((wc_Sha512*)info->copy.src)->heap); + case WC_HASH_TYPE_SHA512: 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 /* WOLF_CRYPTO_CB_COPY */ -#ifdef WOLF_CRYPTO_CB_FREE -static int wc_MxcFreeCb(wc_CryptoInfo* info) -{ - if (info == NULL || info->free.obj == NULL) { - return BAD_FUNC_ARG; - } - - switch (info->free.type) { -#ifdef MAX3266X_SHA_CB - #ifndef NO_SHA - case WC_HASH_TYPE_SHA: - wc_MXC_TPU_SHA_FreeCtx(info->free.obj, sizeof(wc_Sha), - &((wc_Sha*)info->free.obj)->msg, - &((wc_Sha*)info->free.obj)->used, - &((wc_Sha*)info->free.obj)->len, - ((wc_Sha*)info->free.obj)->heap); - return 0; - #endif - #ifdef WOLFSSL_SHA224 - case WC_HASH_TYPE_SHA224: - wc_MXC_TPU_SHA_FreeCtx(info->free.obj, sizeof(wc_Sha224), - &((wc_Sha224*)info->free.obj)->msg, - &((wc_Sha224*)info->free.obj)->used, - &((wc_Sha224*)info->free.obj)->len, - ((wc_Sha224*)info->free.obj)->heap); - return 0; - #endif - #ifndef NO_SHA256 - case WC_HASH_TYPE_SHA256: - wc_MXC_TPU_SHA_FreeCtx(info->free.obj, sizeof(wc_Sha256), - &((wc_Sha256*)info->free.obj)->msg, - &((wc_Sha256*)info->free.obj)->used, - &((wc_Sha256*)info->free.obj)->len, - ((wc_Sha256*)info->free.obj)->heap); - return 0; - #endif - #ifdef WOLFSSL_SHA384 - case WC_HASH_TYPE_SHA384: - wc_MXC_TPU_SHA_FreeCtx(info->free.obj, sizeof(wc_Sha384), - &((wc_Sha384*)info->free.obj)->msg, - &((wc_Sha384*)info->free.obj)->used, - &((wc_Sha384*)info->free.obj)->len, - ((wc_Sha384*)info->free.obj)->heap); - return 0; - #endif - #ifdef WOLFSSL_SHA512 - case WC_HASH_TYPE_SHA512: - wc_MXC_TPU_SHA_FreeCtx(info->free.obj, sizeof(wc_Sha512), - &((wc_Sha512*)info->free.obj)->msg, - &((wc_Sha512*)info->free.obj)->used, - &((wc_Sha512*)info->free.obj)->len, - ((wc_Sha512*)info->free.obj)->heap); - return 0; - #endif -#endif /* MAX3266X_SHA_CB */ - default: - return WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); - } -} -#endif /* WOLF_CRYPTO_CB_FREE */ - /* General Callback Function to determine ALGO Type */ int wc_MxcCryptoCb(int devIdArg, wc_CryptoInfo* info, void* ctx) { @@ -363,14 +330,10 @@ int wc_MxcCryptoCb(int devIdArg, wc_CryptoInfo* info, void* ctx) ret = wc_MxcCopyCb(info); break; #endif /* WOLF_CRYPTO_CB_COPY */ -#ifdef WOLF_CRYPTO_CB_FREE - case WC_ALGO_TYPE_FREE: - MAX3266X_MSG("Using MXC Free Callback:"); - ret = wc_MxcFreeCb(info); - break; -#endif /* WOLF_CRYPTO_CB_FREE */ + /* No WC_ALGO_TYPE_FREE needed: SHA contexts have no heap + * allocations to clean up. */ 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,169 +654,280 @@ int wc_MxcCb_AesCbcDecrypt(Aes* aes, byte* out, const byte* in, word32 sz) #if defined(MAX3266X_SHA) || defined(MAX3266X_SHA_CB) -/* 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, - unsigned char* digest, - MXC_TPU_HASH_TYPE algo) +/* TPU hash helpers (bare-metal SHA accelerator) */ + +/* Reset TPU, select hash function, and restore intermediate state into + * the HASH_DIGEST registers. Does NOT set INIT - caller provides state. */ +void wc_MXC_TPU_Hash_Setup(MXC_TPU_HASH_TYPE algo, + const unsigned int* state, int stateWords) { - if (digest == NULL) { - return BAD_FUNC_ARG; + 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]; } - if (msg == NULL && msgSz == 0) { - switch (algo) { - #ifndef NO_SHA - case MXC_TPU_HASH_SHA1: - XMEMCPY(digest, MXC_EMPTY_DIGEST_SHA1, WC_SHA_DIGEST_SIZE); - break; - #endif /* NO_SHA */ - #ifdef WOLFSSL_SHA224 - case MXC_TPU_HASH_SHA224: - XMEMCPY(digest, MXC_EMPTY_DIGEST_SHA224, WC_SHA224_DIGEST_SIZE); - break; - #endif /* WOLFSSL_SHA224 */ - #ifndef NO_SHA256 - case MXC_TPU_HASH_SHA256: - XMEMCPY(digest, MXC_EMPTY_DIGEST_SHA256, WC_SHA256_DIGEST_SIZE); - break; - #endif /* NO_SHA256 */ - #ifdef WOLFSSL_SHA384 - case MXC_TPU_HASH_SHA384: - XMEMCPY(digest, MXC_EMPTY_DIGEST_SHA384, WC_SHA384_DIGEST_SIZE); - break; - #endif /* WOLFSSL_SHA384 */ - #ifdef WOLFSSL_SHA512 - case MXC_TPU_HASH_SHA512: - XMEMCPY(digest, MXC_EMPTY_DIGEST_SHA512, WC_SHA512_DIGEST_SIZE); - break; - #endif /* WOLFSSL_SHA512 */ - default: - return BAD_FUNC_ARG; - } - return 1; /* True: empty digest provided */ - } - return 0; /* False: needs hardware processing */ } -/* Compute hash from accumulated message using TPU hardware */ -int wc_MXC_TPU_SHA_GetHash(const unsigned char* msg, unsigned int msgSz, - unsigned char* digest, - MXC_TPU_HASH_TYPE algo) +/* 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; - if (digest == NULL || (msg == NULL && msgSz != 0)) { - return BAD_FUNC_ARG; - } - status = wc_MXC_TPU_SHA_GetDigest(msg, msgSz, digest, algo); - /* True Case that msg is an empty string */ - if (status == 1) { - /* Hardware cannot handle the case of an empty string */ - /* so in the case of this we will provide the hash via software */ + unsigned int fill; + + if (len == 0) { return 0; } - /* False Case where msg needs to be processed */ - else if (status == 0) { - status = wolfSSL_HwHashMutexLock(); /* Set Mutex */ - if (status != 0) { /* Mutex Call Check */ - return status; + + /* Update total length */ + { + unsigned int oldLo = *loLen; + *loLen += len; + if (*loLen < oldLo) { + (*hiLen)++; } - MXC_TPU_Init(MXC_SYS_PERIPH_CLOCK_TPU); - MXC_TPU_Hash_Config(algo); - status = MXC_TPU_Hash_SHA((const char *)msg, algo, msgSz, - (char *)digest); + } + + /* 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(); /* Release Mutex */ - if (wc_MXC_error(&status) != 0) { - MAX3266X_MSG("SHA HW Error Occurred"); - return status; - } - } - /* Error Occurred */ - return status; -} - -/* Free HASH_KEEP message buffer and reset fields */ -void wc_MXC_TPU_SHA_Free(byte** msg, word32* used, word32* len, void* heap) -{ - if (msg == NULL) { - return; - } - if (*msg != NULL) { - XFREE(*msg, heap, DYNAMIC_TYPE_TMP_BUFFER); - *msg = NULL; - } - if (used != NULL) { - *used = 0; - } - if (len != NULL) { - *len = 0; - } -} - -/* Free HASH_KEEP message buffer and zero the full SHA context struct */ -void wc_MXC_TPU_SHA_FreeCtx(void* ctx, word32 ctxSz, byte** msg, word32* used, - word32* len, void* heap) -{ - if (ctx == NULL) { - return; - } - wc_MXC_TPU_SHA_Free(msg, used, len, heap); - XMEMSET(ctx, 0, ctxSz); -} - -/* Copy SHA context struct and deep copy the HASH_KEEP message buffer. - * Frees any existing dst msg buffer to prevent memory leaks when copying - * into an already-used context. */ -int wc_MXC_TPU_SHA_Copy(void* src, void* dst, word32 ctxSz, - byte** dstMsg, word32* dstUsed, word32* dstLen, - void* dstHeap, void* srcHeap) -{ - byte* srcBuf = NULL; - - if (src == NULL || dst == NULL || dstMsg == NULL || - dstUsed == NULL || dstLen == NULL || ctxSz == 0) { - return BAD_FUNC_ARG; + wolfSSL_HwHashMutexUnLock(); } - /* Free existing dst msg buffer using dst's original heap */ - wc_MXC_TPU_SHA_Free(dstMsg, dstUsed, dstLen, dstHeap); - - /* Shallow copy the full context struct */ - XMEMCPY(dst, src, ctxSz); - - /* Deep copy src msg buffer if present. Since dstMsg points into the dst - * struct, the XMEMCPY above overwrites it with the src's msg pointer. - * Save that pointer, allocate a new buffer for dst, and copy the data. - * Do NOT move srcBuf assignment before XMEMCPY - it must capture the - * src msg pointer that lands in *dstMsg after the shallow copy. */ - if (*dstMsg != NULL) { - srcBuf = *dstMsg; - *dstMsg = (byte*)XMALLOC(*dstLen, srcHeap, DYNAMIC_TYPE_TMP_BUFFER); - if (*dstMsg == NULL) { - return MEMORY_E; - } - XMEMCPY(*dstMsg, srcBuf, *dstUsed); + /* Buffer remaining data (1..blockSz bytes) */ + if (len > 0) { + XMEMCPY((unsigned char*)buffer, data, len); + *buffLen = len; } return 0; } -/* Compute hash, free message buffer, and reset HASH_KEEP fields */ -int wc_MXC_TPU_SHA_Final(unsigned char** msg, unsigned int* used, - unsigned int* len, void* heap, - unsigned char* digest, - MXC_TPU_HASH_TYPE algo) +/* 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; - if (msg == NULL || used == NULL || len == NULL || digest == NULL) { - return BAD_FUNC_ARG; - } - status = wc_MXC_TPU_SHA_GetHash(*msg, *used, digest, algo); - wc_MXC_TPU_SHA_Free(msg, used, len, heap); - return 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; +} + +/* Per-algorithm Init / Update / Final / GetHash / Copy / Free */ + #ifndef MAX3266X_SHA_CB +/* 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) @@ -864,26 +938,36 @@ WOLFSSL_API int wc_InitSha_ex(wc_Sha* sha, void* heap, int devId) (void)devId; XMEMSET(sha, 0, sizeof(*sha)); sha->heap = heap; - return 0; + 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) + unsigned int len) { if (sha == NULL || (data == NULL && len > 0)) { return BAD_FUNC_ARG; } - return _wc_Hash_Grow(&sha->msg, &sha->used, &sha->len, - data, (int)len, sha->heap); + 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; } - return wc_MXC_TPU_SHA_Final(&sha->msg, &sha->used, &sha->len, - sha->heap, hash, MXC_TPU_HASH_SHA1); + 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) @@ -891,8 +975,10 @@ 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((const unsigned char*)sha->msg, - sha->used, hash, MXC_TPU_HASH_SHA1); + 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) @@ -900,9 +986,8 @@ WOLFSSL_API int wc_ShaCopy(wc_Sha* src, wc_Sha* dst) if (src == NULL || dst == NULL) { return BAD_FUNC_ARG; } - return wc_MXC_TPU_SHA_Copy(src, dst, sizeof(wc_Sha), - &dst->msg, &dst->used, &dst->len, - dst->heap, src->heap); + XMEMCPY(dst, src, sizeof(wc_Sha)); + return 0; } WOLFSSL_API void wc_ShaFree(wc_Sha* sha) @@ -910,11 +995,10 @@ WOLFSSL_API void wc_ShaFree(wc_Sha* sha) if (sha == NULL) { return; } - wc_MXC_TPU_SHA_FreeCtx(sha, sizeof(wc_Sha), &sha->msg, &sha->used, - &sha->len, sha->heap); + ForceZero(sha, sizeof(wc_Sha)); } -#endif /* NO_SHA */ +#endif /* !NO_SHA */ #if defined(WOLFSSL_SHA224) @@ -926,7 +1010,8 @@ WOLFSSL_API int wc_InitSha224_ex(wc_Sha224* sha224, void* heap, int devId) (void)devId; XMEMSET(sha224, 0, sizeof(*sha224)); sha224->heap = heap; - return 0; + return wc_MXC_TPU_SHA_Init(sha224->digest, MXC_SHA224_STATE_WORDS, + MXC_TPU_HASH_SHA224); } WOLFSSL_API int wc_InitSha224(wc_Sha224* sha224) @@ -935,23 +1020,33 @@ WOLFSSL_API int wc_InitSha224(wc_Sha224* sha224) } WOLFSSL_API int wc_Sha224Update(wc_Sha224* sha224, const unsigned char* data, - unsigned int len) + unsigned int len) { if (sha224 == NULL || (data == NULL && len > 0)) { return BAD_FUNC_ARG; } - return _wc_Hash_Grow(&sha224->msg, &sha224->used, &sha224->len, - data, (int)len, sha224->heap); + 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; } - return wc_MXC_TPU_SHA_Final(&sha224->msg, &sha224->used, &sha224->len, - sha224->heap, hash, - MXC_TPU_HASH_SHA224); + 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) @@ -959,9 +1054,11 @@ 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((const unsigned char*)sha224->msg, - sha224->used, hash, - MXC_TPU_HASH_SHA224); + 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) @@ -969,9 +1066,8 @@ WOLFSSL_API int wc_Sha224Copy(wc_Sha224* src, wc_Sha224* dst) if (src == NULL || dst == NULL) { return BAD_FUNC_ARG; } - return wc_MXC_TPU_SHA_Copy(src, dst, sizeof(wc_Sha224), - &dst->msg, &dst->used, &dst->len, - dst->heap, src->heap); + XMEMCPY(dst, src, sizeof(wc_Sha224)); + return 0; } WOLFSSL_API void wc_Sha224Free(wc_Sha224* sha224) @@ -979,9 +1075,7 @@ WOLFSSL_API void wc_Sha224Free(wc_Sha224* sha224) if (sha224 == NULL) { return; } - wc_MXC_TPU_SHA_FreeCtx(sha224, sizeof(wc_Sha224), &sha224->msg, - &sha224->used, &sha224->len, - sha224->heap); + ForceZero(sha224, sizeof(wc_Sha224)); } #endif /* WOLFSSL_SHA224 */ @@ -996,7 +1090,8 @@ WOLFSSL_API int wc_InitSha256_ex(wc_Sha256* sha256, void* heap, int devId) (void)devId; XMEMSET(sha256, 0, sizeof(*sha256)); sha256->heap = heap; - return 0; + return wc_MXC_TPU_SHA_Init(sha256->digest, MXC_SHA256_STATE_WORDS, + MXC_TPU_HASH_SHA256); } WOLFSSL_API int wc_InitSha256(wc_Sha256* sha256) @@ -1005,23 +1100,33 @@ WOLFSSL_API int wc_InitSha256(wc_Sha256* sha256) } WOLFSSL_API int wc_Sha256Update(wc_Sha256* sha256, const unsigned char* data, - unsigned int len) + unsigned int len) { if (sha256 == NULL || (data == NULL && len > 0)) { return BAD_FUNC_ARG; } - return _wc_Hash_Grow(&sha256->msg, &sha256->used, &sha256->len, - data, (int)len, sha256->heap); + 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; } - return wc_MXC_TPU_SHA_Final(&sha256->msg, &sha256->used, &sha256->len, - sha256->heap, hash, - MXC_TPU_HASH_SHA256); + 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) @@ -1029,9 +1134,11 @@ 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((const unsigned char*)sha256->msg, - sha256->used, hash, - MXC_TPU_HASH_SHA256); + 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) @@ -1039,9 +1146,8 @@ WOLFSSL_API int wc_Sha256Copy(wc_Sha256* src, wc_Sha256* dst) if (src == NULL || dst == NULL) { return BAD_FUNC_ARG; } - return wc_MXC_TPU_SHA_Copy(src, dst, sizeof(wc_Sha256), - &dst->msg, &dst->used, &dst->len, - dst->heap, src->heap); + XMEMCPY(dst, src, sizeof(wc_Sha256)); + return 0; } WOLFSSL_API void wc_Sha256Free(wc_Sha256* sha256) @@ -1049,12 +1155,10 @@ WOLFSSL_API void wc_Sha256Free(wc_Sha256* sha256) if (sha256 == NULL) { return; } - wc_MXC_TPU_SHA_FreeCtx(sha256, sizeof(wc_Sha256), &sha256->msg, - &sha256->used, &sha256->len, - sha256->heap); + ForceZero(sha256, sizeof(wc_Sha256)); } -#endif /* NO_SHA256 */ +#endif /* !NO_SHA256 */ #if defined(WOLFSSL_SHA384) @@ -1066,7 +1170,8 @@ WOLFSSL_API int wc_InitSha384_ex(wc_Sha384* sha384, void* heap, int devId) (void)devId; XMEMSET(sha384, 0, sizeof(*sha384)); sha384->heap = heap; - return 0; + 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) @@ -1075,23 +1180,47 @@ WOLFSSL_API int wc_InitSha384(wc_Sha384* sha384) } WOLFSSL_API int wc_Sha384Update(wc_Sha384* sha384, const unsigned char* data, - unsigned int len) + unsigned int len) { + word32 loLen, hiLen, oldLo; + int ret; if (sha384 == NULL || (data == NULL && len > 0)) { return BAD_FUNC_ARG; } - return _wc_Hash_Grow(&sha384->msg, &sha384->used, &sha384->len, - data, (int)len, sha384->heap); + + /* 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); + oldLo = loLen; + + 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); + (void)oldLo; + return ret; } WOLFSSL_API int wc_Sha384Final(wc_Sha384* sha384, unsigned char* hash) { + int ret; if (sha384 == NULL || hash == NULL) { return BAD_FUNC_ARG; } - return wc_MXC_TPU_SHA_Final(&sha384->msg, &sha384->used, &sha384->len, - sha384->heap, hash, - MXC_TPU_HASH_SHA384); + 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) @@ -1099,9 +1228,11 @@ 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((const unsigned char*)sha384->msg, - sha384->used, hash, - MXC_TPU_HASH_SHA384); + 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) @@ -1109,9 +1240,8 @@ WOLFSSL_API int wc_Sha384Copy(wc_Sha384* src, wc_Sha384* dst) if (src == NULL || dst == NULL) { return BAD_FUNC_ARG; } - return wc_MXC_TPU_SHA_Copy(src, dst, sizeof(wc_Sha384), - &dst->msg, &dst->used, &dst->len, - dst->heap, src->heap); + XMEMCPY(dst, src, sizeof(wc_Sha384)); + return 0; } WOLFSSL_API void wc_Sha384Free(wc_Sha384* sha384) @@ -1119,9 +1249,7 @@ WOLFSSL_API void wc_Sha384Free(wc_Sha384* sha384) if (sha384 == NULL) { return; } - wc_MXC_TPU_SHA_FreeCtx(sha384, sizeof(wc_Sha384), &sha384->msg, - &sha384->used, &sha384->len, - sha384->heap); + ForceZero(sha384, sizeof(wc_Sha384)); } #endif /* WOLFSSL_SHA384 */ @@ -1139,7 +1267,8 @@ WOLFSSL_API int wc_InitSha512_ex(wc_Sha512* sha512, void* heap, int devId) #if defined(WOLFSSL_SHA512_HASHTYPE) sha512->hashType = WC_HASH_TYPE_SHA512; #endif - return 0; + 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) @@ -1148,23 +1277,42 @@ WOLFSSL_API int wc_InitSha512(wc_Sha512* sha512) } WOLFSSL_API int wc_Sha512Update(wc_Sha512* sha512, const unsigned char* data, - unsigned int len) + unsigned int len) { + word32 loLen, hiLen; + int ret; if (sha512 == NULL || (data == NULL && len > 0)) { return BAD_FUNC_ARG; } - return _wc_Hash_Grow(&sha512->msg, &sha512->used, &sha512->len, - data, (int)len, sha512->heap); + + 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; } - return wc_MXC_TPU_SHA_Final(&sha512->msg, &sha512->used, &sha512->len, - sha512->heap, hash, - MXC_TPU_HASH_SHA512); + 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) @@ -1172,9 +1320,11 @@ 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((const unsigned char*)sha512->msg, - sha512->used, hash, - MXC_TPU_HASH_SHA512); + 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) @@ -1182,9 +1332,8 @@ WOLFSSL_API int wc_Sha512Copy(wc_Sha512* src, wc_Sha512* dst) if (src == NULL || dst == NULL) { return BAD_FUNC_ARG; } - return wc_MXC_TPU_SHA_Copy(src, dst, sizeof(wc_Sha512), - &dst->msg, &dst->used, &dst->len, - dst->heap, src->heap); + XMEMCPY(dst, src, sizeof(wc_Sha512)); + return 0; } WOLFSSL_API void wc_Sha512Free(wc_Sha512* sha512) @@ -1192,13 +1341,11 @@ WOLFSSL_API void wc_Sha512Free(wc_Sha512* sha512) if (sha512 == NULL) { return; } - wc_MXC_TPU_SHA_FreeCtx(sha512, sizeof(wc_Sha512), &sha512->msg, - &sha512->used, &sha512->len, - sha512->heap); + ForceZero(sha512, sizeof(wc_Sha512)); } #endif /* WOLFSSL_SHA512 */ -#endif /* !MAX3266X_SHA_CB*/ +#endif /* !MAX3266X_SHA_CB */ #endif /* MAX3266X_SHA || MAX3266X_SHA_CB */ #if defined(MAX3266X_MATH) diff --git a/wolfssl/wolfcrypt/port/maxim/max3266x.h b/wolfssl/wolfcrypt/port/maxim/max3266x.h index 9acc799c75..7f357d6b95 100644 --- a/wolfssl/wolfcrypt/port/maxim/max3266x.h +++ b/wolfssl/wolfcrypt/port/maxim/max3266x.h @@ -57,14 +57,11 @@ #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 - #endif #endif /* Crypto HW can be used in parallel on this device */ @@ -246,52 +243,6 @@ #if defined(MAX3266X_SHA) || defined(MAX3266X_SHA_CB) - /* Use HASH_KEEP to accumulate message data for one-shot TPU hardware */ - #ifndef WOLFSSL_HASH_KEEP - #define WOLFSSL_HASH_KEEP - #endif - - #if !defined(NO_SHA) - /* Define the SHA digest for an empty string */ - /* as a constant byte array */ - static const unsigned char MXC_EMPTY_DIGEST_SHA1[20] = { - 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, - 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, - 0xaf, 0xd8, 0x07, 0x09}; - #endif /* NO_SHA */ - - #if defined(WOLFSSL_SHA224) - /* Define the SHA-224 digest for an empty string */ - /* as a constant byte array */ - static const unsigned char MXC_EMPTY_DIGEST_SHA224[28] = { - 0xd1, 0x4a, 0x02, 0x8c, 0x2a, 0x3a, 0x2b, 0xc9, - 0x47, 0x61, 0x02, 0xbb, 0x28, 0x82, 0x34, 0xc4, - 0x15, 0xa2, 0xb0, 0x1f, 0x82, 0x8e, 0xa6, 0x2a, - 0xc5, 0xb3, 0xe4, 0x2f}; - #endif /* WOLFSSL_SHA224 */ - - #if !defined(NO_SHA256) - /* Define the SHA-256 digest for an empty string */ - /* as a constant byte array */ - static const unsigned char MXC_EMPTY_DIGEST_SHA256[32] = { - 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, - 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, - 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, - 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}; - #endif /* NO_SHA256 */ - - #if defined(WOLFSSL_SHA384) - /* Define the SHA-384 digest for an empty string */ - /* as a constant byte array */ - static const unsigned char MXC_EMPTY_DIGEST_SHA384[48] = { - 0x38, 0xb0, 0x60, 0xa7, 0x51, 0xac, 0x96, 0x38, - 0x4c, 0xd9, 0x32, 0x7e, 0xb1, 0xb1, 0xe3, 0x6a, - 0x21, 0xfd, 0xb7, 0x11, 0x14, 0xbe, 0x07, 0x43, - 0x4c, 0x0c, 0xc7, 0xbf, 0x63, 0xf6, 0xe1, 0xda, - 0x27, 0x4e, 0xde, 0xbf, 0xe7, 0x6f, 0x65, 0xfb, - 0xd5, 0x1a, 0xd2, 0xf1, 0x48, 0x98, 0xb9, 0x5b}; - #endif /* WOLFSSL_SHA384 */ - #if defined(WOLFSSL_SHA512) /* Does not support these SHA512 Macros */ #ifndef WOLFSSL_NOSHA512_224 @@ -302,58 +253,52 @@ #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] = { - 0xcf, 0x83, 0xe1, 0x35, 0x7e, 0xef, 0xb8, 0xbd, - 0xf1, 0x54, 0x28, 0x50, 0xd6, 0x6d, 0x80, 0x07, - 0xd6, 0x20, 0xe4, 0x05, 0x0b, 0x57, 0x15, 0xdc, - 0x83, 0xf4, 0xa9, 0x21, 0xd3, 0x6c, 0xe9, 0xce, - 0x47, 0xd0, 0xd1, 0x3c, 0x5d, 0x85, 0xf2, 0xb0, - 0xff, 0x83, 0x18, 0xd2, 0x87, 0x7e, 0xec, 0x2f, - 0x63, 0xb9, 0x31, 0xbd, 0x47, 0x41, 0x7a, 0x81, - 0xa5, 0x38, 0x32, 0x7a, 0xf9, 0x27, 0xda, 0x3e}; #endif /* WOLFSSL_SHA512 */ + /* 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) */ - /* Check for empty message and provide pre-computed digest if so */ - WOLFSSL_LOCAL int wc_MXC_TPU_SHA_GetDigest(const unsigned char* msg, - unsigned int msgSz, - unsigned char* digest, - MXC_TPU_HASH_TYPE algo); - /* Compute hash from accumulated message using TPU hardware */ - WOLFSSL_LOCAL int wc_MXC_TPU_SHA_GetHash(const unsigned char* msg, - unsigned int msgSz, - unsigned char* digest, - MXC_TPU_HASH_TYPE algo); - /* Free HASH_KEEP message buffer and reset fields */ - WOLFSSL_LOCAL void wc_MXC_TPU_SHA_Free(unsigned char** msg, - unsigned int* used, - unsigned int* len, - void* heap); - /* Free HASH_KEEP message buffer and zero the full SHA context */ - WOLFSSL_LOCAL void wc_MXC_TPU_SHA_FreeCtx(void* ctx, - unsigned int ctxSz, - unsigned char** msg, - unsigned int* used, - unsigned int* len, - void* heap); - /* Copy SHA context and deep copy HASH_KEEP message buffer */ - WOLFSSL_LOCAL int wc_MXC_TPU_SHA_Copy(void* src, void* dst, - unsigned int ctxSz, - unsigned char** dstMsg, - unsigned int* dstUsed, - unsigned int* dstLen, - void* dstHeap, void* srcHeap); - /* Compute hash, free message buffer, and reset fields */ - WOLFSSL_LOCAL int wc_MXC_TPU_SHA_Final(unsigned char** msg, - unsigned int* used, - unsigned int* len, - void* heap, - unsigned char* digest, - MXC_TPU_HASH_TYPE algo); + /* 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 /* defined(MAX3266X_SHA) || defined(MAX3266X_SHA_CB) */ From 36acdef662cf1e17f69d142bb2918e6f875ded82 Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Fri, 8 May 2026 04:23:47 +0200 Subject: [PATCH 005/118] Update README --- wolfcrypt/src/port/maxim/README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/wolfcrypt/src/port/maxim/README.md b/wolfcrypt/src/port/maxim/README.md index 3919ffd0f9..e759472b94 100644 --- a/wolfcrypt/src/port/maxim/README.md +++ b/wolfcrypt/src/port/maxim/README.md @@ -84,10 +84,6 @@ 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. - `#define MAX3266X_MATH` (Replaces math operation calls for algos like RSA and ECC key generation): From e8d3e19da527800bb31ce356d58782f9f7b9be0c Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Fri, 8 May 2026 21:59:32 +0200 Subject: [PATCH 006/118] Address Copilot suggestions --- wolfcrypt/src/port/maxim/max3266x.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/wolfcrypt/src/port/maxim/max3266x.c b/wolfcrypt/src/port/maxim/max3266x.c index efbec9424a..bd285b26a9 100644 --- a/wolfcrypt/src/port/maxim/max3266x.c +++ b/wolfcrypt/src/port/maxim/max3266x.c @@ -275,19 +275,34 @@ static int wc_MxcCopyCb(wc_CryptoInfo* info) switch (info->copy.type) { #ifdef MAX3266X_SHA_CB #ifndef NO_SHA - case WC_HASH_TYPE_SHA: sz = sizeof(wc_Sha); break; + 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: sz = sizeof(wc_Sha224); break; + 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: sz = sizeof(wc_Sha256); break; + 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: sz = sizeof(wc_Sha384); break; + 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: sz = sizeof(wc_Sha512); break; + case WC_HASH_TYPE_SHA512: + wc_Sha512Free((wc_Sha512*)info->copy.dst); + sz = sizeof(wc_Sha512); + break; #endif #endif /* MAX3266X_SHA_CB */ default: @@ -657,7 +672,7 @@ int wc_MxcCb_AesCbcDecrypt(Aes* aes, byte* out, const byte* in, word32 sz) /* TPU hash helpers (bare-metal SHA accelerator) */ /* Reset TPU, select hash function, and restore intermediate state into - * the HASH_DIGEST registers. Does NOT set INIT - caller provides state. */ + * the HASH_DIGEST registers. */ void wc_MXC_TPU_Hash_Setup(MXC_TPU_HASH_TYPE algo, const unsigned int* state, int stateWords) { From 11b207e57f28bc29fa38c0c33523cf587b7b6947 Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Fri, 8 May 2026 22:01:15 +0200 Subject: [PATCH 007/118] Remove unused variable --- wolfcrypt/src/port/maxim/max3266x.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/wolfcrypt/src/port/maxim/max3266x.c b/wolfcrypt/src/port/maxim/max3266x.c index bd285b26a9..a2637183c7 100644 --- a/wolfcrypt/src/port/maxim/max3266x.c +++ b/wolfcrypt/src/port/maxim/max3266x.c @@ -1197,7 +1197,7 @@ WOLFSSL_API int wc_InitSha384(wc_Sha384* sha384) WOLFSSL_API int wc_Sha384Update(wc_Sha384* sha384, const unsigned char* data, unsigned int len) { - word32 loLen, hiLen, oldLo; + word32 loLen, hiLen; int ret; if (sha384 == NULL || (data == NULL && len > 0)) { return BAD_FUNC_ARG; @@ -1207,7 +1207,6 @@ WOLFSSL_API int wc_Sha384Update(wc_Sha384* sha384, const unsigned char* data, * uses word32. We bridge by converting here. */ loLen = (word32)sha384->loLen; hiLen = (word32)(sha384->loLen >> 32); - oldLo = loLen; ret = wc_MXC_TPU_SHA_Update((word32*)sha384->digest, (word32*)sha384->buffer, &sha384->buffLen, @@ -1217,7 +1216,6 @@ WOLFSSL_API int wc_Sha384Update(wc_Sha384* sha384, const unsigned char* data, /* Write back the updated length */ sha384->loLen = (word64)loLen | ((word64)hiLen << 32); - (void)oldLo; return ret; } From c9a534a63e10b6ed4f00812ab176958e5ecb5a77 Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Tue, 12 May 2026 01:31:26 +0200 Subject: [PATCH 008/118] Fix issues in wc_MXC_MAA_zeroPad --- wolfcrypt/src/port/maxim/max3266x.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/wolfcrypt/src/port/maxim/max3266x.c b/wolfcrypt/src/port/maxim/max3266x.c index a2637183c7..c8527b9964 100644 --- a/wolfcrypt/src/port/maxim/max3266x.c +++ b/wolfcrypt/src/port/maxim/max3266x.c @@ -1445,6 +1445,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"); @@ -1456,19 +1457,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; @@ -1491,7 +1496,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; From 03e695a9c675b1df1133a7a4eea34035eff0c398 Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Wed, 20 May 2026 22:31:33 +0200 Subject: [PATCH 009/118] Lazy-initialize `digest` in cryptocb mode --- wolfcrypt/src/port/maxim/max3266x.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/wolfcrypt/src/port/maxim/max3266x.c b/wolfcrypt/src/port/maxim/max3266x.c index c8527b9964..494999f100 100644 --- a/wolfcrypt/src/port/maxim/max3266x.c +++ b/wolfcrypt/src/port/maxim/max3266x.c @@ -152,12 +152,19 @@ static int wc_MXC_TPU_SHA_Init(unsigned int* digest, int stateWords, static int wc_MxcShaCbDispatch( unsigned int* digest, unsigned int* buffer, unsigned int* buffLen, unsigned int* loLen, - unsigned int* hiLen, int stateWords, + 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, @@ -200,8 +207,8 @@ static int wc_MxcShaCbDispatch512(wc_Sha512* ctx, int stateWords, ret = wc_MxcShaCbDispatch((unsigned int*)ctx->digest, (unsigned int*)ctx->buffer, &ctx->buffLen, &loLen, &hiLen, - stateWords, blockSz, digestSz, algo, - in, inSz, digest); + &ctx->devCtx, stateWords, blockSz, digestSz, + algo, in, inSz, digest); ctx->loLen = (word64)loLen | ((word64)hiLen << 32); return ret; @@ -217,6 +224,7 @@ int wc_MxcShaCryptoCb(wc_CryptoInfo* info) 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); @@ -228,6 +236,7 @@ int wc_MxcShaCryptoCb(wc_CryptoInfo* info) 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); @@ -239,6 +248,7 @@ int wc_MxcShaCryptoCb(wc_CryptoInfo* info) 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); From 43fabc694f735551a4b1e977bf6f14acf2e10d8e Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Thu, 14 May 2026 15:46:38 -0400 Subject: [PATCH 010/118] Check SNI/ALPN in TLS 1.2 stateful session ID resumption --- src/internal.c | 49 +++++++++++++++++++++----- src/ssl_sess.c | 50 +++++++++++++++++++++++++++ tests/api/test_tls.c | 82 ++++++++++++++++++++++++++++++++++++++++++++ tests/api/test_tls.h | 2 ++ wolfssl/internal.h | 12 +++++++ 5 files changed, 186 insertions(+), 9 deletions(-) diff --git a/src/internal.c b/src/internal.c index 8b34e20c37..9108ae7111 100644 --- a/src/internal.c +++ b/src/internal.c @@ -38086,6 +38086,30 @@ 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; + } +#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; + } +#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) { @@ -39450,7 +39474,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; @@ -39470,16 +39494,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); 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/tests/api/test_tls.c b/tests/api/test_tls.c index ee2e112bfa..4b696d5e9f 100644 --- a/tests/api/test_tls.c +++ b/tests/api/test_tls.c @@ -906,6 +906,88 @@ int test_tls_set_session_min_downgrade(void) return EXPECT_RESULT(); } +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \ + !defined(WOLFSSL_NO_TLS12) && 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(); +} + int test_tls_set_curves_list_ecc_fallback(void) { EXPECT_DECLS; diff --git a/tests/api/test_tls.h b/tests/api/test_tls.h index fb796244d7..f496aaff36 100644 --- a/tests/api/test_tls.h +++ b/tests/api/test_tls.h @@ -33,6 +33,7 @@ int test_tls12_bad_cv_sig_alg(void); int test_tls12_no_null_compression(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_tls_set_curves_list_ecc_fallback(void); int test_tls12_corrupted_finished(void); int test_tls12_peerauth_failsafe(void); @@ -51,6 +52,7 @@ int test_wolfSSL_alert_desc_string(void); TEST_DECL_GROUP("tls", test_tls12_no_null_compression), \ 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_tls_set_curves_list_ecc_fallback), \ TEST_DECL_GROUP("tls", test_tls12_corrupted_finished), \ TEST_DECL_GROUP("tls", test_tls12_peerauth_failsafe), \ diff --git a/wolfssl/internal.h b/wolfssl/internal.h index c09647c1ba..c2ba7a1966 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -6824,9 +6824,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 From 73b4f7b5fd1b6422154d68c1b7e8c20ec6eb588b Mon Sep 17 00:00:00 2001 From: Anthony Hu Date: Wed, 27 May 2026 13:55:15 -0400 Subject: [PATCH 011/118] For chachapoly, force zero of output on auth fail --- wolfcrypt/src/chacha20_poly1305.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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; } From 7de624ff087964abe014f2feb2dba56ea7a40a99 Mon Sep 17 00:00:00 2001 From: Colton Willey Date: Mon, 13 Apr 2026 11:42:17 -0700 Subject: [PATCH 012/118] Add negative length validation to d2i wrappers, PEM helpers, and buffer loaders Reject negative signed lengths before they are cast to unsigned (word32/size_t), preventing heap buffer over-reads and oversized allocations. Covers d2i_* OpenSSL compat wrappers, ProcessBuffer, PemToDer, certgen helpers, and CRL buffer paths. --- src/crl.c | 4 ++-- src/ocsp.c | 2 ++ src/pk_ec.c | 5 +++++ src/pk_rsa.c | 8 ++++++++ src/ssl_asn1.c | 13 +++++++++---- src/ssl_load.c | 4 ++++ src/x509.c | 4 ++-- wolfcrypt/src/asn.c | 33 +++++++++++++++++++++++++++++++-- wolfcrypt/src/evp_pk.c | 10 ++++++++-- 9 files changed, 71 insertions(+), 12 deletions(-) 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/ocsp.c b/src/ocsp.c index b90fcc8af9..bae2a499ce 100644 --- a/src/ocsp.c +++ b/src/ocsp.c @@ -1272,6 +1272,8 @@ OcspResponse* wolfSSL_d2i_OCSP_RESPONSE(OcspResponse** response, if (data == NULL) return NULL; + if (len <= 0) + return NULL; if (response != NULL) resp = *response; diff --git a/src/pk_ec.c b/src/pk_ec.c index 883f758150..02af9bacc5 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; @@ -5001,6 +5003,9 @@ WOLFSSL_ECDSA_SIG* wolfSSL_d2i_ECDSA_SIG(WOLFSSL_ECDSA_SIG** sig, if (pp == NULL) { err = 1; } + if ((!err) && (len <= 0)) { + err = 1; + } if (!err) { if (sig != NULL) { /* Use the ECDSA signature object passed in. */ diff --git a/src/pk_rsa.c b/src/pk_rsa.c index ba68929bfa..685fdb9fd1 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"); diff --git a/src/ssl_asn1.c b/src/ssl_asn1.c index 8dd158ef19..f7734eddba 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; diff --git a/src/ssl_load.c b/src/ssl_load.c index 888c578334..9831518005 100644 --- a/src/ssl_load.c +++ b/src/ssl_load.c @@ -2423,6 +2423,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/x509.c b/src/x509.c index 73f4c3c92e..a3e412f1ed 100644 --- a/src/x509.c +++ b/src/x509.c @@ -4147,7 +4147,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 @@ -11291,7 +11291,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/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index a4bd0d7ae2..433d6caac3 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -24671,10 +24671,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; @@ -24695,6 +24695,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) @@ -29958,6 +29966,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) { @@ -30462,6 +30473,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; @@ -30491,6 +30505,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) { @@ -30518,6 +30535,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) { @@ -30552,6 +30572,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) { @@ -30589,6 +30612,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) { @@ -30616,6 +30642,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) { diff --git a/wolfcrypt/src/evp_pk.c b/wolfcrypt/src/evp_pk.c index 03eb059b8c..f601b4a994 100644 --- a/wolfcrypt/src/evp_pk.c +++ b/wolfcrypt/src/evp_pk.c @@ -1464,12 +1464,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) { From adc8d8fe531a43fc26f7501dea5087ad184848f2 Mon Sep 17 00:00:00 2001 From: kaleb-himes Date: Thu, 21 May 2026 11:15:11 -0700 Subject: [PATCH 013/118] Add PQ documentation Co-Pilot feedback --- .../header_files/doxygen_groups.h | 64 ++ doc/dox_comments/header_files/wc_lms.h | 643 ++++++++++++ doc/dox_comments/header_files/wc_mldsa.h | 932 ++++++++++++++++++ doc/dox_comments/header_files/wc_mlkem.h | 472 +++++++++ doc/dox_comments/header_files/wc_xmss.h | 530 ++++++++++ 5 files changed, 2641 insertions(+) create mode 100644 doc/dox_comments/header_files/wc_lms.h create mode 100644 doc/dox_comments/header_files/wc_mldsa.h create mode 100644 doc/dox_comments/header_files/wc_mlkem.h create mode 100644 doc/dox_comments/header_files/wc_xmss.h 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); From 3ffe25f783892d0a646004f7f9a230896b04ba7f Mon Sep 17 00:00:00 2001 From: Colton Willey Date: Tue, 28 Apr 2026 19:14:43 -0700 Subject: [PATCH 014/118] Add d2i NULL-deref guards and regression tests Add `*pp == NULL` checks to three d2i wrappers to prevent NULL deref on public OpenSSL-compat APIs: - d2i_evp_pkey (reachable via wolfSSL_d2i_PublicKey/PrivateKey) - wolfSSL_d2i_OCSP_RESPONSE - wolfSSL_d2i_ECDSA_SIG (template-ASN crash) Also add regression tests for the existing PR fixes: ProcessBuffer negative-size, PemToDer family negative-pemSz, GetCRLInfo negative-sz, wc_Set*Buffer derSz<0, and d2i_ECDSA_SIG negative-length / *pp==NULL. --- src/ocsp.c | 2 ++ src/pk_ec.c | 2 +- tests/api.c | 43 ++++++++++++++++++++++++++++++++++++++++ tests/api/test_ossl_ec.c | 5 +++++ wolfcrypt/src/evp_pk.c | 2 +- 5 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/ocsp.c b/src/ocsp.c index bae2a499ce..2901487e77 100644 --- a/src/ocsp.c +++ b/src/ocsp.c @@ -1272,6 +1272,8 @@ OcspResponse* wolfSSL_d2i_OCSP_RESPONSE(OcspResponse** response, if (data == NULL) return NULL; + if (*data == NULL) + return NULL; if (len <= 0) return NULL; diff --git a/src/pk_ec.c b/src/pk_ec.c index 02af9bacc5..fc22ce163d 100644 --- a/src/pk_ec.c +++ b/src/pk_ec.c @@ -5000,7 +5000,7 @@ 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)) { diff --git a/tests/api.c b/tests/api.c index 8ba962b79b..e2d4fe02e0 100644 --- a/tests/api.c +++ b/tests/api.c @@ -2516,6 +2516,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; @@ -12159,6 +12181,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); @@ -12332,6 +12360,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)); @@ -23478,6 +23510,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(); @@ -27379,6 +27418,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), @@ -40624,6 +40666,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), 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/wolfcrypt/src/evp_pk.c b/wolfcrypt/src/evp_pk.c index f601b4a994..806bbd8fc1 100644 --- a/wolfcrypt/src/evp_pk.c +++ b/wolfcrypt/src/evp_pk.c @@ -1240,7 +1240,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; } From de9d0fded88598acb4117839ba141a526a4800af Mon Sep 17 00:00:00 2001 From: Kareem Date: Tue, 19 May 2026 16:14:07 -0700 Subject: [PATCH 015/118] Fix unused variable warning in random.c when building with CUSTOM_RAND_GENERATE_BLOCK. Fixes #10499. --- wolfcrypt/src/random.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wolfcrypt/src/random.c b/wolfcrypt/src/random.c index 4631734d7c..1984c0a5c5 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 From 5b2569e321fd785b3e2c60539875d3ca70fab653 Mon Sep 17 00:00:00 2001 From: Kareem Date: Tue, 19 May 2026 16:15:20 -0700 Subject: [PATCH 016/118] Fix potential mismatch in size between DECL_MP_INT_SIZE_DYN and NEW_MP_INT_SIZE. In some configurations DECL_MP_INT_SIZE_DYN will set the size to max while NEW_MP_INT_SIZE will memset bits. --- tests/api/test_rsa.c | 50 ++++++++++++++++++++++++++++++++++++++ tests/api/test_rsa.h | 2 ++ wolfcrypt/src/ecc.c | 49 +++++++++++++++++++++++++++++++++++++ wolfcrypt/src/rsa.c | 23 +++++++++++++++++- wolfssl/wolfcrypt/sp_int.h | 6 +++-- 5 files changed, 127 insertions(+), 3 deletions(-) diff --git a/tests/api/test_rsa.c b/tests/api/test_rsa.c index 7678737573..564534a484 100644 --- a/tests/api/test_rsa.c +++ b/tests/api/test_rsa.c @@ -1211,6 +1211,56 @@ 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). + */ +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_SP_MATH) || defined(WOLFSSL_SP_MATH_ALL)) && \ + !defined(WOLFSSL_SMALL_STACK) && \ + (defined(USE_CERT_BUFFERS_1024) || defined(USE_CERT_BUFFERS_2048)) + WC_RNG rng; + RsaKey key; + const byte* derKey; + word32 derKeySz; + word32 idx = 0; + byte flatC[256]; + word32 flatCSz; + byte out[256]; + word32 outSz = sizeof(out); + + #ifdef USE_CERT_BUFFERS_1024 + derKey = server_key_der_1024; + derKeySz = (word32)sizeof_server_key_der_1024; + flatCSz = 128; + #else + derKey = server_key_der_2048; + derKeySz = (word32)sizeof_server_key_der_2048; + flatCSz = 256; + #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); + 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); +#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/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 57b29197d6..9e1ca7c243 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -2012,6 +2012,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_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; @@ -2412,6 +2416,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_bitsused(modulus) > MAX_ECC_BITS_USE) { + return WC_KEY_SIZE_E; + } + #ifdef WOLFSSL_SMALL_STACK #ifdef WOLFSSL_SMALL_STACK_CACHE if (R->key != NULL) { @@ -2762,6 +2770,10 @@ int ecc_map_ex(ecc_point* P, mp_int* modulus, mp_digit mp, int ct) #endif mp_int *x, *y, *z; + if (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); @@ -3580,8 +3592,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_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); @@ -3886,6 +3903,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_bitsused(order) > MAX_ECC_BITS_USE || + 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) { @@ -6836,6 +6858,10 @@ int wc_ecc_sign_hash(const byte* in, word32 inlen, byte* out, word32 *outlen, word32 keySz; #endif + if (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; } @@ -7034,8 +7060,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 (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) @@ -7363,6 +7394,9 @@ int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng, #else DECLARE_CURVE_SPECS(1); #endif + if (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) { @@ -8280,8 +8314,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_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); @@ -8668,6 +8707,10 @@ int wc_ecc_verify_hash(const byte* sig, word32 siglen, const byte* hash, word32 keySz; #endif + if (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; } @@ -9038,6 +9081,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); @@ -9050,6 +9094,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 (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/rsa.c b/wolfcrypt/src/rsa.c index 5fbbd6bdf8..e09dfb87ef 100644 --- a/wolfcrypt/src/rsa.c +++ b/wolfcrypt/src/rsa.c @@ -839,6 +839,10 @@ int wc_CheckRsaKey(RsaKey* key) } #endif + if (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) { @@ -2875,6 +2879,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_bitsused(&key->n) > RSA_MAX_SIZE) { + return WC_KEY_SIZE_E; + } + (void)rng; #if defined(WC_RSA_BLINDING) && !defined(WC_NO_RNG) @@ -3054,6 +3062,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_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); @@ -3316,7 +3328,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) { @@ -3481,8 +3493,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_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) @@ -4823,6 +4840,10 @@ int wc_RsaEncryptSize(const RsaKey* key) return BAD_FUNC_ARG; } + if (mp_bitsused(&key->n) > RSA_MAX_SIZE) { + return WC_KEY_SIZE_E; + } + ret = mp_unsigned_bin_size(&key->n); #if defined(WOLFSSL_MICROCHIP_TA100) diff --git a/wolfssl/wolfcrypt/sp_int.h b/wolfssl/wolfcrypt/sp_int.h index af33e540ee..4efe41c8a8 100644 --- a/wolfssl/wolfcrypt/sp_int.h +++ b/wolfssl/wolfcrypt/sp_int.h @@ -895,9 +895,11 @@ 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. */ +/* Zero out mp_int of minimal size. + * Use the declared digit array size, not bits, so memset cannot exceed the + * buffer allocated by DECL_MP_INT_SIZE_DYN(..., bits, max). */ #define NEW_MP_INT_SIZE(name, bits, heap, type) \ - XMEMSET(name, 0, MP_INT_SIZEOF(MP_BITS_CNT(bits))) + XMEMSET(name, 0, sizeof(name##d)) /* 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. */ From d942fe47d5b626f3affd645766820c29152bf522 Mon Sep 17 00:00:00 2001 From: Kareem Date: Tue, 19 May 2026 16:56:22 -0700 Subject: [PATCH 017/118] Fix issue in ECC test from size mismatch. Code review feedback. --- wolfcrypt/src/ecc.c | 32 ++++++++++++++++++++------------ wolfcrypt/src/rsa.c | 20 ++++++++++++-------- wolfssl/wolfcrypt/sp_int.h | 10 ++++++---- 3 files changed, 38 insertions(+), 24 deletions(-) diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 9e1ca7c243..0668c3d956 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -327,6 +327,14 @@ ECC Curve Sizes: #define MAX_ECC_BITS_USE MAX_ECC_BITS_NEEDED #endif +#if defined(WOLFSSL_SP_MATH) || defined(WOLFSSL_SP_MATH_ALL) +#define ECC_DECL_MP_OVER_MAX(bits) \ + (MP_BITS_CNT(bits) > MP_BITS_CNT(MAX_ECC_BITS_USE)) +#else +#define ECC_DECL_MP_OVER_MAX(bits) \ + ((bits) > MAX_ECC_BITS_USE) +#endif + #if !defined(WOLFSSL_CUSTOM_CURVES) && (ECC_MIN_KEY_SZ > 160) && \ (!defined(HAVE_ECC_KOBLITZ) || (ECC_MIN_KEY_SZ > 224)) @@ -2012,7 +2020,7 @@ static int _ecc_projective_add_point(ecc_point* P, ecc_point* Q, ecc_point* R, mp_int *x, *y, *z; int err; - if (mp_bitsused(modulus) > MAX_ECC_BITS_USE) { + if (ECC_DECL_MP_OVER_MAX(mp_bitsused(modulus))) { return WC_KEY_SIZE_E; } @@ -2416,7 +2424,7 @@ static int _ecc_projective_dbl_point(ecc_point *P, ecc_point *R, mp_int* a, mp_int *x, *y, *z; int err; - if (mp_bitsused(modulus) > MAX_ECC_BITS_USE) { + if (ECC_DECL_MP_OVER_MAX(mp_bitsused(modulus))) { return WC_KEY_SIZE_E; } @@ -2770,7 +2778,7 @@ int ecc_map_ex(ecc_point* P, mp_int* modulus, mp_digit mp, int ct) #endif mp_int *x, *y, *z; - if (mp_bitsused(modulus) > MAX_ECC_BITS_USE) { + if (ECC_DECL_MP_OVER_MAX(mp_bitsused(modulus))) { return WC_KEY_SIZE_E; } @@ -3595,7 +3603,7 @@ static int ecc_point_to_mont(ecc_point* p, ecc_point* r, mp_int* modulus, DECL_MP_INT_SIZE_DYN(mu, mp_bitsused(modulus), MAX_ECC_BITS_USE); - if (mp_bitsused(modulus) > MAX_ECC_BITS_USE) { + if (ECC_DECL_MP_OVER_MAX(mp_bitsused(modulus))) { return WC_KEY_SIZE_E; } @@ -3903,8 +3911,8 @@ 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_bitsused(order) > MAX_ECC_BITS_USE || - mp_bitsused(modulus) > MAX_ECC_BITS_USE) { + if (ECC_DECL_MP_OVER_MAX(mp_bitsused(order)) || + ECC_DECL_MP_OVER_MAX(mp_bitsused(modulus))) { return WC_KEY_SIZE_E; } @@ -6858,7 +6866,7 @@ int wc_ecc_sign_hash(const byte* in, word32 inlen, byte* out, word32 *outlen, word32 keySz; #endif - if (ECC_KEY_MAX_BITS(key) > MAX_ECC_BITS_USE) { + if (ECC_DECL_MP_OVER_MAX(ECC_KEY_MAX_BITS(key))) { return WC_KEY_SIZE_E; } @@ -7063,7 +7071,7 @@ static int ecc_sign_hash_sw(ecc_key* key, ecc_key* pubkey, WC_RNG* rng, DECL_MP_INT_SIZE_DYN(b, ECC_KEY_MAX_BITS_NONULLCHECK(key), MAX_ECC_BITS_USE); - if (ECC_KEY_MAX_BITS_NONULLCHECK(key) > MAX_ECC_BITS_USE) { + if (ECC_DECL_MP_OVER_MAX(ECC_KEY_MAX_BITS_NONULLCHECK(key))) { return WC_KEY_SIZE_E; } @@ -7394,7 +7402,7 @@ int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng, #else DECLARE_CURVE_SPECS(1); #endif - if (ECC_KEY_MAX_BITS(key) > MAX_ECC_BITS_USE) { + if (ECC_DECL_MP_OVER_MAX(ECC_KEY_MAX_BITS(key))) { return WC_KEY_SIZE_E; } #endif /* !WOLFSSL_SP_MATH */ @@ -8317,7 +8325,7 @@ static int ecc_mont_norm_points(ecc_point* A, ecc_point* Am, ecc_point* B, DECL_MP_INT_SIZE_DYN(mu, mp_bitsused(modulus), MAX_ECC_BITS_USE); - if (mp_bitsused(modulus) > MAX_ECC_BITS_USE) { + if (ECC_DECL_MP_OVER_MAX(mp_bitsused(modulus))) { return WC_KEY_SIZE_E; } @@ -8707,7 +8715,7 @@ int wc_ecc_verify_hash(const byte* sig, word32 siglen, const byte* hash, word32 keySz; #endif - if (ECC_KEY_MAX_BITS(key) > MAX_ECC_BITS_USE) { + if (ECC_DECL_MP_OVER_MAX(ECC_KEY_MAX_BITS(key))) { return WC_KEY_SIZE_E; } @@ -9095,7 +9103,7 @@ static int ecc_verify_hash(mp_int *r, mp_int *s, const byte* hash, mp_int* u1 = NULL; /* Will be e. */ mp_int* u2 = NULL; /* Will be w. */ - if (ECC_KEY_MAX_BITS_NONULLCHECK(key) > MAX_ECC_BITS_USE) { + if (ECC_DECL_MP_OVER_MAX(ECC_KEY_MAX_BITS_NONULLCHECK(key))) { return WC_KEY_SIZE_E; } diff --git a/wolfcrypt/src/rsa.c b/wolfcrypt/src/rsa.c index e09dfb87ef..54880d5ac2 100644 --- a/wolfcrypt/src/rsa.c +++ b/wolfcrypt/src/rsa.c @@ -44,6 +44,14 @@ RSA keys can be used to encrypt, decrypt, sign and verify data. #include #include +#if defined(WOLFSSL_SP_MATH) || defined(WOLFSSL_SP_MATH_ALL) +#define RSA_DECL_MP_OVER_MAX(bits) \ + (MP_BITS_CNT(bits) > MP_BITS_CNT(RSA_MAX_SIZE)) +#else +#define RSA_DECL_MP_OVER_MAX(bits) \ + ((bits) > RSA_MAX_SIZE) +#endif + #ifdef WOLFSSL_AFALG_XILINX_RSA #include #endif @@ -839,7 +847,7 @@ int wc_CheckRsaKey(RsaKey* key) } #endif - if (mp_bitsused(&key->n) > RSA_MAX_SIZE) { + if (RSA_DECL_MP_OVER_MAX(mp_bitsused(&key->n))) { return WC_KEY_SIZE_E; } @@ -2879,7 +2887,7 @@ 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_bitsused(&key->n) > RSA_MAX_SIZE) { + if (RSA_DECL_MP_OVER_MAX(mp_bitsused(&key->n))) { return WC_KEY_SIZE_E; } @@ -3062,7 +3070,7 @@ 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_bitsused(&key->n) > RSA_MAX_SIZE) { + if (RSA_DECL_MP_OVER_MAX(mp_bitsused(&key->n))) { return WC_KEY_SIZE_E; } @@ -3496,7 +3504,7 @@ int RsaFunctionCheckIn(const byte* in, word32 inLen, RsaKey* key, DECL_MP_INT_SIZE_DYN(c, mp_bitsused(&key->n), RSA_MAX_SIZE); - if (mp_bitsused(&key->n) > RSA_MAX_SIZE) { + if (RSA_DECL_MP_OVER_MAX(mp_bitsused(&key->n))) { return WC_KEY_SIZE_E; } @@ -4840,10 +4848,6 @@ int wc_RsaEncryptSize(const RsaKey* key) return BAD_FUNC_ARG; } - if (mp_bitsused(&key->n) > RSA_MAX_SIZE) { - return WC_KEY_SIZE_E; - } - ret = mp_unsigned_bin_size(&key->n); #if defined(WOLFSSL_MICROCHIP_TA100) diff --git a/wolfssl/wolfcrypt/sp_int.h b/wolfssl/wolfcrypt/sp_int.h index 4efe41c8a8..74b4017737 100644 --- a/wolfssl/wolfcrypt/sp_int.h +++ b/wolfssl/wolfcrypt/sp_int.h @@ -895,11 +895,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. - * Use the declared digit array size, not bits, so memset cannot exceed the - * buffer allocated by DECL_MP_INT_SIZE_DYN(..., bits, max). */ +/* 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, sizeof(name##d)) + 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. */ From 903fd97dbe7909b57526b7efc1f2701ff962c8cc Mon Sep 17 00:00:00 2001 From: Kareem Date: Wed, 27 May 2026 16:24:47 -0700 Subject: [PATCH 018/118] Fix issues with newly added check when using fast/integer math. Simplify logic by using single macro for ECC & RSA. --- wolfcrypt/src/ecc.c | 32 ++++++++++++-------------------- wolfcrypt/src/rsa.c | 16 ++++------------ wolfssl/wolfcrypt/integer.h | 4 ++++ wolfssl/wolfcrypt/sp_int.h | 11 +++++++++++ wolfssl/wolfcrypt/tfm.h | 4 ++++ 5 files changed, 35 insertions(+), 32 deletions(-) diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 0668c3d956..293802af31 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -327,14 +327,6 @@ ECC Curve Sizes: #define MAX_ECC_BITS_USE MAX_ECC_BITS_NEEDED #endif -#if defined(WOLFSSL_SP_MATH) || defined(WOLFSSL_SP_MATH_ALL) -#define ECC_DECL_MP_OVER_MAX(bits) \ - (MP_BITS_CNT(bits) > MP_BITS_CNT(MAX_ECC_BITS_USE)) -#else -#define ECC_DECL_MP_OVER_MAX(bits) \ - ((bits) > MAX_ECC_BITS_USE) -#endif - #if !defined(WOLFSSL_CUSTOM_CURVES) && (ECC_MIN_KEY_SZ > 160) && \ (!defined(HAVE_ECC_KOBLITZ) || (ECC_MIN_KEY_SZ > 224)) @@ -2020,7 +2012,7 @@ static int _ecc_projective_add_point(ecc_point* P, ecc_point* Q, ecc_point* R, mp_int *x, *y, *z; int err; - if (ECC_DECL_MP_OVER_MAX(mp_bitsused(modulus))) { + if (MP_BITS_OVER_MAX(mp_bitsused(modulus), MAX_ECC_BITS_USE)) { return WC_KEY_SIZE_E; } @@ -2424,7 +2416,7 @@ static int _ecc_projective_dbl_point(ecc_point *P, ecc_point *R, mp_int* a, mp_int *x, *y, *z; int err; - if (ECC_DECL_MP_OVER_MAX(mp_bitsused(modulus))) { + if (MP_BITS_OVER_MAX(mp_bitsused(modulus), MAX_ECC_BITS_USE)) { return WC_KEY_SIZE_E; } @@ -2778,7 +2770,7 @@ int ecc_map_ex(ecc_point* P, mp_int* modulus, mp_digit mp, int ct) #endif mp_int *x, *y, *z; - if (ECC_DECL_MP_OVER_MAX(mp_bitsused(modulus))) { + if (MP_BITS_OVER_MAX(mp_bitsused(modulus), MAX_ECC_BITS_USE)) { return WC_KEY_SIZE_E; } @@ -3603,7 +3595,7 @@ static int ecc_point_to_mont(ecc_point* p, ecc_point* r, mp_int* modulus, DECL_MP_INT_SIZE_DYN(mu, mp_bitsused(modulus), MAX_ECC_BITS_USE); - if (ECC_DECL_MP_OVER_MAX(mp_bitsused(modulus))) { + if (MP_BITS_OVER_MAX(mp_bitsused(modulus), MAX_ECC_BITS_USE)) { return WC_KEY_SIZE_E; } @@ -3911,8 +3903,8 @@ 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 (ECC_DECL_MP_OVER_MAX(mp_bitsused(order)) || - ECC_DECL_MP_OVER_MAX(mp_bitsused(modulus))) { + 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; } @@ -6866,7 +6858,7 @@ int wc_ecc_sign_hash(const byte* in, word32 inlen, byte* out, word32 *outlen, word32 keySz; #endif - if (ECC_DECL_MP_OVER_MAX(ECC_KEY_MAX_BITS(key))) { + if (MP_BITS_OVER_MAX(ECC_KEY_MAX_BITS(key), MAX_ECC_BITS_USE)) { return WC_KEY_SIZE_E; } @@ -7071,7 +7063,7 @@ static int ecc_sign_hash_sw(ecc_key* key, ecc_key* pubkey, WC_RNG* rng, DECL_MP_INT_SIZE_DYN(b, ECC_KEY_MAX_BITS_NONULLCHECK(key), MAX_ECC_BITS_USE); - if (ECC_DECL_MP_OVER_MAX(ECC_KEY_MAX_BITS_NONULLCHECK(key))) { + if (MP_BITS_OVER_MAX(ECC_KEY_MAX_BITS_NONULLCHECK(key), MAX_ECC_BITS_USE)) { return WC_KEY_SIZE_E; } @@ -7402,7 +7394,7 @@ int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng, #else DECLARE_CURVE_SPECS(1); #endif - if (ECC_DECL_MP_OVER_MAX(ECC_KEY_MAX_BITS(key))) { + if (MP_BITS_OVER_MAX(ECC_KEY_MAX_BITS(key), MAX_ECC_BITS_USE)) { return WC_KEY_SIZE_E; } #endif /* !WOLFSSL_SP_MATH */ @@ -8325,7 +8317,7 @@ static int ecc_mont_norm_points(ecc_point* A, ecc_point* Am, ecc_point* B, DECL_MP_INT_SIZE_DYN(mu, mp_bitsused(modulus), MAX_ECC_BITS_USE); - if (ECC_DECL_MP_OVER_MAX(mp_bitsused(modulus))) { + if (MP_BITS_OVER_MAX(mp_bitsused(modulus), MAX_ECC_BITS_USE)) { return WC_KEY_SIZE_E; } @@ -8715,7 +8707,7 @@ int wc_ecc_verify_hash(const byte* sig, word32 siglen, const byte* hash, word32 keySz; #endif - if (ECC_DECL_MP_OVER_MAX(ECC_KEY_MAX_BITS(key))) { + if (MP_BITS_OVER_MAX(ECC_KEY_MAX_BITS(key), MAX_ECC_BITS_USE)) { return WC_KEY_SIZE_E; } @@ -9103,7 +9095,7 @@ static int ecc_verify_hash(mp_int *r, mp_int *s, const byte* hash, mp_int* u1 = NULL; /* Will be e. */ mp_int* u2 = NULL; /* Will be w. */ - if (ECC_DECL_MP_OVER_MAX(ECC_KEY_MAX_BITS_NONULLCHECK(key))) { + if (MP_BITS_OVER_MAX(ECC_KEY_MAX_BITS_NONULLCHECK(key), MAX_ECC_BITS_USE)) { return WC_KEY_SIZE_E; } diff --git a/wolfcrypt/src/rsa.c b/wolfcrypt/src/rsa.c index 54880d5ac2..b8ee0b6a83 100644 --- a/wolfcrypt/src/rsa.c +++ b/wolfcrypt/src/rsa.c @@ -44,14 +44,6 @@ RSA keys can be used to encrypt, decrypt, sign and verify data. #include #include -#if defined(WOLFSSL_SP_MATH) || defined(WOLFSSL_SP_MATH_ALL) -#define RSA_DECL_MP_OVER_MAX(bits) \ - (MP_BITS_CNT(bits) > MP_BITS_CNT(RSA_MAX_SIZE)) -#else -#define RSA_DECL_MP_OVER_MAX(bits) \ - ((bits) > RSA_MAX_SIZE) -#endif - #ifdef WOLFSSL_AFALG_XILINX_RSA #include #endif @@ -847,7 +839,7 @@ int wc_CheckRsaKey(RsaKey* key) } #endif - if (RSA_DECL_MP_OVER_MAX(mp_bitsused(&key->n))) { + if (MP_BITS_OVER_MAX(mp_bitsused(&key->n), RSA_MAX_SIZE)) { return WC_KEY_SIZE_E; } @@ -2887,7 +2879,7 @@ 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 (RSA_DECL_MP_OVER_MAX(mp_bitsused(&key->n))) { + if (MP_BITS_OVER_MAX(mp_bitsused(&key->n), RSA_MAX_SIZE)) { return WC_KEY_SIZE_E; } @@ -3070,7 +3062,7 @@ 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 (RSA_DECL_MP_OVER_MAX(mp_bitsused(&key->n))) { + if (MP_BITS_OVER_MAX(mp_bitsused(&key->n), RSA_MAX_SIZE)) { return WC_KEY_SIZE_E; } @@ -3504,7 +3496,7 @@ int RsaFunctionCheckIn(const byte* in, word32 inLen, RsaKey* key, DECL_MP_INT_SIZE_DYN(c, mp_bitsused(&key->n), RSA_MAX_SIZE); - if (RSA_DECL_MP_OVER_MAX(mp_bitsused(&key->n))) { + if (MP_BITS_OVER_MAX(mp_bitsused(&key->n), RSA_MAX_SIZE)) { return WC_KEY_SIZE_E; } 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/sp_int.h b/wolfssl/wolfcrypt/sp_int.h index 74b4017737..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) || \ 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 */ From a1b71a6f3420930464d327435df2ad632fbd0699 Mon Sep 17 00:00:00 2001 From: Kareem Date: Wed, 27 May 2026 18:20:20 -0700 Subject: [PATCH 019/118] Rework added test --- tests/api/test_rsa.c | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/tests/api/test_rsa.c b/tests/api/test_rsa.c index 564534a484..81e1c7cdd1 100644 --- a/tests/api/test_rsa.c +++ b/tests/api/test_rsa.c @@ -1214,33 +1214,43 @@ int test_wc_RsaDecrypt_BoundsCheck(void) /* * 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[256]; + byte flatC[WC_RSA_OVERSIZED_BUF_LEN]; word32 flatCSz; - byte out[256]; + 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; - flatCSz = 128; #else derKey = server_key_der_2048; derKeySz = (word32)sizeof_server_key_der_2048; - flatCSz = 256; #endif XMEMSET(&key, 0, sizeof(RsaKey)); @@ -1251,12 +1261,22 @@ int test_wc_RsaFunctionCheckIn_OversizedModulus(void) 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); - XMEMSET(flatC, 0, flatCSz); - ExpectIntEQ(wc_RsaDirect(flatC, flatCSz, out, &outSz, &key, - RSA_PRIVATE_DECRYPT, &rng), WC_NO_ERR_TRACE(WC_KEY_SIZE_E)); + + /* 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 */ From 6303af86ac6f8b4587eab68a07483e05014196e8 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Wed, 13 May 2026 11:26:38 +0000 Subject: [PATCH 020/118] Cache AEAD record overhead on WOLFSSL wolfssl_local_GetRecordSize() runs BuildMessage(sizeOnly=1) on every wolfSSL_write hot path. For AEAD ciphers the overhead is constant per connection framing state, so cache (recordSz - payloadSz) on WOLFSSL and invalidate in SetKeysSide(), at cidInfo->tx assignment, and in wolfSSL_clear(). BuildMessage stays the single source of truth. Add test_record_size_matches_build_message (cross-checks every built cipher over TLS/DTLS +/- CID against BuildMessage) and test_record_size_cache_invalidated_on_renegotiation. --- src/dtls.c | 8 ++ src/internal.c | 29 +++++++ src/keys.c | 6 ++ src/ssl.c | 1 + tests/api/test_tls.c | 197 +++++++++++++++++++++++++++++++++++++++++++ tests/api/test_tls.h | 8 +- wolfssl/internal.h | 19 ++++- 7 files changed, 263 insertions(+), 5 deletions(-) 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/internal.c b/src/internal.c index 75c007c657..5a94bd3bd9 100644 --- a/src/internal.c +++ b/src/internal.c @@ -42612,6 +42612,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 */ @@ -42622,6 +42643,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/ssl.c b/src/ssl.c index efbbf3074e..1379a3d31f 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -10140,6 +10140,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; diff --git a/tests/api/test_tls.c b/tests/api/test_tls.c index ee2e112bfa..6b24e4704d 100644 --- a/tests/api/test_tls.c +++ b/tests/api/test_tls.c @@ -1219,3 +1219,200 @@ 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 '-'. */ + static const char* const deny[] = { + "PSK", "SRP", "ANON", "NULL", "ECDSA", "ECDH-", "SM" + }; + 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..e3b1b2d7c2 100644 --- a/tests/api/test_tls.h +++ b/tests/api/test_tls.h @@ -38,6 +38,8 @@ int test_tls12_corrupted_finished(void); int test_tls12_peerauth_failsafe(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); #define TEST_TLS_DECLS \ TEST_DECL_GROUP("tls", test_utils_memio_move_message), \ @@ -55,6 +57,10 @@ int test_wolfSSL_alert_desc_string(void); TEST_DECL_GROUP("tls", test_tls12_corrupted_finished), \ TEST_DECL_GROUP("tls", test_tls12_peerauth_failsafe), \ 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_tls12_peerauth_failsafe), \ + TEST_DECL_GROUP("tls", test_record_size_matches_build_message), \ + TEST_DECL_GROUP("tls", \ + test_record_size_cache_invalidated_on_renegotiation) #endif /* TESTS_API_TEST_TLS_H */ diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 025878a8d3..d5341d0119 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -6612,6 +6612,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) @@ -6886,7 +6890,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); @@ -7177,8 +7181,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 */ @@ -7258,7 +7266,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); From f3bdecf3f6eee3ba2094146dd246d38fe22a6a10 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Thu, 14 May 2026 14:05:42 +0200 Subject: [PATCH 021/118] tests: skip RENEGOTIATION-INFO SCSV in record_size cipher loop TLS_EMPTY_RENEGOTIATION_INFO_SCSV appears in GetCipherNames() when HAVE_RENEGOTIATION_INDICATION is set. It is a signaling value, not a real suite; set_cipher_list accepts it but the handshake rejects it with UNSUPPORTED_SUITE. Add it to record_size_skip_cipher's deny list. --- tests/api/test_tls.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/api/test_tls.c b/tests/api/test_tls.c index 6b24e4704d..d63498937b 100644 --- a/tests/api/test_tls.c +++ b/tests/api/test_tls.c @@ -1226,9 +1226,11 @@ int test_wolfSSL_alert_desc_string(void) 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 '-'. */ + * 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" + "PSK", "SRP", "ANON", "NULL", "ECDSA", "ECDH-", "SM", + "RENEGOTIATION-INFO" }; size_t i; for (i = 0; i < XELEM_CNT(deny); i++) { From e7f491a98a4d60e3b6ad9b253bdd3911b79f164f Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Wed, 27 May 2026 09:15:58 -0400 Subject: [PATCH 022/118] Check SNI/ALPN in TLS 1.3 session resumption --- src/internal.c | 62 +++++++++++++++---- src/tls13.c | 79 +++++++++++++++++++----- tests/api/test_tls.c | 144 ++++++++++++++++++++++++++++++++++++++++++- tests/api/test_tls.h | 4 ++ 4 files changed, 259 insertions(+), 30 deletions(-) diff --git a/src/internal.c b/src/internal.c index 9108ae7111..664c0045b5 100644 --- a/src/internal.c +++ b/src/internal.c @@ -38691,8 +38691,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; @@ -39519,15 +39533,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 @@ -40036,8 +40065,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 */ @@ -40133,8 +40163,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 @@ -40500,8 +40535,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: diff --git a/src/tls13.c b/src/tls13.c index 5128f6097f..880882f691 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -6429,6 +6429,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) { @@ -6592,11 +6623,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; @@ -7562,6 +7593,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) { @@ -7671,6 +7721,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, @@ -7712,16 +7771,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; diff --git a/tests/api/test_tls.c b/tests/api/test_tls.c index 4b696d5e9f..4abf2b6206 100644 --- a/tests/api/test_tls.c +++ b/tests/api/test_tls.c @@ -907,8 +907,9 @@ int test_tls_set_session_min_downgrade(void) } #if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \ - !defined(WOLFSSL_NO_TLS12) && defined(HAVE_SNI) && \ - defined(HAVE_SESSION_TICKET) && !defined(NO_SESSION_CACHE) + (!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) { @@ -988,6 +989,145 @@ int test_tls12_session_id_resumption_sni_mismatch(void) 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(); +} + int test_tls_set_curves_list_ecc_fallback(void) { EXPECT_DECLS; diff --git a/tests/api/test_tls.h b/tests/api/test_tls.h index f496aaff36..4b4f5385c3 100644 --- a/tests/api/test_tls.h +++ b/tests/api/test_tls.h @@ -34,6 +34,8 @@ int test_tls12_no_null_compression(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_tls_set_curves_list_ecc_fallback(void); int test_tls12_corrupted_finished(void); int test_tls12_peerauth_failsafe(void); @@ -53,6 +55,8 @@ int test_wolfSSL_alert_desc_string(void); 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_tls_set_curves_list_ecc_fallback), \ TEST_DECL_GROUP("tls", test_tls12_corrupted_finished), \ TEST_DECL_GROUP("tls", test_tls12_peerauth_failsafe), \ From 406365ec1c417168e5c44ec7f4d60d371d76cc4c Mon Sep 17 00:00:00 2001 From: sebastian-carpenter Date: Fri, 17 Apr 2026 15:04:13 -0600 Subject: [PATCH 023/118] TLS ECH keylogging --- src/internal.c | 18 ++++ src/tls.c | 176 +++++++++++++++++++++++++++++---------- src/tls13.c | 8 +- tests/api.c | 175 ++++++++++++++++++++++++++++++++++++-- wolfcrypt/src/hpke.c | 32 +++++++ wolfssl/internal.h | 3 +- wolfssl/ssl.h | 6 +- wolfssl/wolfcrypt/hpke.h | 8 ++ 8 files changed, 372 insertions(+), 54 deletions(-) diff --git a/src/internal.c b/src/internal.c index 75c007c657..f39fbeb588 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; } diff --git a/src/tls.c b/src/tls.c index 62118d0678..5f5ed8eecc 100644 --- a/src/tls.c +++ b/src/tls.c @@ -13952,6 +13952,42 @@ static int TLSX_ECH_GetSize(WOLFSSL_ECH* ech, byte msgType) 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. @@ -14361,8 +14397,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; @@ -14370,7 +14406,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) @@ -14388,13 +14424,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 */ @@ -14412,7 +14449,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; @@ -14423,6 +14460,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, @@ -14436,17 +14483,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; } @@ -14650,9 +14709,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; @@ -14662,42 +14721,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) { @@ -14719,10 +14782,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); @@ -14732,13 +14799,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 */ @@ -14766,6 +14835,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); @@ -14786,6 +14867,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) @@ -14804,7 +14894,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) diff --git a/src/tls13.c b/src/tls13.c index 8d7efb9df4..a947ee8a61 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -5097,7 +5097,7 @@ 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))); @@ -16099,6 +16099,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/tests/api.c b/tests/api.c index fe92bdee85..22f5f8772d 100644 --- a/tests/api.c +++ b/tests/api.c @@ -14552,12 +14552,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) @@ -14566,16 +14611,26 @@ 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; XFILE fp = XBADFILE; + int label_count = 4; +#ifdef HAVE_KEYING_MATERIAL + label_count += 1; +#endif +#ifdef HAVE_ECH + label_count += 2; +#endif XMEMSET(&server_cbf, 0, sizeof(test_ssl_cbf)); 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); @@ -14590,7 +14645,7 @@ static int test_wolfSSL_Tls13_Key_Logging_test(void) /* check if the keylog file exists */ { char buff[300] = {0}; - int found[4] = {0}; + int found[7] = {0}; int numfnd = 0; int i; @@ -14600,37 +14655,140 @@ static int test_wolfSSL_Tls13_Key_Logging_test(void) XFGETS(buff, (int)sizeof(buff), fp) != NULL) { if (0 == strncmp(buff, "CLIENT_HANDSHAKE_TRAFFIC_SECRET ", sizeof("CLIENT_HANDSHAKE_TRAFFIC_SECRET ")-1)) { - found[0] = 1; + found[0]++; continue; } else if (0 == strncmp(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 ", sizeof("CLIENT_TRAFFIC_SECRET_0 ")-1)) { - found[2] = 1; + found[2]++; continue; } else if (0 == strncmp(buff, "SERVER_TRAFFIC_SECRET_0 ", sizeof("SERVER_TRAFFIC_SECRET_0 ")-1)) { - found[3] = 1; + found[3]++; continue; } +#ifdef HAVE_KEYING_MATERIAL + else if (0 == strncmp(buff, "EXPORTER_SECRET ", + sizeof("EXPORTER_SECRET ")-1)) { + found[4]++; + continue; + } +#endif +#ifdef HAVE_ECH + else if (0 == strncmp(buff, "ECH_SECRET ", + sizeof("ECH_SECRET ")-1)) { + found[5]++; + continue; + } + else if (0 == strncmp(buff, "ECH_CONFIG ", + sizeof("ECH_CONFIG ")-1)) { + found[6]++; + continue; + } +#endif } if (fp != XBADFILE) XFCLOSE(fp); - for (i = 0; i < 4; i++) { + for (i = 0; i < (int)(sizeof(found) / sizeof(found[0])); i++) { if (found[i] != 0) numfnd++; } - ExpectIntEQ(numfnd, 4); + ExpectIntEQ(numfnd, label_count); + /* 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); +#endif } #endif /* OPENSSL_EXTRA && HAVE_SECRET_CALLBACK && WOLFSSL_TLS13 */ return EXPECT_RESULT(); } +#if defined(WOLFSSL_TLS13) && defined(OPENSSL_EXTRA) && \ + defined(HAVE_SECRET_CALLBACK) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) +/* Fails only when the derive site fires with an id matching *ctx, so the + * caller can drive each Derive*Secret call site's failure path in isolation. */ +static int keylog_fail_cb(WOLFSSL* ssl, int id, const unsigned char* secret, + int secretSz, void* ctx) +{ + (void)ssl; + (void)secret; + (void)secretSz; + return (ctx != NULL && id == *(const int*)ctx) ? -1 : 0; +} +#endif + +static int test_wolfSSL_Tls13_Key_Logging_callback_fail(void) +{ + EXPECT_DECLS; +#if defined(WOLFSSL_TLS13) && defined(OPENSSL_EXTRA) && \ + defined(HAVE_SECRET_CALLBACK) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) + /* A non-zero return from Tls13SecretCb at any derive site must surface as + * TLS13_SECRET_CB_E and fail the handshake. */ + const int labels[] = { + CLIENT_HANDSHAKE_TRAFFIC_SECRET, + SERVER_HANDSHAKE_TRAFFIC_SECRET, + CLIENT_TRAFFIC_SECRET, + SERVER_TRAFFIC_SECRET, +#ifdef HAVE_KEYING_MATERIAL + EXPORTER_SECRET, +#endif +#ifdef HAVE_ECH + ECH_SECRET, + ECH_CONFIG, +#endif + }; + struct test_ssl_memio_ctx test_ctx; + int fail_id; + int i; + + for (i = 0; i < (int)(sizeof(labels) / sizeof(labels[0])); i++) { + fail_id = labels[i]; + + 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; + test_ctx.c_cb.ctx_ready = &test_wolfSSL_Tls13_Key_Logging_client_ctx_ready; + test_ctx.c_cb.ssl_ready = &test_wolfSSL_Tls13_Key_Logging_client_ssl_ready; + test_ctx.s_cb.ctx_ready = &test_wolfSSL_Tls13_Key_Logging_server_ctx_ready; + test_ctx.s_cb.ssl_ready = &test_wolfSSL_Tls13_Key_Logging_server_ssl_ready; + + ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS); + ExpectIntEQ(wolfSSL_set_tls13_secret_cb(test_ctx.c_ssl, + keylog_fail_cb, &fail_id), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_tls13_secret_cb(test_ctx.s_ssl, + keylog_fail_cb, &fail_id), WOLFSSL_SUCCESS); + ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), + TEST_SUCCESS); + /* either peer may surface the error first depending on derive order */ + ExpectTrue(wolfSSL_get_error(test_ctx.c_ssl, 0) + == WC_NO_ERR_TRACE(TLS13_SECRET_CB_E) || + wolfSSL_get_error(test_ctx.s_ssl, 0) + == WC_NO_ERR_TRACE(TLS13_SECRET_CB_E)); + test_ssl_memio_cleanup(&test_ctx); + } +#endif + return EXPECT_RESULT(); +} + #if defined(WOLFSSL_TLS13) && defined(HAVE_ECH) #if defined(HAVE_IO_TESTS_DEPENDENCIES) static int test_wolfSSL_Tls13_ECH_params(void) @@ -40709,6 +40867,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_callback_fail), TEST_DECL(test_wolfSSL_Tls13_postauth), TEST_DECL(test_wolfSSL_set_ecdh_auto), TEST_DECL(test_wolfSSL_CTX_set_ecdh_auto), 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/wolfssl/internal.h b/wolfssl/internal.h index 025878a8d3..a08595eb5e 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -3178,7 +3178,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, diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 0081cfc494..b258d96de6 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -1064,7 +1064,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 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 */ From 050e538ece4fbb55364b818b451fec29a593b401 Mon Sep 17 00:00:00 2001 From: sebastian-carpenter Date: Tue, 26 May 2026 14:28:31 -0600 Subject: [PATCH 024/118] change random handling in ECH --- src/tls13.c | 9 +-- tests/api.c | 185 ++++++++++++++++++++++++++++++---------------------- 2 files changed, 111 insertions(+), 83 deletions(-) diff --git a/src/tls13.c b/src/tls13.c index a947ee8a61..85a7434899 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -5879,7 +5879,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); } @@ -7452,7 +7453,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; @@ -13686,8 +13688,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; } diff --git a/tests/api.c b/tests/api.c index 22f5f8772d..830f464178 100644 --- a/tests/api.c +++ b/tests/api.c @@ -14534,7 +14534,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; } @@ -14616,13 +14616,6 @@ static int test_wolfSSL_Tls13_Key_Logging_test(void) test_ssl_cbf server_cbf; test_ssl_cbf client_cbf; XFILE fp = XBADFILE; - int label_count = 4; -#ifdef HAVE_KEYING_MATERIAL - label_count += 1; -#endif -#ifdef HAVE_ECH - label_count += 2; -#endif XMEMSET(&server_cbf, 0, sizeof(test_ssl_cbf)); XMEMSET(&client_cbf, 0, sizeof(test_ssl_cbf)); @@ -14646,47 +14639,56 @@ static int test_wolfSSL_Tls13_Key_Logging_test(void) { char buff[300] = {0}; int found[7] = {0}; - int numfnd = 0; - int i; +#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]++; +#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]++; 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]++; 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]++; continue; } #ifdef HAVE_KEYING_MATERIAL - else if (0 == strncmp(buff, "EXPORTER_SECRET ", + else if (0 == XSTRNCMP(buff, "EXPORTER_SECRET ", sizeof("EXPORTER_SECRET ")-1)) { found[4]++; continue; } #endif #ifdef HAVE_ECH - else if (0 == strncmp(buff, "ECH_SECRET ", + 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 == strncmp(buff, "ECH_CONFIG ", + else if (0 == XSTRNCMP(buff, "ECH_CONFIG ", sizeof("ECH_CONFIG ")-1)) { found[6]++; continue; @@ -14695,11 +14697,6 @@ static int test_wolfSSL_Tls13_Key_Logging_test(void) } if (fp != XBADFILE) XFCLOSE(fp); - for (i = 0; i < (int)(sizeof(found) / sizeof(found[0])); i++) { - if (found[i] != 0) - numfnd++; - } - ExpectIntEQ(numfnd, label_count); /* 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); @@ -14716,74 +14713,104 @@ static int test_wolfSSL_Tls13_Key_Logging_test(void) * 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(); } -#if defined(WOLFSSL_TLS13) && defined(OPENSSL_EXTRA) && \ - defined(HAVE_SECRET_CALLBACK) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) -/* Fails only when the derive site fires with an id matching *ctx, so the - * caller can drive each Derive*Secret call site's failure path in isolation. */ -static int keylog_fail_cb(WOLFSSL* ssl, int id, const unsigned char* secret, - int secretSz, void* ctx) -{ - (void)ssl; - (void)secret; - (void)secretSz; - return (ctx != NULL && id == *(const int*)ctx) ? -1 : 0; -} -#endif - -static int test_wolfSSL_Tls13_Key_Logging_callback_fail(void) +/* 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_SSL_MEMIO_TESTS_DEPENDENCIES) - /* A non-zero return from Tls13SecretCb at any derive site must surface as - * TLS13_SECRET_CB_E and fail the handshake. */ - const int labels[] = { - CLIENT_HANDSHAKE_TRAFFIC_SECRET, - SERVER_HANDSHAKE_TRAFFIC_SECRET, - CLIENT_TRAFFIC_SECRET, - SERVER_TRAFFIC_SECRET, -#ifdef HAVE_KEYING_MATERIAL - EXPORTER_SECRET, -#endif -#ifdef HAVE_ECH - ECH_SECRET, - ECH_CONFIG, -#endif - }; - struct test_ssl_memio_ctx test_ctx; - int fail_id; - int i; + 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; - for (i = 0; i < (int)(sizeof(labels) / sizeof(labels[0])); i++) { - fail_id = labels[i]; + 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; - 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; - test_ctx.c_cb.ctx_ready = &test_wolfSSL_Tls13_Key_Logging_client_ctx_ready; - test_ctx.c_cb.ssl_ready = &test_wolfSSL_Tls13_Key_Logging_client_ssl_ready; - test_ctx.s_cb.ctx_ready = &test_wolfSSL_Tls13_Key_Logging_server_ctx_ready; - test_ctx.s_cb.ssl_ready = &test_wolfSSL_Tls13_Key_Logging_server_ssl_ready; + ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS); - ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS); - ExpectIntEQ(wolfSSL_set_tls13_secret_cb(test_ctx.c_ssl, - keylog_fail_cb, &fail_id), WOLFSSL_SUCCESS); - ExpectIntEQ(wolfSSL_set_tls13_secret_cb(test_ctx.s_ssl, - keylog_fail_cb, &fail_id), WOLFSSL_SUCCESS); - ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), - TEST_SUCCESS); - /* either peer may surface the error first depending on derive order */ - ExpectTrue(wolfSSL_get_error(test_ctx.c_ssl, 0) - == WC_NO_ERR_TRACE(TLS13_SECRET_CB_E) || - wolfSSL_get_error(test_ctx.s_ssl, 0) - == WC_NO_ERR_TRACE(TLS13_SECRET_CB_E)); - test_ssl_memio_cleanup(&test_ctx); + /* 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); + /* 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 return EXPECT_RESULT(); @@ -40867,7 +40894,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_callback_fail), + 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), From fb3693ce50db9069a240ddd76d5c2786a5b35022 Mon Sep 17 00:00:00 2001 From: sebastian-carpenter Date: Wed, 20 May 2026 15:44:36 -0700 Subject: [PATCH 025/118] send ECH on rejection --- src/tls.c | 26 ++++++++------------------ src/tls13.c | 10 +++++++++- tests/api.c | 25 +++++++++++++++++++++++-- 3 files changed, 40 insertions(+), 21 deletions(-) diff --git a/src/tls.c b/src/tls.c index 62118d0678..fec8cb545f 100644 --- a/src/tls.c +++ b/src/tls.c @@ -13840,7 +13840,9 @@ 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->hpkeContext == NULL || ech->state == ECH_WRITE_GREASE) { + /* GREASE always writes a fresh enc, even when a prior hpkeContext + * exists from a real CH1 that was rejected */ c16toa(ech->encLen, writeBuf_p); } else { @@ -16460,9 +16462,7 @@ static int TLSX_EchChangeSNI(WOLFSSL* ssl, TLSX** pEchX, /* 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)) { + ((WOLFSSL_ECH*)echX->data)->type == ECH_TYPE_OUTER) { if (ssl->extensions) { serverNameX = TLSX_Find(ssl->extensions, TLSX_SERVER_NAME); @@ -16657,12 +16657,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 && @@ -16869,14 +16863,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, diff --git a/src/tls13.c b/src/tls13.c index 8d7efb9df4..ee8ce71591 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -5854,9 +5854,11 @@ 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, fallback to outer. Swap ECH to GREASE so + * CH2 still carries an ECH extension */ Free_HS_Hashes(ssl->hsHashesEch, ssl->heap); ssl->hsHashesEch = NULL; + ((WOLFSSL_ECH*)args->echX->data)->state = ECH_WRITE_GREASE; } else { /* account for hrr extension instead of server random */ @@ -5878,6 +5880,12 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, } if (ret != 0) return ret; + /* When rejected on HRR, swap ECH to GREASE so CH2 still carries an + * ECH extension */ + if (args->extMsgType == hello_retry_request && + !ssl->options.echAccepted) { + ((WOLFSSL_ECH*)args->echX->data)->state = ECH_WRITE_GREASE; + } /* use the inner random for client random */ if (args->extMsgType != hello_retry_request) { XMEMCPY(ssl->arrays->clientRandom, diff --git a/tests/api.c b/tests/api.c index fe92bdee85..3ae03277af 100644 --- a/tests/api.c +++ b/tests/api.c @@ -16081,11 +16081,13 @@ 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; test_ssl_memio_ctx test_ctx; + word16 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; XMEMSET(&test_ctx, 0, sizeof(test_ctx)); @@ -16115,7 +16117,26 @@ 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 */ + /* One round: client sends CH1, server consumes it and writes HRR */ + (void)test_ssl_memio_do_handshake(&test_ctx, 1, NULL); + + ExpectIntEQ(ech_find_extension(test_ctx.s_buff, &idx, TLSXT_ECH), 0); + + if (EXPECT_SUCCESS()) { + idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + + /* 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(test_ctx.c_ssl->options.echAccepted, 0); + /* 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); From 6c5097e7edc1ed3146745c3d7eb59940e3b2703c Mon Sep 17 00:00:00 2001 From: Anthony Hu Date: Fri, 8 May 2026 15:57:41 -0400 Subject: [PATCH 026/118] Enforce only 1 protocolname in serverhello --- src/tls.c | 10 ++++++++++ tests/api.c | 1 + tests/api/test_tls_ext.c | 38 ++++++++++++++++++++++++++++++++++++++ tests/api/test_tls_ext.h | 1 + 4 files changed, 50 insertions(+) diff --git a/src/tls.c b/src/tls.c index 62118d0678..388a2095b6 100644 --- a/src/tls.c +++ b/src/tls.c @@ -2026,6 +2026,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 +2043,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) { diff --git a/tests/api.c b/tests/api.c index fe92bdee85..1a77d179a2 100644 --- a/tests/api.c +++ b/tests/api.c @@ -40753,6 +40753,7 @@ 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_wolfSSL_wolfSSL_UseSecureRenegotiation), TEST_DECL(test_wolfSSL_clear_secure_renegotiation), TEST_DECL(test_wolfSSL_SCR_Reconnect), diff --git a/tests/api/test_tls_ext.c b/tests/api/test_tls_ext.c index 294fa9c903..49edaf29f5 100644 --- a/tests/api/test_tls_ext.c +++ b/tests/api/test_tls_ext.c @@ -1033,3 +1033,41 @@ 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(); +} diff --git a/tests/api/test_tls_ext.h b/tests/api/test_tls_ext.h index e9d07d81ec..dc617e2d62 100644 --- a/tests/api/test_tls_ext.h +++ b/tests/api/test_tls_ext.h @@ -36,5 +36,6 @@ 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); #endif /* TESTS_API_TEST_TLS_EMS_H */ From 056d548467619743d4c58e620d8748821b6dbb48 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Tue, 12 May 2026 22:08:33 -0400 Subject: [PATCH 027/118] Rust wrapper: add scrypt kdf support and scrypt_password_hash trait impl module --- wrapper/rust/wolfssl-wolfcrypt/build.rs | 1 + wrapper/rust/wolfssl-wolfcrypt/src/kdf.rs | 108 ++++++++ wrapper/rust/wolfssl-wolfcrypt/src/lib.rs | 2 + .../src/scrypt_password_hash.rs | 252 ++++++++++++++++++ .../tests/test_scrypt_password_hash.rs | 164 ++++++++++++ 5 files changed, 527 insertions(+) create mode 100644 wrapper/rust/wolfssl-wolfcrypt/src/scrypt_password_hash.rs create mode 100644 wrapper/rust/wolfssl-wolfcrypt/tests/test_scrypt_password_hash.rs diff --git a/wrapper/rust/wolfssl-wolfcrypt/build.rs b/wrapper/rust/wolfssl-wolfcrypt/build.rs index 3d0c7ea6b1..6306c88f54 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"); 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..ced6a90cab 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/lib.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/lib.rs @@ -79,6 +79,8 @@ 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/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_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); +} From 014925d37b933e443f19c12b97686d2ee1ce9b4c Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Thu, 14 May 2026 08:59:48 -0400 Subject: [PATCH 028/118] Rust wrapper: Add RSA-OAEP API --- wrapper/rust/wolfssl-wolfcrypt/build.rs | 1 + wrapper/rust/wolfssl-wolfcrypt/src/lib.rs | 2 + wrapper/rust/wolfssl-wolfcrypt/src/rsa.rs | 156 +++++++ .../rust/wolfssl-wolfcrypt/src/rsa_oaep.rs | 386 ++++++++++++++++++ .../rust/wolfssl-wolfcrypt/tests/test_rsa.rs | 64 +++ .../wolfssl-wolfcrypt/tests/test_rsa_oaep.rs | 139 +++++++ 6 files changed, 748 insertions(+) create mode 100644 wrapper/rust/wolfssl-wolfcrypt/src/rsa_oaep.rs create mode 100644 wrapper/rust/wolfssl-wolfcrypt/tests/test_rsa_oaep.rs diff --git a/wrapper/rust/wolfssl-wolfcrypt/build.rs b/wrapper/rust/wolfssl-wolfcrypt/build.rs index 6306c88f54..646932366b 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/build.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/build.rs @@ -458,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/lib.rs b/wrapper/rust/wolfssl-wolfcrypt/src/lib.rs index ced6a90cab..f25e42a574 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/lib.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/lib.rs @@ -74,6 +74,8 @@ 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; diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/rsa.rs b/wrapper/rust/wolfssl-wolfcrypt/src/rsa.rs index da9dc765d1..3dcf307c25 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/rsa.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/rsa.rs @@ -847,6 +847,162 @@ 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 { + Some(label) => (label.as_ptr() as *mut u8, crate::buffer_len_to_u32(label.len())?), + None => (core::ptr::null_mut(), 0), + }; + let rc = unsafe { + 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 { + Some(label) => (label.as_ptr() as *mut u8, crate::buffer_len_to_u32(label.len())?), + None => (core::ptr::null_mut(), 0), + }; + let rc = unsafe { + 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/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()); +} From 830aa7f7b6dbf20ad97da53e079210e9a5c73518 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Tue, 19 May 2026 10:17:49 -0700 Subject: [PATCH 029/118] Rust wrapper: fix CFB::encrypt1 and CFB::decrypt1 to take size in bits --- wrapper/rust/wolfssl-wolfcrypt/src/aes.rs | 28 ++++++++++++------- .../rust/wolfssl-wolfcrypt/tests/test_aes.rs | 28 +++++++++++++++++++ 2 files changed, 46 insertions(+), 10 deletions(-) diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/aes.rs b/wrapper/rust/wolfssl-wolfcrypt/src/aes.rs index 7d954d2164..3974d930af 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); 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() { From f7a5df34897ec5eceb6a73e0ed6bccde7bd70706 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Tue, 19 May 2026 11:05:28 -0700 Subject: [PATCH 030/118] Rust wrapper: support older non-const RSA API in rsa_pkcs1v15.rs --- .../rust/wolfssl-wolfcrypt/src/rsa_pkcs1v15.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) 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, ) From e3f57d5f92cfe907c4c3e38e2b8b6341e3fc2f7c Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Tue, 19 May 2026 11:15:24 -0700 Subject: [PATCH 031/118] Rust wrapper: fix ParamInvalid error in hash_password_customized() --- wrapper/rust/wolfssl-wolfcrypt/src/pbkdf2_password_hash.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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" })?; From 904975d5a983a1862da820725dc041acd41107b0 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Tue, 19 May 2026 11:32:34 -0700 Subject: [PATCH 032/118] Rust wrapper: add null check for kid_ptr returned from C in Lms::get_kid() --- wrapper/rust/wolfssl-wolfcrypt/src/lms.rs | 3 +++ 1 file changed, 3 insertions(+) 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); From 685a6632a9818088c7826a6186e3050f432be72f Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Tue, 19 May 2026 11:47:11 -0700 Subject: [PATCH 033/118] Rust wrapper: zeroize mlkem_kem seeds after use --- wrapper/rust/wolfssl-wolfcrypt/src/mlkem_kem.rs | 2 ++ 1 file changed, 2 insertions(+) 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]; From 364e883941e75c2bda300c088e12ca0c81e5e28e Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Fri, 29 May 2026 10:40:12 -0400 Subject: [PATCH 034/118] Rust wrapper: handle MAC_CMP_FAILED_E from CMAC::verify{,_ex}() Fix F-4468 --- wrapper/rust/wolfssl-wolfcrypt/src/cmac.rs | 6 ++++++ wrapper/rust/wolfssl-wolfcrypt/tests/test_cmac.rs | 8 ++++++++ 2 files changed, 14 insertions(+) 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/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); } From bdd70dd3e361e3a605b1d43b233434ab39a615e3 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Fri, 29 May 2026 10:44:39 -0400 Subject: [PATCH 035/118] Rust wrapper: zeroize XTSStream.xtsaesstreamdata Fix F-4467 --- wrapper/rust/wolfssl-wolfcrypt/src/aes.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/aes.rs b/wrapper/rust/wolfssl-wolfcrypt/src/aes.rs index 3974d930af..d58250b857 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/aes.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/aes.rs @@ -3001,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)] From b737370ac467b7935e79b457896c51c2b08c481d Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Fri, 29 May 2026 10:45:41 -0400 Subject: [PATCH 036/118] Rust wrapper: add new files to include.am --- wrapper/rust/include.am | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) 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 From 75de834b7f2f0c0073a8c698d58f7f0048371844 Mon Sep 17 00:00:00 2001 From: sebastian-carpenter Date: Thu, 28 May 2026 17:12:03 -0600 Subject: [PATCH 037/118] fix GREASE ECH write --- src/tls.c | 111 ++++++++++++++++++++++++++------------------- src/tls13.c | 35 +++++++------- tests/api.c | 14 +++--- wolfssl/internal.h | 1 + 4 files changed, 89 insertions(+), 72 deletions(-) diff --git a/src/tls.c b/src/tls.c index fec8cb545f..1fbfa5524f 100644 --- a/src/tls.c +++ b/src/tls.c @@ -13645,10 +13645,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); @@ -13840,9 +13845,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 || ech->state == ECH_WRITE_GREASE) { - /* GREASE always writes a fresh enc, even when a prior hpkeContext - * exists from a real CH1 that was rejected */ + if (ech->innerCount == 0) { c16toa(ech->encLen, writeBuf_p); } else { @@ -13851,50 +13854,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; @@ -13917,11 +13929,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; @@ -13946,8 +13966,8 @@ 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; } @@ -16460,8 +16480,8 @@ 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 && + /* 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); @@ -16754,8 +16774,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; @@ -16977,10 +16996,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 ee8ce71591..0b1a88bb99 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -4781,7 +4781,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 +4790,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 +4854,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; @@ -5103,10 +5112,10 @@ int SendTls13ClientHello(WOLFSSL* ssl) 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,11 +5863,9 @@ 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. Swap ECH to GREASE so - * CH2 still carries an ECH extension */ + /* server rejected ECH, fall back to outer */ Free_HS_Hashes(ssl->hsHashesEch, ssl->heap); ssl->hsHashesEch = NULL; - ((WOLFSSL_ECH*)args->echX->data)->state = ECH_WRITE_GREASE; } else { /* account for hrr extension instead of server random */ @@ -5880,12 +5887,6 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, } if (ret != 0) return ret; - /* When rejected on HRR, swap ECH to GREASE so CH2 still carries an - * ECH extension */ - if (args->extMsgType == hello_retry_request && - !ssl->options.echAccepted) { - ((WOLFSSL_ECH*)args->echX->data)->state = ECH_WRITE_GREASE; - } /* use the inner random for client random */ if (args->extMsgType != hello_retry_request) { XMEMCPY(ssl->arrays->clientRandom, diff --git a/tests/api.c b/tests/api.c index 3ae03277af..474457552b 100644 --- a/tests/api.c +++ b/tests/api.c @@ -16087,7 +16087,6 @@ static int test_wolfSSL_Tls13_ECH_HRR_rejection(void) { EXPECT_DECLS; test_ssl_memio_ctx test_ctx; - word16 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; XMEMSET(&test_ctx, 0, sizeof(test_ctx)); @@ -16117,19 +16116,18 @@ static int test_wolfSSL_Tls13_ECH_HRR_rejection(void) * outer transcript */ ExpectIntEQ(wolfSSL_NoKeyShares(test_ctx.c_ssl), WOLFSSL_SUCCESS); - /* One round: client sends CH1, server consumes it and writes HRR */ - (void)test_ssl_memio_do_handshake(&test_ctx, 1, NULL); - - ExpectIntEQ(ech_find_extension(test_ctx.s_buff, &idx, TLSXT_ECH), 0); - if (EXPECT_SUCCESS()) { - idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + 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(test_ctx.c_ssl->options.echAccepted, 0); + 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); diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 025878a8d3..1fc6f12ada 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -3111,6 +3111,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, From 62168d44c74d5557fa067cffa36968fad83d0c36 Mon Sep 17 00:00:00 2001 From: jordan Date: Mon, 1 Jun 2026 00:03:56 -0500 Subject: [PATCH 038/118] bsdkm: misc cleanup. --- bsdkm/wolfkmod.c | 29 ++++++++++++++++++++--------- bsdkm/wolfkmod_aes.c | 2 +- bsdkm/x86_vecreg.c | 10 ++++++++++ 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/bsdkm/wolfkmod.c b/bsdkm/wolfkmod.c index 872d68589f..8767f46cb7 100644 --- a/bsdkm/wolfkmod.c +++ b/bsdkm/wolfkmod.c @@ -491,8 +491,9 @@ static int wolfkdriv_attach(device_t dev) attach_out: if (error) { - wolfkdriv_unregister(softc); + device_printf(dev, "error: attach_out: %d\n", error); (void)wolfkmod_cleanup(); + wolfkdriv_unregister(softc); } return (error); @@ -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); ret = wolfkmod_cleanup(); - - if (ret == 0) { - /* unregister wolfcrypt algs */ - softc = device_get_softc(dev); - wolfkdriv_unregister(softc); - } - + 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..d621cee599 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("info : 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("info: 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. */ From 226f96db33da7777474106553c1b8bc7599a32af Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Mon, 1 Jun 2026 14:57:58 -0400 Subject: [PATCH 039/118] Rust wrapper: add comments about label pointer casts in rsa.rs --- wrapper/rust/wolfssl-wolfcrypt/src/rsa.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/rsa.rs b/wrapper/rust/wolfssl-wolfcrypt/src/rsa.rs index 3dcf307c25..d7c422ee35 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/rsa.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/rsa.rs @@ -928,10 +928,13 @@ impl RSA { 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, @@ -988,10 +991,13 @@ impl RSA { 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, From 492603fbd4e1198aa8de2eacaa3403ac6d72aeb0 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Mon, 1 Jun 2026 16:15:43 -0400 Subject: [PATCH 040/118] Early-return from TLS 1.2 resumption on SNI/ALPN mismatch --- src/internal.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/internal.c b/src/internal.c index 664c0045b5..d767f9846d 100644 --- a/src/internal.c +++ b/src/internal.c @@ -38097,6 +38097,7 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) TICKET_BINDING_HASH_SZ) != 0) { WOLFSSL_MSG("Resumed session SNI mismatch, full handshake"); ssl->options.resuming = 0; + return ret; } #endif #ifdef HAVE_ALPN @@ -38106,6 +38107,7 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) TICKET_BINDING_HASH_SZ) != 0)) { WOLFSSL_MSG("Resumed session ALPN mismatch, full handshake"); ssl->options.resuming = 0; + return ret; } #endif } From 320010aad66e93b666c6d4f46c8024ce058bd43b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Tue, 2 Jun 2026 10:51:37 +0200 Subject: [PATCH 041/118] Migrate internal ML-KEM consumers to canonical wc_MlKemKey API --- src/tls.c | 132 ++++++++++++++++---------------- tests/api/test_tls13.c | 4 +- wolfcrypt/benchmark/benchmark.c | 44 +++++------ wolfcrypt/src/cryptocb.c | 2 +- wolfcrypt/test/test.c | 42 +++++----- 5 files changed, 112 insertions(+), 112 deletions(-) diff --git a/src/tls.c b/src/tls.c index 62118d0678..77d0872cfe 100644 --- a/src/tls.c +++ b/src/tls.c @@ -8585,7 +8585,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 @@ -8745,11 +8745,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 @@ -8762,7 +8762,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; } @@ -8770,7 +8770,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"); @@ -8780,17 +8780,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) { @@ -8802,8 +8802,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"); @@ -8811,13 +8811,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 @@ -8831,32 +8831,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 @@ -8872,7 +8872,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 @@ -9031,7 +9031,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; @@ -9043,7 +9043,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 @@ -9131,7 +9131,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); @@ -9146,7 +9146,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); @@ -9895,7 +9895,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. @@ -9910,7 +9910,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 @@ -9934,8 +9934,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"); @@ -9949,29 +9949,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."); @@ -9979,7 +9979,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 @@ -9990,11 +9990,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; } } @@ -10002,7 +10002,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; @@ -10013,7 +10013,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. @@ -10101,11 +10101,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"); @@ -10113,10 +10113,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 @@ -10127,11 +10127,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."); @@ -10665,7 +10665,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. @@ -10683,7 +10683,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; @@ -10698,8 +10698,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"); @@ -10713,21 +10713,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) { @@ -10745,13 +10745,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."); } } @@ -10774,7 +10774,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; @@ -10834,8 +10834,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"); @@ -10849,22 +10849,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); } } diff --git a/tests/api/test_tls13.c b/tests/api/test_tls13.c index ca37fb48cc..72890c627b 100644 --- a/tests/api/test_tls13.c +++ b/tests/api/test_tls13.c @@ -4847,7 +4847,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 +4944,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 diff --git a/wolfcrypt/benchmark/benchmark.c b/wolfcrypt/benchmark/benchmark.c index c99fc71822..e96ee0bd76 100644 --- a/wolfcrypt/benchmark/benchmark.c +++ b/wolfcrypt/benchmark/benchmark.c @@ -11088,7 +11088,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; @@ -11103,17 +11103,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) @@ -11143,7 +11143,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; @@ -11161,24 +11161,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; } @@ -11190,10 +11190,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) @@ -11223,7 +11223,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(); @@ -11260,11 +11260,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; @@ -11315,10 +11315,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; @@ -11331,8 +11331,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/cryptocb.c b/wolfcrypt/src/cryptocb.c index c3af7ed608..8179a1700c 100644 --- a/wolfcrypt/src/cryptocb.c +++ b/wolfcrypt/src/cryptocb.c @@ -1177,7 +1177,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; diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index f3fc88c8a1..1bd05904b9 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -48538,23 +48538,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); @@ -48566,14 +48566,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); @@ -48588,7 +48588,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); @@ -50001,23 +50001,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); @@ -50029,14 +50029,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); @@ -50051,7 +50051,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); @@ -51848,23 +51848,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); @@ -51876,14 +51876,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); @@ -51898,7 +51898,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); From 08a7c4590ea35498c42fed365aa8173766c7eaca Mon Sep 17 00:00:00 2001 From: Ruby Martin Date: Tue, 26 May 2026 12:10:05 -0600 Subject: [PATCH 042/118] Remove CheckOcspResponderChain and related references. Function is not compliant with RFC 6960, 4.2.2.2. remove unused vp parameter Update ChangeLog.md to include OCSP responder change --- .wolfssl_known_macro_extras | 1 - ChangeLog.md | 8 ++++ src/ocsp.c | 89 +------------------------------------ wolfcrypt/src/asn.c | 8 ++-- wolfcrypt/src/asn_orig.c | 2 +- wolfssl/ocsp.h | 2 +- 6 files changed, 16 insertions(+), 94 deletions(-) diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index fb34d7c6f2..08f7b2b43c 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -844,7 +844,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 diff --git a/ChangeLog.md b/ChangeLog.md index ef01745e95..9deacce2ce 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -46,6 +46,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/src/ocsp.c b/src/ocsp.c index 14d5eb1354..14e3bafeb9 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) { @@ -1111,8 +1027,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; diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index f4ef7125ef..282e761461 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -33718,7 +33718,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; @@ -33733,7 +33733,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; @@ -33823,7 +33823,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; @@ -34044,7 +34044,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; } } diff --git a/wolfcrypt/src/asn_orig.c b/wolfcrypt/src/asn_orig.c index 7db2a4eed1..156e3c0f3e 100644 --- a/wolfcrypt/src/asn_orig.c +++ b/wolfcrypt/src/asn_orig.c @@ -8905,7 +8905,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/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); From 5c3100ed5cb41bd60cbf906b90ea555aee0b5eab Mon Sep 17 00:00:00 2001 From: Ruby Martin Date: Tue, 26 May 2026 13:35:18 -0600 Subject: [PATCH 043/118] Remove non-RFC-compliant OCSP responder chain walk. The chain walk authorized any responder issued by an ancestor of the target's issuer; RFC 6960 4.2.2.2 requires direct issuance by the CA identified in the request. - Remove CheckOcspResponderChain() and WOLFSSL_NO_OCSP_ISSUER_CHAIN_CHECK. - Drop now-unused vp parameter from CheckOcspResponder() and the OcspRespCheck() helper; cascade through template and non-template paths. OCSP test blobs: - Re-sign resp_server1_cert with intermediate1-ca (CA-direct path). - Add resp_server1_cert_ancestor_responder for the negative test. - Embed server1_cert_pem[] in test_ocsp_test_blobs.h so the new test runs under NO_FILESYSTEM; matching entry added to create_ocsp_test_blobs.py. - Regenerate response[] in test_certman.c with intermediate1-ca as signer; recipe switched from Wireshark export to openssl -respout + xxd -i for reproducibility. - Fix self-XOR in test_wolfSSL_CertManagerCheckOCSPResponse so the serial byte actually flips (^= 0xFF). Live OCSP coverage: - Add ocsp-responder-int1 (delegated responder issued directly by intermediate1-ca, with id-kp-OCSPSigning EKU) for the responder->intermediate->root chain. - scripts/ocsp-stapling.test: intermediate1 responder switched to ocsp-responder-int1 (delegated path). - scripts/ocsp-stapling2.test, scripts/ocsp-stapling_tls13multi.test: intermediate2 and intermediate3 sign their OCSP responses with their own CA keys (CA-direct path); root block unchanged (ocsp-responder-cert is still RFC-compliant for root-issued certs). - .github/workflows/ocsp.yml: server1 OCSP responder switched to ocsp-responder-int1 to match the cert chain. - New test_ocsp_ancestor_responder_rejected confirms the ancestor-issued response is rejected with OCSP_LOOKUP_FAIL. --- .github/workflows/ocsp.yml | 2 +- certs/ocsp/include.am | 4 + certs/ocsp/ocsp-responder-int1-cert.der | Bin 0 -> 1233 bytes certs/ocsp/ocsp-responder-int1-cert.pem | 273 ++++++++ certs/ocsp/ocsp-responder-int1-key.der | Bin 0 -> 1218 bytes certs/ocsp/ocsp-responder-int1-key.pem | 28 + certs/ocsp/renewcerts.sh | 15 +- certs/ocsp/test-leaf-response.der | Bin 1860 -> 1880 bytes scripts/ocsp-stapling.test | 4 +- scripts/ocsp-stapling2.test | 8 +- scripts/ocsp-stapling_tls13multi.test | 8 +- tests/api.c | 1 + tests/api/create_ocsp_test_blobs.py | 20 +- tests/api/test_certman.c | 405 +++++------- tests/api/test_ocsp.c | 27 + tests/api/test_ocsp.h | 1 + tests/api/test_ocsp_test_blobs.h | 827 ++++++++++++++---------- 17 files changed, 1035 insertions(+), 588 deletions(-) create mode 100644 certs/ocsp/ocsp-responder-int1-cert.der create mode 100644 certs/ocsp/ocsp-responder-int1-cert.pem create mode 100644 certs/ocsp/ocsp-responder-int1-key.der create mode 100644 certs/ocsp/ocsp-responder-int1-key.pem 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/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 0000000000000000000000000000000000000000..c9203cb81ba0896aea359b76f81f5df9717ea112 GIT binary patch literal 1233 zcmXqLVmWKj#JqI@GZP~d6C;-aFB_*;n@8JsUPeZ4RtAH{g@)V)oNUaYENsF|p}~g2 z27(|C2Mo}qvNA4rg$hdnqov7{s?6(+*P!(N`BlNKE8V<=)E1X9Dz z!|j@vo|%`LT9lcWZm49S01{>9k%X#K$jmEAEy_(z$xJLsRd9AxFf^1mkcGR6lTl0{ zGcPUQ0i?XRI7crzKi5D`oY%E~X|%Mur(p zAD-WeIN!>>ERhS>_9`PZscW!DPqxFA{6P%x)KZECQS%mhF6w_o$x^Yva&n))C=_}@P9 zmG#fIb9yJw;h276vstM{uHF9|50y&8rQ#C|e5Lp3&#Y&9e_utlBYa}DPX6~96Ex=w zrLD9pKGInHe9mj7uQ^whA5`yJc1moq@lU;=#VbyJyxS^&a0<6v|8|dk3KwqewQlX3 zbnrvX8@;3I3;dLh9`cn=d%h;T$3%N+=u4A1^~RbP{7y?rF^O+-UF^vk%TU=GF!6w` z!RZ#RS-QDQ%!~|-i<=m^44N3(z)4b8n1#uJ!9bRcIaHR9MT|vcg3Zp~q6(|OvMe`X&oqRN^!Zxx3F>UlEzsE zjniqGP9zM(AnAl3mQITD^Gg(*9SNrJCPqdBVURCWS$GV%*f_M=7+G1_nK_Zu3pY5u zFf!OUZ9TkL>bmZ+EZa>n5}vJUsjce|>ABrmDATLd_Ge`=Q)PnP^B-sapWJBiV4A<- zj;C9BHpt2xQrA3gU(gnns3&;5v9zn`M=4LszEqbP=QP`y4Bk4q|0%uMQJk_i`>fHl z&{tc3_bHxZio9bt-`FAT$i5GS9p}EzsMNh1p{=o>v$KQM&g|Z^jkErEHApl3J*nk( zt|z5&hw91NONOjEp5ZTB4lKFzO`-1h!Rtr&ykg(~OkhEKTT+@B{)W|d75CoAX(E;FsDInYOs^c1V8n+U-R1Y^3b$PUc8`4u7jEsfZta_N@I%cTy`$<2 z{FII!@|8||z9ziKM0;uIOOrYE#+n!WPD@EKiEnaU?8zF-P}v$V@qn$t=@zb8y17iu zj0}uSO^gh}qRSVaKL6YP<0GLBuD)L-)^q&U`t?e?;m--v1HMly#d6cXC0^}PQ(s$l zx!|kAzOuiLK{eCsbhOG@SFb%ZQR}s1Q*Tb0!?yf00xM(RsZZC*t3H(Jkyo;P+Ahm? zJz9J_T|`y4O?+F-^61Cb<0)3!JdPQ+G=i#Awr%5Wy4=taas45e_a&~|iEk>qlP>2v z%y}%^clJkbzk^}e-ts!m$s_v`+uF^c`@{Rw{1w8c~I(e>u{$H zii;+ApWpWI?*f~iv&PLkKA(E{>OhTWm}5zK(gJgrd#w3M4_iVPl+M}Jl(2f;IfQiLQ_LR>eRzRUPef#Fk<%bP+ zoXUzWUtWK7_9BhNojW;?=OhcVb2h$Pqa1tN_>#zn(+s=5%rTy#owvSbY3=fmjckez zlb45Q^5<7N^>GAe&lf2{pc*VhF&RrKhRD>PvDI0 zxdkS+IxcH>i2b`Hw5}^jak_*5o;7bL&YCQ@<}Pn=+xqWj>C$k*dZ~g!O`i!M|d=EL>+!p>)u$@v@#IT9&+t;X&^^)9%Eu3Z-JT%XF9npI! z%(C~i*o2@9r(KK;$|^x_SmdseHG6s~`)=b;ul~g7UAFplAYqA#v0EaqVBoh!|M>-W zUOR7-6SKPifqKgGdn->wA5{O$|6+a4vnXNHR`n&fr|0=yIAnErL?EL+@?rZZ1jDtcgxZtv_p4PWN1 hUuR&nJXU$0f0yaz37U0JS0%bEK9%NM)zQwg003lhLVy4O literal 0 HcmV?d00001 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 dc086fed436ff7e8a9c68e69ac17b9781d9f71b0..1e0f16dece3aac5bceeebe2ff5d62472bc63b2e8 100644 GIT binary patch delta 1194 zcmX@YcY{yIpou+%i;-bL6T7cL6T2rHr#2fSD=WJJBO^-_yOlu`yO}`~qwB)PWd@Cl zCpWUjs;U?$u`!3TF!M;4=jWsa2m2`aI|m0S1f>=i zWM*J$WNv6?WMFDM@s@`i5;tmrAXtT^fsv5`M8#wWMlpej4wB6g7tS$Cchm?JwWbPB zHeeH}ceh&g{JeDFs_w{AODhBRzd~n^?AP4&xUXO5n~mwnaAoVlK>2vb)g7FmFcO>RBO+q{bFzqi&3DKA^7WK#dxvzTk$_vwz`x)d$$o#R}) zReRwy`zcN@uea=bJYm0V!*o`LJ@E^_U$Faj+cYR+hp!g9`~rz{e7~dOt*b>@em}S} zh2xoj`rkvDZ90uJJ+)SU-!_|R!hPR5FALt-{M|0ECa`wSsa+;;jZf~z>%hY_6iv!X1`3d9l7vN5W?o5ZQEqBVW@1UIg0rInD3X+v^V zYXprDFqhO=cdDP!^x^rfi1V%7OYWIC+E+&XFRhq*tTSf2-jQ6^;-wp1BZ};F9vu*G z|FF6O}>9pr-!h1}#mxjJHnNx49dBN|rloXTr zCfCKDtg#H0tpO7c*czN};hM#yn>$&SRoQNW&CcJV3ah{6U;cQqaKi=J>Bp8HHE2A- z#vCfE%+k2WpmAq|Nb@nPPMyXtOxNf7JkmN)*p%XOi*I4$+$D{(CNE@~#oWZmI9Zxa zv);yO>*2*x*L9C&*=~xF@N88}ZC!sz&+X1anO>!~KP!uwDiiFU|2XsiGr`gVA@Yc!wPwCB$;*_=7XN{(X zzS{b`Pw^a6D#tvym_I)VqIQMl%rS9DbZH@i)oShx4c4qgUZJhPTt3jIK?@2AU zb3G}IJ5*2BUNU6W@eF_2a$w1wZwht44_-gI=N0?@X95d?RsHLZmao`yY=%xzndhsg zuDg#s{o_4{BV~*J{^@-!E!Pd2>Wx&38LmdSXnW~!RJH~1zkELB;uSvsl@C_$>V6@$ RZ^EP$O99gfob^m^GXc&O_@@8> delta 1172 zcmcb?cZ5&Jpo!gqi;-bL6T78B6T2xJr#2fSD=WJJBO^-_yP820yOKc@qr<|+g$9lD zCg(E8D##nivN4CUF!P9&=jWsa2m2`aI|m0S1f>=iP1%eX%Mg~R}1{MaE5EW4il?@aPxp~JqEmNoLX%jZQpqr8M#>*n41_G8M-1X9v-n*F1{fvCA)WmY){7#2cM~ze*DuZ zzbm5GV5Jzh@{~cAh*drF*Hh*-Cd@6fO_8;4N?o@^ z=BvQPjs+oYoBwsYF*I6Bo4bFDb@rM%StR_$_v(h&L&Z*Vlh+m3hgHOt*R%YpW<0@c z^Lm$QANR6z%rlcO-@niLt?9@-j_Uj=L46T&+xZMVrPz*}hiV^d5^q>B^?Ce)^2dC( zLFulGvn7S4rI&mS)Cq8Z@;v7U*Jj1J276vP&)j&Qa|4s>f+m(@22Cu744PQ>88k63 zTfof3$i&3Rf*M+^3JbL?-y_@#Gr&0EfCF!M8S5CQl_?^>_-q(|+KD?Q_-T8>bJ+X!f=TuA;kA$v? z3VfiayO}G>->cX#;GLJ)Ud!&atRD648)rTeSk6|Iek$hT^t~rOmi>6(^=8lHFKIp+ zg%@w6F>je*uv>h?zv*A)UL22|-7P37WV5=du;TwZd!tPpg`1>%)Yk~^xZ&)1enY{= z4?XK{skDn*-(X42VJHiDFUoO!OL2ypNc+^o@p*|m+FO1#NO5(~`26_4pNmXtNljr$ zD$`TT$%d@T7Dnk0H&$M1{4-yfr@$d#t6SI(12cohBW%o}vdS!tdkh+PHi#5&kXfSN zbo#veQj6;wSemTribNGB_pmNvOrEUIrdh9a{?QQ|zVpt9w99V>@80hgm98d#t>@9Y z%h|VTmTsxkvrNtM4?34)hXZ zUm()pZs_{K&~)cy%W|W@1>KV;PAhkmG7#PI?6qf~%~C}#CtGC$AHPPzKT zN%n0{{dVh(6~|_6uz2+BU-aR2K~Fi4;;4@D&fmw|-?u*$?@kkQsmY7ijncocuPn3W zmd#@S{S5!lq_c@R@R#0stZ=P*=JEX&ih%}R-sRUVFF*24&)}<>dL&Tk2!F}ayIExport 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); diff --git a/tests/api/test_ocsp.c b/tests/api/test_ocsp.c index 7945c1433c..279693edca 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 a139f56824..12a7495a3c 100644 --- a/tests/api/test_ocsp.h +++ b/tests/api/test_ocsp.h @@ -33,5 +33,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 */ From 754f5cfe4161f886f83d4fae4358fd0c412219da Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Mon, 1 Jun 2026 18:31:02 +0200 Subject: [PATCH 044/118] F-5606: enforce DTLS 1.3 KeyUpdate 2^48-1 sending epoch ceiling RFC 9147 Section 4.2.1 limits the DTLS 1.3 epoch to 2^48-1. SendTls13KeyUpdate now refuses to send a KeyUpdate when the sending epoch is already at the maximum, and Dtls13KeyUpdateAckReceived rejects an epoch that would exceed the limit after incrementing (previously only a full 64-bit wrap to zero was checked). --- src/dtls13.c | 14 ++++++++++++-- src/tls13.c | 23 +++++++++++++++++++++-- wolfssl/internal.h | 5 +++++ 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/src/dtls13.c b/src/dtls13.c index 995d144119..299dafca92 100644 --- a/src/dtls13.c +++ b/src/dtls13.c @@ -2720,17 +2720,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/tls13.c b/src/tls13.c index 8d7efb9df4..23fa8e25d2 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -12172,8 +12172,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; @@ -12307,7 +12315,18 @@ static int DoTls13KeyUpdate(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #ifdef WOLFSSL_DTLS13 if (ssl->options.dtls) { - w64Increment(&ssl->dtls13PeerEpoch); + w64wrapper newEpoch = ssl->dtls13PeerEpoch; + w64Increment(&newEpoch); + + /* RFC 9147 Section 4.2.1: the epoch must not exceed 2^48-1. Reject a + * peer KeyUpdate that would advance the receiving epoch past the + * limit. Validate on a local copy so ssl->dtls13PeerEpoch is left + * untouched when the check fails. */ + if (w64GT(newEpoch, + w64From32(DTLS13_EPOCH_MAX_HI32, DTLS13_EPOCH_MAX_LO32))) + return BAD_STATE_E; + + ssl->dtls13PeerEpoch = newEpoch; ret = Dtls13SetEpochKeys(ssl, ssl->dtls13PeerEpoch, DECRYPT_SIDE_ONLY); if (ret != 0) diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 794808f38b..fb5f8a3233 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -5948,6 +5948,11 @@ enum { DTLS13_EPOCH_TRAFFIC0 = 3 }; +/* RFC 9147 Section 4.2.1: the DTLS 1.3 epoch is a 48-bit value and must not + * exceed 2^48-1. 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 */ From 7047d4e01ad8546023167660c754a393f0e59298 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Mon, 1 Jun 2026 18:31:20 +0200 Subject: [PATCH 045/118] F-5590: reject oversized length in wolfSSL_CRYPTO_memcmp The size_t length was cast directly to the int taken by ConstantCompare. On 64-bit builds a size with a negative low 32-bit value (e.g. 0x80000000) became a negative length, so ConstantCompare ran zero iterations and returned 0 (equal) without comparing. Reject size > INT_MAX with a non-zero (mismatch) result before narrowing. --- src/ssl.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/ssl.c b/src/ssl.c index efbbf3074e..1dc5717476 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -16199,9 +16199,24 @@ int wolfSSL_CTX_set_servername_arg(WOLFSSL_CTX* ctx, void* arg) 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) From abb59434662c5b04851eb774261f52bdc1ab8d8b Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Mon, 1 Jun 2026 18:31:31 +0200 Subject: [PATCH 046/118] F-4594: return non-zero from wolfSSL_get_verify_result on NULL ssl WOLFSSL_FAILURE is 0, which equals X509_V_OK, so a NULL ssl was indistinguishable from successful verification under the standard "SSL_get_verify_result(ssl) \!= X509_V_OK" idiom. Return WOLFSSL_X509_V_ERR_APPLICATION_VERIFICATION (50, matching the OpenSSL compat value) instead, and add it to the X509 verify-error enum. --- src/ssl.c | 5 ++++- tests/api.c | 5 ++++- wolfssl/ssl.h | 1 + 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/ssl.c b/src/ssl.c index 1dc5717476..bd192f78af 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -13025,7 +13025,10 @@ size_t wolfSSL_get_peer_finished(const WOLFSSL *ssl, void *buf, size_t count) long wolfSSL_get_verify_result(const WOLFSSL *ssl) { if (ssl == NULL) { - return WOLFSSL_FAILURE; + /* 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). */ + return WOLFSSL_X509_V_ERR_APPLICATION_VERIFICATION; } return (long)ssl->peerVerifyRet; diff --git a/tests/api.c b/tests/api.c index a2873fd747..183649f15c 100644 --- a/tests/api.c +++ b/tests/api.c @@ -19069,7 +19069,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)); diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 2281bb2f26..f46d0009af 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -2732,6 +2732,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, From 7a0eca841f4cf77bd4f76ff05d31d8ac958f66e1 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Mon, 1 Jun 2026 18:31:46 +0200 Subject: [PATCH 047/118] F-5628: reject max_fragment_length response that differs from request TLSX_MFL_Parse only checked that the extension was requested and that the value was recognized, not that the server echoed the requested value. Per RFC 6066 Section 4, compare the ServerHello value against the locally stored request and abort with a fatal illegal_parameter alert on mismatch. --- src/tls.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/tls.c b/src/tls.c index 62118d0678..bf58e2ee2d 100644 --- a/src/tls.c +++ b/src/tls.c @@ -3251,9 +3251,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) { From 6e7bf5fa66be4abcc8ca39445c65d04688f9ae8c Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Mon, 1 Jun 2026 18:31:58 +0200 Subject: [PATCH 048/118] F-5629: reject ServerHello ALPN response with multiple protocols A response ProtocolNameList was passed whole to ALPN_find_match, which accepts the first configured match, so a server could return more than one protocol. Per RFC 7301 Section 3.1 the ServerHello list must contain exactly one name; enforce that the single name spans the whole list and reject otherwise with a fatal illegal_parameter alert. --- src/tls.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/tls.c b/src/tls.c index bf58e2ee2d..c23f3f7a49 100644 --- a/src/tls.c +++ b/src/tls.c @@ -2065,6 +2065,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; From 18b86922d9119e6657e32c345ad4327999de59cb Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Mon, 1 Jun 2026 18:32:10 +0200 Subject: [PATCH 049/118] F-5630: require signature_algorithms in TLS 1.3 CertificateRequest DoTls13CertificateRequest parsed the extensions but never verified the mandatory signature_algorithms extension was present. A request with none left peerSuites.hashSigAlgoSz at zero and was accepted. Per RFC 8446 Section 4.3.2, reject such a request with a fatal missing_extension alert before selecting a certificate response. --- src/tls13.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/tls13.c b/src/tls13.c index 23fa8e25d2..775a76be40 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -6134,6 +6134,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; From 0089fa852ed5a9f85c167d628b12bdf5822addeb Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Mon, 1 Jun 2026 18:32:25 +0200 Subject: [PATCH 050/118] F-5631: reject zero-length/duplicate post-handshake CertReq context DoTls13CertificateRequest rejected a non-empty context during the handshake but did the complementary check for post-handshake auth. Per RFC 8446 Section 4.3.2 a post-handshake certificate_request_context must be non-empty and unique; reject a zero-length context and one that duplicates a still-pending request context with a fatal illegal_parameter alert. --- src/tls13.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/tls13.c b/src/tls13.c index 775a76be40..063b59b65e 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -6100,11 +6100,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 +6126,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; From 289a2670f40f5dc5adbd120113fbfef1ff550467 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Mon, 1 Jun 2026 18:32:36 +0200 Subject: [PATCH 051/118] F-5591: reject negative group count in group setters wolfSSL_CTX_set_groups/wolfSSL_set_groups only rejected counts above WOLFSSL_MAX_GROUP_COUNT; a negative count skipped the copy loop and was cast to byte (e.g. 255) into numGroups, which InitSSL later trusts for a fixed-size copy. Reject count <= 0 in both, and in the set1_groups OpenSSL-compat wrappers. --- src/ssl.c | 8 ++++---- src/tls.c | 16 ++++++++++------ 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/ssl.c b/src/ssl.c index bd192f78af..395352835c 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -3319,8 +3319,8 @@ int wolfSSL_CTX_set1_groups(WOLFSSL_CTX* ctx, int* groups, int i; int _groups[WOLFSSL_MAX_GROUP_COUNT]; WOLFSSL_ENTER("wolfSSL_CTX_set1_groups"); - if (count == 0) { - WOLFSSL_MSG("Group count is zero"); + if (count <= 0) { + WOLFSSL_MSG("Group count is not positive"); return WOLFSSL_FAILURE; } if (count > WOLFSSL_MAX_GROUP_COUNT) { @@ -3358,8 +3358,8 @@ 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"); + if (count <= 0) { + WOLFSSL_MSG("Group count is not positive"); return WOLFSSL_FAILURE; } if (count > WOLFSSL_MAX_GROUP_COUNT) { diff --git a/src/tls.c b/src/tls.c index c23f3f7a49..2defa82509 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; From 118d3a8226a105532257e47e7eadba2918d93bca Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Mon, 1 Jun 2026 18:32:46 +0200 Subject: [PATCH 052/118] F-5583: evict oldest DTLS 1.3 epoch slot, not the last eligible one Dtls13NewEpochSlot never updated oldestNumber after picking a candidate, so every eligible epoch compared "older" than the sentinel and the last eligible slot was returned instead of the lowest epoch number. Update oldestNumber alongside oldest so the true minimum is evicted. --- src/dtls13.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/dtls13.c b/src/dtls13.c index 299dafca92..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) From 108b120d7fd3271af2d086ce46b81907660d7f5f Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Mon, 1 Jun 2026 18:32:54 +0200 Subject: [PATCH 053/118] F-5632: zeroize Camellia key schedule on cipher free FreeCiphersSide freed cipher->cam with XFREE only, leaving the expanded key schedule and IV in freed heap memory. Call wc_CamelliaFree (which ForceZeros the context) before XFREE, matching the ARIA cleanup above. --- src/internal.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/internal.c b/src/internal.c index dcd8fa8ab6..ccea4c0271 100644 --- a/src/internal.c +++ b/src/internal.c @@ -3282,6 +3282,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 From da719da30c6724c5873e0ffeb59ed7fbfd262552 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Mon, 1 Jun 2026 18:33:04 +0200 Subject: [PATCH 054/118] F-4591: fix right-justification of short DH shared secret The constant-time path of _DH_compute_key (DH_compute_key_padded) had the XMEMMOVE source/dest swapped and used (padded_keySz - keySz) as the length instead of keySz, overwriting the secret with junk when keySz < padded_keySz. Move key[0..keySz-1] to the high end, matching the idiom used in tls.c/sniffer.c. --- src/pk.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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; } From 00a899e9a3cd1d5d8f7c0dc9cd988e80b1e3391e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Sat, 16 May 2026 11:03:35 +0200 Subject: [PATCH 055/118] Fixes for Zephyr secure sockets integration --- .wolfssl_known_macro_extras | 1 + src/ssl.c | 3 --- src/x509.c | 5 +++-- zephyr/Kconfig | 7 +++++++ zephyr/samples/wolfssl_tls_sock/prj-no-malloc.conf | 10 ---------- zephyr/user_settings.h | 9 +++++++++ 6 files changed, 20 insertions(+), 15 deletions(-) diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index fb34d7c6f2..653f801359 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 diff --git a/src/ssl.c b/src/ssl.c index efbbf3074e..3d4940c743 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -10107,7 +10107,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"); @@ -10224,8 +10223,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) { diff --git a/src/x509.c b/src/x509.c index 73f4c3c92e..f365cd84cc 100644 --- a/src/x509.c +++ b/src/x509.c @@ -6049,8 +6049,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 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 From 05f8d0beedc4c5b24fb67fb2be32b78d70b5ce5d Mon Sep 17 00:00:00 2001 From: Mark Atwood Date: Mon, 16 Mar 2026 11:43:49 -0700 Subject: [PATCH 056/118] evp: fix EVP_PKEY_cmp for EC keys after DER deserialization wolfSSL_EVP_PKEY_cmp returned 'not equal' for EC keys that were serialized to DER and deserialized back, even though the key material was identical. This happened because keys imported via RFC 5915 (ECPrivateKey) without the optional public key field had type ECC_PRIVATEKEY_ONLY, meaning the internal ecc_key.pubkey was not populated. The point comparison then failed against a key that did have a populated pubkey. Fix by deriving the public key from the private key via wc_ecc_make_pub() when the ecc_key type is ECC_PRIVATEKEY_ONLY before comparing. Also ensure SetECKeyInternal() is called when the internal representation is not yet synced from external BIGNUMs. --- wolfcrypt/src/evp.c | 53 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 6 deletions(-) diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index c7e1e4c885..f149e8d026 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); From 9e711f5c9c18db7f0c62cb103d4bb84ead101de2 Mon Sep 17 00:00:00 2001 From: Hideki Miyazaki Date: Thu, 4 Jun 2026 09:08:24 +0900 Subject: [PATCH 057/118] Add MAX ENTROPY BITS check --- tests/api/test_random.c | 30 ++++++++++++++++++++++++++++++ tests/api/test_random.h | 4 +++- wolfcrypt/src/wolfentropy.c | 2 +- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/tests/api/test_random.c b/tests/api/test_random.c index cdd7e84499..85ce701283 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(2049, 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/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; } From 2e34433c52af53cd183649cd3787addad98a10af Mon Sep 17 00:00:00 2001 From: Hideki Miyazaki Date: Thu, 4 Jun 2026 10:32:27 +0900 Subject: [PATCH 058/118] enforce trailerField==1 in DecodeRsaPssParams --- tests/api/test_asn.c | 41 +++++++++++++++++++++++++++++++++++++++++ wolfcrypt/src/asn.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/tests/api/test_asn.c b/tests/api/test_asn.c index e9eab25bdf..e40ff8cf4a 100644 --- a/tests/api/test_asn.c +++ b/tests/api/test_asn.c @@ -1097,6 +1097,47 @@ 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)); + } +#endif /* !WOLFSSL_NO_ASN_STRICT */ + #endif /* WC_RSA_PSS && !NO_RSA && !NO_ASN */ return EXPECT_RESULT(); } diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index bb48198a90..099921cc7e 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -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,24 @@ 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 { + WOLFSSL_MSG("DecodeRsaPssParams: trailerField must be 1"); + if (ret >= 0) + ret = ASN_PARSE_E; + } +#else if (ret > 0) { ret = 0; } else if (ret != 0) { WOLFSSL_MSG("DecodeRsaPssParams: fail at trailer_value"); } +#endif } } } From 904a70d179641e637d17ac0195610d9f1a0a0c49 Mon Sep 17 00:00:00 2001 From: Hideki Miyazaki Date: Thu, 4 Jun 2026 15:30:39 +0900 Subject: [PATCH 059/118] Addressed Copilot comments --- tests/api/test_random.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/api/test_random.c b/tests/api/test_random.c index 85ce701283..fc70df7cd4 100644 --- a/tests/api/test_random.c +++ b/tests/api/test_random.c @@ -757,7 +757,7 @@ int test_wc_Entropy_Get(void) /* 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(2049, entropy, sizeof(entropy)), + 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 */ From 26a2b793dc769b6151a47d49a40e2ab62f7e5b2a Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Thu, 4 Jun 2026 15:23:12 +1000 Subject: [PATCH 060/118] Regression testing fixes 1. Side-aware ML-KEM in TLS (tls.c, tls13.c, ssl.c, internal.h): TLSX_IsGroupSupported/TLSX_UseSupportedCurve take a `side` arg; new TLSX_IsMlKemGroupSupported + client/server support macros. A build only capable of one ML-KEM op no longer advertises groups it can't use for its role. 2. NO_ASN_TIME support (ssl_asn1.c, ssl.h, settings.h): data-only ASN1_TIME APIs now compile without system time; OCSP responder auto-disabled under NO_ASN_TIME. 3. SP ECC (sp_*.c, sp_x86_64_asm.asm): curve `b` constants and sp_ecc_is_point_* always compiled (point-check available in more configs); asm movsxd -> movsx. 4. configure.ac: BUILD_MEMUSE fixed to trigger on != "xno". 5. Test fixes: HRR-aware TLS 1.3 memio tests (new test_memio_msg_is_hello_retry_request); tightened build guards (Ed25519/Ed448 key-import, AES decrypt, XMSS heights, SP sizes, static-PSK). --- configure.ac | 2 +- src/ssl.c | 6 +- src/ssl_asn1.c | 21 +-- src/tls.c | 274 +++++++++++++++++++++------------- src/tls13.c | 2 +- tests/api.c | 7 +- tests/api/test_certman.c | 2 +- tests/api/test_evp_pkey.c | 9 +- tests/api/test_lms_xmss.c | 36 ++++- tests/api/test_mldsa_legacy.c | 13 -- tests/api/test_tls.c | 12 ++ tests/api/test_tls13.c | 55 ++++++- tests/api/test_x509.c | 2 +- tests/suites.c | 50 ++++++- tests/utils.c | 34 +++++ tests/utils.h | 1 + wolfcrypt/src/evp_pk.c | 26 ++-- wolfcrypt/src/sp_arm32.c | 17 +-- wolfcrypt/src/sp_arm64.c | 17 +-- wolfcrypt/src/sp_armthumb.c | 17 +-- wolfcrypt/src/sp_c32.c | 17 +-- wolfcrypt/src/sp_c64.c | 17 +-- wolfcrypt/src/sp_cortexm.c | 17 +-- wolfcrypt/src/sp_int.c | 3 +- wolfcrypt/src/sp_x86_64.c | 17 +-- wolfcrypt/test/test.c | 41 +++-- wolfssl/internal.h | 4 +- wolfssl/ssl.h | 63 +++++--- wolfssl/wolfcrypt/settings.h | 7 + 29 files changed, 506 insertions(+), 283 deletions(-) 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/src/ssl.c b/src/ssl.c index 4593496a52..5e4613b734 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -3294,7 +3294,8 @@ int wolfSSL_UseSupportedCurve(WOLFSSL* ssl, word16 name) #if defined(NO_TLS) return WOLFSSL_FAILURE; #else - return TLSX_UseSupportedCurve(&ssl->extensions, name, ssl->heap); + return TLSX_UseSupportedCurve(&ssl->extensions, name, ssl->heap, + ssl->options.side); #endif /* NO_TLS */ } @@ -3308,7 +3309,8 @@ int wolfSSL_CTX_UseSupportedCurve(WOLFSSL_CTX* ctx, word16 name) #if defined(NO_TLS) return WOLFSSL_FAILURE; #else - return TLSX_UseSupportedCurve(&ctx->extensions, name, ctx->heap); + return TLSX_UseSupportedCurve(&ctx->extensions, name, ctx->heap, + ctx->method->side); #endif /* NO_TLS */ } diff --git a/src/ssl_asn1.c b/src/ssl_asn1.c index 8dd158ef19..cbc0b94303 100644 --- a/src/ssl_asn1.c +++ b/src/ssl_asn1.c @@ -3760,8 +3760,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 +3809,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 +4004,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 +4048,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 +4070,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 +4114,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 +4129,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 +4203,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 +4232,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 +4612,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 +4652,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/tls.c b/src/tls.c index 62118d0678..5af3d672dc 100644 --- a/src/tls.c +++ b/src/tls.c @@ -4584,16 +4584,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: @@ -4705,14 +4761,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 @@ -4731,7 +4787,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 @@ -4743,14 +4799,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 @@ -4776,7 +4832,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: @@ -5144,7 +5200,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 && @@ -5533,7 +5590,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; } @@ -5936,7 +5994,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; } @@ -5945,7 +6006,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; @@ -5955,7 +6016,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; } @@ -7936,7 +7997,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 @@ -8595,7 +8657,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)) @@ -8732,7 +8795,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. * @@ -9052,7 +9116,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. @@ -9070,7 +9134,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)) @@ -11394,18 +11459,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)) && \ @@ -11499,7 +11564,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; @@ -11778,7 +11843,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); @@ -15602,14 +15667,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; } @@ -15617,39 +15683,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 @@ -15658,8 +15726,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 @@ -15668,7 +15736,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 */ @@ -15676,14 +15744,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 @@ -15693,9 +15761,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 @@ -15703,15 +15772,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 */ @@ -15719,14 +15788,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 @@ -15735,8 +15804,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 */ @@ -15744,9 +15813,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 @@ -15754,20 +15824,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 */ @@ -15775,20 +15845,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 @@ -15796,8 +15866,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 */ @@ -15805,13 +15875,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 @@ -15819,30 +15889,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 @@ -15854,8 +15924,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; } @@ -15863,8 +15933,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; } @@ -15872,8 +15942,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; } @@ -15881,8 +15951,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; } @@ -15890,8 +15960,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; } @@ -15900,35 +15970,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 } @@ -15936,58 +16007,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 diff --git a/src/tls13.c b/src/tls13.c index 8d7efb9df4..416c3334c2 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -14663,7 +14663,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; } diff --git a/tests/api.c b/tests/api.c index 54dd016512..f49bbaaab0 100644 --- a/tests/api.c +++ b/tests/api.c @@ -23505,7 +23505,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) { @@ -33276,7 +33276,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]; @@ -34534,7 +34535,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) && \ diff --git a/tests/api/test_certman.c b/tests/api/test_certman.c index 1c73e64a73..5a258f9129 100644 --- a/tests/api/test_certman.c +++ b/tests/api/test_certman.c @@ -3508,7 +3508,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_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..f99b1ed574 100644 --- a/tests/api/test_lms_xmss.c +++ b/tests/api/test_lms_xmss.c @@ -288,8 +288,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 +512,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 +562,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,6 +638,7 @@ static int rfc9802_xmss_import_negative(void) WC_NO_ERR_TRACE(BAD_STATE_E)); wc_XmssKey_Free(&key); } +#endif return EXPECT_RESULT(); } @@ -833,8 +837,10 @@ static int rfc9802_xmss_chain_verify(void) ExpectNotNull(cm = wolfSSL_CertManagerNew()); ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, caBuf, (long)caLen, WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); +#if !defined(WOLFSSL_XMSS_MIN_HEIGHT) || (WOLFSSL_XMSS_MIN_HEIGHT <= 10) ExpectIntEQ(wolfSSL_CertManagerVerifyBuffer(cm, leafBuf, (long)leafLen, WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); +#endif if (cm != NULL) { wolfSSL_CertManagerFree(cm); @@ -905,24 +911,50 @@ int test_rfc9802_xmss_x509_verify(void) EXPECT_DECLS; #if defined(WOLFSSL_HAVE_XMSS) #if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) +#if (!defined(WOLFSSL_XMSS_MIN_HEIGHT) || (WOLFSSL_XMSS_MIN_HEIGHT <= 16)) static const char* const xmssFiles[] = { +#if (!defined(WOLFSSL_XMSS_MAX_HEIGHT) || (WOLFSSL_XMSS_MAX_HEIGHT >= 10)) && \ + (!defined(WOLFSSL_XMSS_MIN_HEIGHT) || (WOLFSSL_XMSS_MIN_HEIGHT <= 10)) "./certs/xmss/bc_xmss_sha2_10_256_root.der", +#endif +#if (!defined(WOLFSSL_XMSS_MAX_HEIGHT) || (WOLFSSL_XMSS_MAX_HEIGHT >= 16)) && \ + (!defined(WOLFSSL_XMSS_MIN_HEIGHT) || (WOLFSSL_XMSS_MIN_HEIGHT <= 16)) "./certs/xmss/bc_xmss_sha2_16_256_root.der", +#endif }; +#endif +#if (!defined(WOLFSSL_XMSS_MAX_HEIGHT) || (WOLFSSL_XMSS_MAX_HEIGHT >= 20)) && \ + (!defined(WOLFSSL_XMSS_MIN_HEIGHT) || (WOLFSSL_XMSS_MIN_HEIGHT <= 40)) static const char* const xmssmtFiles[] = { +#if (!defined(WOLFSSL_XMSS_MAX_HEIGHT) || (WOLFSSL_XMSS_MAX_HEIGHT >= 20)) && \ + (!defined(WOLFSSL_XMSS_MIN_HEIGHT) || (WOLFSSL_XMSS_MIN_HEIGHT <= 20)) "./certs/xmss/bc_xmssmt_sha2_20_2_256_root.der", "./certs/xmss/bc_xmssmt_sha2_20_4_256_root.der", +#endif +#if (!defined(WOLFSSL_XMSS_MAX_HEIGHT) || (WOLFSSL_XMSS_MAX_HEIGHT >= 40)) && \ + (!defined(WOLFSSL_XMSS_MIN_HEIGHT) || (WOLFSSL_XMSS_MIN_HEIGHT <= 40)) "./certs/xmss/bc_xmssmt_sha2_40_8_256_root.der", +#endif }; +#endif +#if (!defined(WOLFSSL_XMSS_MIN_HEIGHT) || (WOLFSSL_XMSS_MIN_HEIGHT <= 16)) || \ + ((!defined(WOLFSSL_XMSS_MAX_HEIGHT) || (WOLFSSL_XMSS_MAX_HEIGHT >= 20)) && \ + (!defined(WOLFSSL_XMSS_MIN_HEIGHT) || (WOLFSSL_XMSS_MIN_HEIGHT <= 40))) size_t i; +#endif +#if (!defined(WOLFSSL_XMSS_MIN_HEIGHT) || (WOLFSSL_XMSS_MIN_HEIGHT <= 16)) for (i = 0; i < sizeof(xmssFiles) / sizeof(xmssFiles[0]); i++) { ExpectIntEQ(rfc9802_verify_one_cert(xmssFiles[i], XMSSk, CTC_XMSS), TEST_SUCCESS); } +#endif +#if (!defined(WOLFSSL_XMSS_MAX_HEIGHT) || (WOLFSSL_XMSS_MAX_HEIGHT >= 20)) && \ + (!defined(WOLFSSL_XMSS_MIN_HEIGHT) || (WOLFSSL_XMSS_MIN_HEIGHT <= 40)) for (i = 0; i < sizeof(xmssmtFiles) / sizeof(xmssmtFiles[0]); i++) { ExpectIntEQ(rfc9802_verify_one_cert(xmssmtFiles[i], XMSSMTk, CTC_XMSSMT), TEST_SUCCESS); } +#endif ExpectIntEQ(rfc9802_xmss_sig_oid_mismatch(), TEST_SUCCESS); ExpectIntEQ(rfc9802_xmss_chain_verify(), TEST_SUCCESS); #endif /* !NO_FILESYSTEM && !NO_CERTS */ 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_tls.c b/tests/api/test_tls.c index ee2e112bfa..f614392144 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); diff --git a/tests/api/test_tls13.c b/tests/api/test_tls13.c index ca37fb48cc..fcda2298c2 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 @@ -5348,6 +5351,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 +5369,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 +5474,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 +6129,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_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/utils.c b/tests/utils.c index a6d37b89d5..f2bf4a06fa 100644 --- a/tests/utils.c +++ b/tests/utils.c @@ -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) { diff --git a/tests/utils.h b/tests/utils.h index bd9a150e01..624a4b4aa6 100644 --- a/tests/utils.h +++ b/tests/utils.h @@ -80,6 +80,7 @@ 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); diff --git a/wolfcrypt/src/evp_pk.c b/wolfcrypt/src/evp_pk.c index 9ef4d459bd..7c9f25539c 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; @@ -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) { diff --git a/wolfcrypt/src/sp_arm32.c b/wolfcrypt/src/sp_arm32.c index dd10cc64ad..e9e5098af5 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) @@ -80782,7 +80779,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 +80851,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 +81279,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) @@ -99065,7 +99059,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 +99131,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 +99601,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) @@ -128007,7 +127998,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 +128070,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. * @@ -158404,7 +158395,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 +158518,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..2045db37fc 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) @@ -41481,7 +41478,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 +41594,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 +42021,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) @@ -67158,7 +67152,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 +67224,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 +67690,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) @@ -111666,7 +111657,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 +111729,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. * @@ -123425,7 +123416,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 +123605,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..77ab6cafa1 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) * @@ -107292,7 +107289,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 +107361,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 +107789,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) * @@ -118083,7 +118077,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 +118149,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 +118619,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) * @@ -134651,7 +134642,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 +134714,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. * @@ -217058,7 +217049,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 +217172,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..6cc1a147a3 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) @@ -26531,7 +26528,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 +26600,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 +27036,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) @@ -34176,7 +34170,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 +34242,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 +34715,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) @@ -41927,7 +41918,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 +41990,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. * @@ -53422,7 +53413,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 +53524,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..65d610d05c 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) @@ -27146,7 +27143,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 +27215,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 +27640,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) @@ -34178,7 +34172,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 +34244,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 +34708,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) @@ -41239,7 +41230,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 +41302,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. * @@ -51727,7 +51718,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 +51829,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..d541e08911 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) @@ -42288,7 +42285,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 +42357,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 +42785,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) @@ -52395,7 +52389,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 +52461,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 +52931,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) @@ -65811,7 +65802,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 +65874,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. * @@ -82141,7 +82132,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 +82255,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..0ead549d16 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" { @@ -25637,7 +25634,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 +25706,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 +26237,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" { @@ -50181,7 +50175,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 +50247,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 +50842,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" { @@ -90927,7 +90918,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 +90990,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. * @@ -103475,7 +103466,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 +103578,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/test/test.c b/wolfcrypt/test/test.c index cd3275650b..d9f62a7337 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -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[] = { @@ -17562,10 +17565,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 +17592,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 +17635,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 +19064,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 +19314,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 +19414,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 +19794,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 +19843,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 +19854,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 +19903,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 +19945,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 +19957,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 +20199,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 +20978,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)]; @@ -52097,7 +52115,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 +52304,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); diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 794808f38b..a918ae2bde 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -3462,11 +3462,11 @@ 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, 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, diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 2281bb2f26..11350afd18 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -2545,13 +2545,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 +2598,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); @@ -3369,15 +3404,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 +6117,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/settings.h b/wolfssl/wolfcrypt/settings.h index e7d9b568f6..4ec84fb170 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -5248,6 +5248,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" From 40a6a04d231791bc2ee3c5121ae6babe4bfa3760 Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Tue, 2 Jun 2026 09:05:04 +0200 Subject: [PATCH 061/118] fix: restore SHA-512 variant IV after generic fallback After the SHA-512/224 and /256 fallback to the generic SHA-512 callback, restore the variant initial state so the object is reset for reuse, and exercise the path in cryptocb_test. --- wolfcrypt/src/cryptocb.c | 48 +++++++++++++++++++++++++++++++++++- wolfcrypt/test/test.c | 12 +++++++++ wolfssl/wolfcrypt/settings.h | 13 ++++++++++ 3 files changed, 72 insertions(+), 1 deletion(-) diff --git a/wolfcrypt/src/cryptocb.c b/wolfcrypt/src/cryptocb.c index c3af7ed608..8215e2fe31 100644 --- a/wolfcrypt/src/cryptocb.c +++ b/wolfcrypt/src/cryptocb.c @@ -50,6 +50,15 @@ 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 @@ -2061,7 +2070,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 +2089,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 +2101,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 (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 (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/test/test.c b/wolfcrypt/test/test.c index f3fc88c8a1..45ec4c4b15 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -74443,6 +74443,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/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index 0fb49e9351..3247bb9298 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 From 76962339c4f3f1e6af608d2d0b9612a431106083 Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Tue, 2 Jun 2026 15:28:32 +0200 Subject: [PATCH 062/118] cryptocb: fallback to sha512 if no sha384 cryptocb handler --- wolfcrypt/src/cryptocb.c | 42 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/wolfcrypt/src/cryptocb.c b/wolfcrypt/src/cryptocb.c index 8215e2fe31..c2cb707f3f 100644 --- a/wolfcrypt/src/cryptocb.c +++ b/wolfcrypt/src/cryptocb.c @@ -2024,16 +2024,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); From 5744df1c77bdfda62a81c63236e2d20d75d2e643 Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Wed, 3 Jun 2026 15:57:23 +0200 Subject: [PATCH 063/118] test: add sha512 variants by sha512 general fallback test --- tests/api/test_sha512.c | 184 ++++++++++++++++++++++++++++++++++++++++ tests/api/test_sha512.h | 4 +- 2 files changed, 187 insertions(+), 1 deletion(-) diff --git a/tests/api/test_sha512.c b/tests/api/test_sha512.c index 419fb60b31..85ed2ab328 100644 --- a/tests/api/test_sha512.c +++ b/tests/api/test_sha512.c @@ -874,3 +874,187 @@ 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(); +} + diff --git a/tests/api/test_sha512.h b/tests/api/test_sha512.h index 48882c4daa..4d584b824a 100644 --- a/tests/api/test_sha512.h +++ b/tests/api/test_sha512.h @@ -66,6 +66,7 @@ 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); #define TEST_SHA512_DECLS \ TEST_DECL_GROUP("sha512", test_wc_InitSha512), \ @@ -77,7 +78,8 @@ 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) #define TEST_SHA512_224_DECLS \ TEST_DECL_GROUP("sha512_224", test_wc_InitSha512_224), \ From b01382c13b3554ab1fedab0a92f69299feda5b45 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Thu, 4 Jun 2026 09:26:43 -0400 Subject: [PATCH 064/118] Add unit tests that TLS resumption fails due to ALPN mismatch Fix F-4141 --- tests/api/test_tls.c | 153 +++++++++++++++++++++++++++++++++++++++++++ tests/api/test_tls.h | 4 ++ 2 files changed, 157 insertions(+) diff --git a/tests/api/test_tls.c b/tests/api/test_tls.c index 4abf2b6206..970b98e47d 100644 --- a/tests/api/test_tls.c +++ b/tests/api/test_tls.c @@ -1128,6 +1128,159 @@ int test_tls13_resumption_with_alpn(void) 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; diff --git a/tests/api/test_tls.h b/tests/api/test_tls.h index 4b4f5385c3..d883a05135 100644 --- a/tests/api/test_tls.h +++ b/tests/api/test_tls.h @@ -36,6 +36,8 @@ 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); @@ -57,6 +59,8 @@ int test_wolfSSL_alert_desc_string(void); 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), \ From 27edd641187529f6e6e0ae643564a36aa9bcb704 Mon Sep 17 00:00:00 2001 From: jordan Date: Thu, 4 Jun 2026 11:42:43 -0500 Subject: [PATCH 065/118] bsdkm: call wolfkdriv_unregister before wolfkmod_cleanup, and misc cleanup. --- bsdkm/wolfkmod.c | 4 ++-- bsdkm/x86_vecreg.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bsdkm/wolfkmod.c b/bsdkm/wolfkmod.c index 8767f46cb7..6e19995ca7 100644 --- a/bsdkm/wolfkmod.c +++ b/bsdkm/wolfkmod.c @@ -492,8 +492,8 @@ static int wolfkdriv_attach(device_t dev) attach_out: if (error) { device_printf(dev, "error: attach_out: %d\n", error); - (void)wolfkmod_cleanup(); wolfkdriv_unregister(softc); + (void)wolfkmod_cleanup(); } return (error); @@ -506,8 +506,8 @@ static int wolfkdriv_detach(device_t dev) /* unregister wolfcrypt algs */ softc = device_get_softc(dev); - ret = wolfkmod_cleanup(); wolfkdriv_unregister(softc); + ret = wolfkmod_cleanup(); #if defined(WOLFSSL_BSDKM_VERBOSE_DEBUG) device_printf(dev, "info: exiting detach: %d\n", ret); #else diff --git a/bsdkm/x86_vecreg.c b/bsdkm/x86_vecreg.c index d621cee599..48f0df7b47 100644 --- a/bsdkm/x86_vecreg.c +++ b/bsdkm/x86_vecreg.c @@ -140,7 +140,7 @@ int wolfkmod_vecreg_save(int flags_unused) #endif if (fpu_states == NULL) { - printf("info : wolfkmod_vecreg_save: fpu_states null\n"); + printf("error: wolfkmod_vecreg_save: fpu_states null\n"); return (EINVAL); } @@ -195,7 +195,7 @@ void wolfkmod_vecreg_restore(void) #endif if (fpu_states == NULL) { - printf("info: wolfkmod_vecreg_restore: fpu_states null\n"); + printf("error: wolfkmod_vecreg_restore: fpu_states null\n"); return; } From 368e1486f6c141edae2d39a57741117539890f62 Mon Sep 17 00:00:00 2001 From: Colton Willey Date: Thu, 4 Jun 2026 10:31:32 -0700 Subject: [PATCH 066/118] Harden X509 DER length handling in wolfSSL_X509_get_der and wolfSSL_i2d_X509 - src/x509.c: Guard wolfSSL_X509_get_der against derCert->length > INT_MAX, and reject derSz <= 0 in wolfSSL_i2d_X509. - tests/api/test_ossl_x509_io.{c,h}: Add API coverage for the X509 DER length guards. --- src/x509.c | 6 +++- tests/api/test_ossl_x509_io.c | 62 ++++++++++++++++++++++++++++++++++- tests/api/test_ossl_x509_io.h | 6 ++++ 3 files changed, 72 insertions(+), 2 deletions(-) diff --git a/src/x509.c b/src/x509.c index 11b74af7fd..88aa2b0f33 100644 --- a/src/x509.c +++ b/src/x509.c @@ -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; } @@ -8835,7 +8839,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; } 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) From 0314b3fed2dd0a4ce1324ddd985017605a2fd1de Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Wed, 20 May 2026 22:01:34 +0200 Subject: [PATCH 067/118] cryptocb: support WOLF_CRYPTO_CB_ONLY_SHA512 --- .github/workflows/cryptocb-only.yml | 16 +- .wolfssl_known_macro_extras | 2 + src/ssl_crypto.c | 9 +- tests/api.c | 6 +- tests/api/test_sha512.c | 97 +++++ tests/api/test_sha512.h | 6 +- tests/swdev/swdev.c | 194 ++++++++- tests/swdev/user_settings.h | 1 + wolfcrypt/src/cryptocb.c | 5 +- wolfcrypt/src/sha512.c | 586 ++++++++++++++++++++++++++++ wolfcrypt/test/test.c | 18 + wolfssl/openssl/sha.h | 12 + wolfssl/wolfcrypt/settings.h | 6 + wolfssl/wolfcrypt/sha512.h | 23 +- 14 files changed, 968 insertions(+), 13 deletions(-) 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/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index fb34d7c6f2..d64831361e 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -966,6 +966,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 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/tests/api.c b/tests/api.c index a2873fd747..4cf30afcff 100644 --- a/tests/api.c +++ b/tests/api.c @@ -27527,7 +27527,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) @@ -28531,7 +28532,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 diff --git a/tests/api/test_sha512.c b/tests/api/test_sha512.c index 85ed2ab328..eb5a31c8f5 100644 --- a/tests/api/test_sha512.c +++ b/tests/api/test_sha512.c @@ -1058,3 +1058,100 @@ int test_wc_sha512_cryptocb_fallback(void) 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 4d584b824a..3347424455 100644 --- a/tests/api/test_sha512.h +++ b/tests/api/test_sha512.h @@ -67,6 +67,8 @@ 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), \ @@ -79,7 +81,9 @@ int test_wc_sha512_cryptocb_fallback(void); 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_cryptocb_fallback) + 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/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/wolfcrypt/src/cryptocb.c b/wolfcrypt/src/cryptocb.c index c2cb707f3f..ce41423166 100644 --- a/wolfcrypt/src/cryptocb.c +++ b/wolfcrypt/src/cryptocb.c @@ -62,6 +62,7 @@ Crypto Callback Build Options: * 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 */ @@ -2154,7 +2155,7 @@ int wc_CryptoCb_Sha512Hash(wc_Sha512* sha512, const byte* in, if (ret == 0 && digest != NULL && digestSz != WC_SHA512_DIGEST_SIZE) { XMEMCPY(digest, localHash, digestSz); #if !defined(WOLFSSL_NOSHA512_224) - if (digestSz == WC_SHA512_224_DIGEST_SIZE) { + if (sha512 != NULL && digestSz == WC_SHA512_224_DIGEST_SIZE) { sha512->digest[0] = W64LIT(0x8c3d37c819544da2); sha512->digest[1] = W64LIT(0x73e1996689dcd4d6); sha512->digest[2] = W64LIT(0x1dfab7ae32ff9c82); @@ -2166,7 +2167,7 @@ int wc_CryptoCb_Sha512Hash(wc_Sha512* sha512, const byte* in, } #endif #if !defined(WOLFSSL_NOSHA512_256) - if (digestSz == WC_SHA512_256_DIGEST_SIZE) { + if (sha512 != NULL && digestSz == WC_SHA512_256_DIGEST_SIZE) { sha512->digest[0] = W64LIT(0x22312194fc2bf72c); sha512->digest[1] = W64LIT(0x9f555fa3c84c64c2); sha512->digest[2] = W64LIT(0x2393b86b6f53b151); 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/test/test.c b/wolfcrypt/test/test.c index 45ec4c4b15..8858601d32 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -73231,6 +73231,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( @@ -73260,6 +73269,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( 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/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index 3247bb9298..e34116c358 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -5224,6 +5224,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 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); From 6291af4e8838e5572d9fa2e5814b2393286652df Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Thu, 4 Jun 2026 20:59:29 +0200 Subject: [PATCH 068/118] Add WOLFSSL_MAX3266X_SHA_ONESHOT to go to previous behavior --- wolfcrypt/src/port/maxim/max3266x.c | 727 +++++++++++++++++++++++- wolfssl/wolfcrypt/port/maxim/max3266x.h | 110 ++++ 2 files changed, 835 insertions(+), 2 deletions(-) diff --git a/wolfcrypt/src/port/maxim/max3266x.c b/wolfcrypt/src/port/maxim/max3266x.c index 494999f100..06c6b8c7e9 100644 --- a/wolfcrypt/src/port/maxim/max3266x.c +++ b/wolfcrypt/src/port/maxim/max3266x.c @@ -136,6 +136,77 @@ 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, + byte* digest, MXC_TPU_HASH_TYPE algo) +{ + if (in != NULL && digest == NULL) { + MAX3266X_MSG("Update CB"); + return _wc_Hash_Grow(msg, used, len, in, (int)inSz, heap); + } + if (in == NULL && digest != NULL) { + MAX3266X_MSG("Final CB"); + return wc_MXC_TPU_SHA_Final(msg, used, len, heap, digest, algo); + } + if (inSz == 0) { + return 0; /* Don't need to Update when Size is Zero */ + } + return BAD_FUNC_ARG; +} + +int wc_MxcShaCryptoCb(wc_CryptoInfo* info) +{ + switch (info->hash.type) { + #ifndef NO_SHA + case WC_HASH_TYPE_SHA: + return wc_MxcShaCbDispatch(&info->hash.sha1->msg, + &info->hash.sha1->used, &info->hash.sha1->len, + info->hash.sha1->heap, info->hash.in, + info->hash.inSz, info->hash.digest, + MXC_TPU_HASH_SHA1); + #endif + #ifdef WOLFSSL_SHA224 + case WC_HASH_TYPE_SHA224: + return wc_MxcShaCbDispatch(&info->hash.sha224->msg, + &info->hash.sha224->used, &info->hash.sha224->len, + info->hash.sha224->heap, info->hash.in, + info->hash.inSz, info->hash.digest, + MXC_TPU_HASH_SHA224); + #endif + #ifndef NO_SHA256 + case WC_HASH_TYPE_SHA256: + return wc_MxcShaCbDispatch(&info->hash.sha256->msg, + &info->hash.sha256->used, &info->hash.sha256->len, + info->hash.sha256->heap, info->hash.in, + info->hash.inSz, info->hash.digest, + MXC_TPU_HASH_SHA256); + #endif + #ifdef WOLFSSL_SHA384 + case WC_HASH_TYPE_SHA384: + return wc_MxcShaCbDispatch(&info->hash.sha384->msg, + &info->hash.sha384->used, &info->hash.sha384->len, + info->hash.sha384->heap, info->hash.in, + info->hash.inSz, info->hash.digest, + MXC_TPU_HASH_SHA384); + #endif + #ifdef WOLFSSL_SHA512 + case WC_HASH_TYPE_SHA512: + return wc_MxcShaCbDispatch(&info->hash.sha512->msg, + &info->hash.sha512->used, &info->hash.sha512->len, + info->hash.sha512->heap, info->hash.in, + info->hash.inSz, info->hash.digest, + MXC_TPU_HASH_SHA512); + #endif + default: + 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, @@ -271,9 +342,76 @@ int wc_MxcShaCryptoCb(wc_CryptoInfo* info) 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) { + return BAD_FUNC_ARG; + } + + switch (info->copy.type) { +#ifdef MAX3266X_SHA_CB + #ifndef NO_SHA + case WC_HASH_TYPE_SHA: + return wc_MXC_TPU_SHA_Copy(info->copy.src, info->copy.dst, + sizeof(wc_Sha), + &((wc_Sha*)info->copy.dst)->msg, + &((wc_Sha*)info->copy.dst)->used, + &((wc_Sha*)info->copy.dst)->len, + ((wc_Sha*)info->copy.dst)->heap, + ((wc_Sha*)info->copy.src)->heap); + #endif + #ifdef WOLFSSL_SHA224 + case WC_HASH_TYPE_SHA224: + return wc_MXC_TPU_SHA_Copy(info->copy.src, info->copy.dst, + sizeof(wc_Sha224), + &((wc_Sha224*)info->copy.dst)->msg, + &((wc_Sha224*)info->copy.dst)->used, + &((wc_Sha224*)info->copy.dst)->len, + ((wc_Sha224*)info->copy.dst)->heap, + ((wc_Sha224*)info->copy.src)->heap); + #endif + #ifndef NO_SHA256 + case WC_HASH_TYPE_SHA256: + return wc_MXC_TPU_SHA_Copy(info->copy.src, info->copy.dst, + sizeof(wc_Sha256), + &((wc_Sha256*)info->copy.dst)->msg, + &((wc_Sha256*)info->copy.dst)->used, + &((wc_Sha256*)info->copy.dst)->len, + ((wc_Sha256*)info->copy.dst)->heap, + ((wc_Sha256*)info->copy.src)->heap); + #endif + #ifdef WOLFSSL_SHA384 + case WC_HASH_TYPE_SHA384: + return wc_MXC_TPU_SHA_Copy(info->copy.src, info->copy.dst, + sizeof(wc_Sha384), + &((wc_Sha384*)info->copy.dst)->msg, + &((wc_Sha384*)info->copy.dst)->used, + &((wc_Sha384*)info->copy.dst)->len, + ((wc_Sha384*)info->copy.dst)->heap, + ((wc_Sha384*)info->copy.src)->heap); + #endif + #ifdef WOLFSSL_SHA512 + case WC_HASH_TYPE_SHA512: + return wc_MXC_TPU_SHA_Copy(info->copy.src, info->copy.dst, + sizeof(wc_Sha512), + &((wc_Sha512*)info->copy.dst)->msg, + &((wc_Sha512*)info->copy.dst)->used, + &((wc_Sha512*)info->copy.dst)->len, + ((wc_Sha512*)info->copy.dst)->heap, + ((wc_Sha512*)info->copy.src)->heap); + #endif +#endif /* MAX3266X_SHA_CB */ + default: + return WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + } +} +#else /* WOLFSSL_MAX3266X_SHA_ONESHOT */ static int wc_MxcCopyCb(wc_CryptoInfo* info) { word32 sz; @@ -321,8 +459,70 @@ static int wc_MxcCopyCb(wc_CryptoInfo* info) 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 +static int wc_MxcFreeCb(wc_CryptoInfo* info) +{ + if (info == NULL || info->free.obj == NULL) { + return BAD_FUNC_ARG; + } + + switch (info->free.type) { +#ifdef MAX3266X_SHA_CB + #ifndef NO_SHA + case WC_HASH_TYPE_SHA: + wc_MXC_TPU_SHA_FreeCtx(info->free.obj, sizeof(wc_Sha), + &((wc_Sha*)info->free.obj)->msg, + &((wc_Sha*)info->free.obj)->used, + &((wc_Sha*)info->free.obj)->len, + ((wc_Sha*)info->free.obj)->heap); + return 0; + #endif + #ifdef WOLFSSL_SHA224 + case WC_HASH_TYPE_SHA224: + wc_MXC_TPU_SHA_FreeCtx(info->free.obj, sizeof(wc_Sha224), + &((wc_Sha224*)info->free.obj)->msg, + &((wc_Sha224*)info->free.obj)->used, + &((wc_Sha224*)info->free.obj)->len, + ((wc_Sha224*)info->free.obj)->heap); + return 0; + #endif + #ifndef NO_SHA256 + case WC_HASH_TYPE_SHA256: + wc_MXC_TPU_SHA_FreeCtx(info->free.obj, sizeof(wc_Sha256), + &((wc_Sha256*)info->free.obj)->msg, + &((wc_Sha256*)info->free.obj)->used, + &((wc_Sha256*)info->free.obj)->len, + ((wc_Sha256*)info->free.obj)->heap); + return 0; + #endif + #ifdef WOLFSSL_SHA384 + case WC_HASH_TYPE_SHA384: + wc_MXC_TPU_SHA_FreeCtx(info->free.obj, sizeof(wc_Sha384), + &((wc_Sha384*)info->free.obj)->msg, + &((wc_Sha384*)info->free.obj)->used, + &((wc_Sha384*)info->free.obj)->len, + ((wc_Sha384*)info->free.obj)->heap); + return 0; + #endif + #ifdef WOLFSSL_SHA512 + case WC_HASH_TYPE_SHA512: + wc_MXC_TPU_SHA_FreeCtx(info->free.obj, sizeof(wc_Sha512), + &((wc_Sha512*)info->free.obj)->msg, + &((wc_Sha512*)info->free.obj)->used, + &((wc_Sha512*)info->free.obj)->len, + ((wc_Sha512*)info->free.obj)->heap); + return 0; + #endif +#endif /* MAX3266X_SHA_CB */ + default: + return WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + } +} +#endif /* WOLF_CRYPTO_CB_FREE */ + /* General Callback Function to determine ALGO Type */ int wc_MxcCryptoCb(int devIdArg, wc_CryptoInfo* info, void* ctx) { @@ -355,8 +555,12 @@ int wc_MxcCryptoCb(int devIdArg, wc_CryptoInfo* info, void* ctx) ret = wc_MxcCopyCb(info); break; #endif /* WOLF_CRYPTO_CB_COPY */ - /* No WC_ALGO_TYPE_FREE needed: SHA contexts have no heap - * allocations to clean up. */ +#ifdef WOLF_CRYPTO_CB_FREE + case WC_ALGO_TYPE_FREE: + MAX3266X_MSG("Using MXC Free Callback:"); + ret = wc_MxcFreeCb(info); + break; +#endif /* WOLF_CRYPTO_CB_FREE */ default: MAX3266X_MSG("Callback not supported with MXC, using SW"); /* return this to bypass HW and use SW */ @@ -679,6 +883,172 @@ 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, + unsigned char* digest, + MXC_TPU_HASH_TYPE algo) +{ + if (digest == NULL) { + return BAD_FUNC_ARG; + } + if (msg == NULL && msgSz == 0) { + switch (algo) { + #ifndef NO_SHA + case MXC_TPU_HASH_SHA1: + XMEMCPY(digest, MXC_EMPTY_DIGEST_SHA1, WC_SHA_DIGEST_SIZE); + break; + #endif /* NO_SHA */ + #ifdef WOLFSSL_SHA224 + case MXC_TPU_HASH_SHA224: + XMEMCPY(digest, MXC_EMPTY_DIGEST_SHA224, WC_SHA224_DIGEST_SIZE); + break; + #endif /* WOLFSSL_SHA224 */ + #ifndef NO_SHA256 + case MXC_TPU_HASH_SHA256: + XMEMCPY(digest, MXC_EMPTY_DIGEST_SHA256, WC_SHA256_DIGEST_SIZE); + break; + #endif /* NO_SHA256 */ + #ifdef WOLFSSL_SHA384 + case MXC_TPU_HASH_SHA384: + XMEMCPY(digest, MXC_EMPTY_DIGEST_SHA384, WC_SHA384_DIGEST_SIZE); + break; + #endif /* WOLFSSL_SHA384 */ + #ifdef WOLFSSL_SHA512 + case MXC_TPU_HASH_SHA512: + XMEMCPY(digest, MXC_EMPTY_DIGEST_SHA512, WC_SHA512_DIGEST_SIZE); + break; + #endif /* WOLFSSL_SHA512 */ + default: + return BAD_FUNC_ARG; + } + return 1; /* True: empty digest provided */ + } + return 0; /* False: needs hardware processing */ +} + +/* Compute hash from accumulated message using TPU hardware */ +int wc_MXC_TPU_SHA_GetHash(const unsigned char* msg, unsigned int msgSz, + unsigned char* digest, + MXC_TPU_HASH_TYPE algo) +{ + int status; + if (digest == NULL || (msg == NULL && msgSz != 0)) { + return BAD_FUNC_ARG; + } + status = wc_MXC_TPU_SHA_GetDigest(msg, msgSz, digest, algo); + /* True Case that msg is an empty string */ + if (status == 1) { + /* Hardware cannot handle the case of an empty string */ + /* so in the case of this we will provide the hash via software */ + return 0; + } + /* False Case where msg needs to be processed */ + else if (status == 0) { + status = wolfSSL_HwHashMutexLock(); /* Set Mutex */ + if (status != 0) { /* Mutex Call Check */ + return status; + } + MXC_TPU_Init(MXC_SYS_PERIPH_CLOCK_TPU); + MXC_TPU_Hash_Config(algo); + status = MXC_TPU_Hash_SHA((const char *)msg, algo, msgSz, + (char *)digest); + MAX3266X_MSG("SHA HW Acceleration Used"); + wolfSSL_HwHashMutexUnLock(); /* Release Mutex */ + if (wc_MXC_error(&status) != 0) { + MAX3266X_MSG("SHA HW Error Occurred"); + return status; + } + } + /* Error Occurred */ + return status; +} + +/* Free HASH_KEEP message buffer and reset fields */ +void wc_MXC_TPU_SHA_Free(byte** msg, word32* used, word32* len, void* heap) +{ + if (msg == NULL) { + return; + } + if (*msg != NULL) { + XFREE(*msg, heap, DYNAMIC_TYPE_TMP_BUFFER); + *msg = NULL; + } + if (used != NULL) { + *used = 0; + } + if (len != NULL) { + *len = 0; + } +} + +/* Free HASH_KEEP message buffer and zero the full SHA context struct */ +void wc_MXC_TPU_SHA_FreeCtx(void* ctx, word32 ctxSz, byte** msg, word32* used, + word32* len, void* heap) +{ + if (ctx == NULL) { + return; + } + wc_MXC_TPU_SHA_Free(msg, used, len, heap); + XMEMSET(ctx, 0, ctxSz); +} + +/* Copy SHA context struct and deep copy the HASH_KEEP message buffer. + * Frees any existing dst msg buffer to prevent memory leaks when copying + * into an already-used context. */ +int wc_MXC_TPU_SHA_Copy(void* src, void* dst, word32 ctxSz, + byte** dstMsg, word32* dstUsed, word32* dstLen, + void* dstHeap, void* srcHeap) +{ + byte* srcBuf = NULL; + + if (src == NULL || dst == NULL || dstMsg == NULL || + dstUsed == NULL || dstLen == NULL || ctxSz == 0) { + return BAD_FUNC_ARG; + } + + /* Free existing dst msg buffer using dst's original heap */ + wc_MXC_TPU_SHA_Free(dstMsg, dstUsed, dstLen, dstHeap); + + /* Shallow copy the full context struct */ + XMEMCPY(dst, src, ctxSz); + + /* Deep copy src msg buffer if present. Since dstMsg points into the dst + * struct, the XMEMCPY above overwrites it with the src's msg pointer. + * Save that pointer, allocate a new buffer for dst, and copy the data. + * Do NOT move srcBuf assignment before XMEMCPY - it must capture the + * src msg pointer that lands in *dstMsg after the shallow copy. */ + if (*dstMsg != NULL) { + srcBuf = *dstMsg; + *dstMsg = (byte*)XMALLOC(*dstLen, srcHeap, DYNAMIC_TYPE_TMP_BUFFER); + if (*dstMsg == NULL) { + return MEMORY_E; + } + XMEMCPY(*dstMsg, srcBuf, *dstUsed); + } + + return 0; +} + +/* Compute hash, free message buffer, and reset HASH_KEEP fields */ +int wc_MXC_TPU_SHA_Final(unsigned char** msg, unsigned int* used, + unsigned int* len, void* heap, + unsigned char* digest, + MXC_TPU_HASH_TYPE algo) +{ + int status; + if (msg == NULL || used == NULL || len == NULL || digest == NULL) { + return BAD_FUNC_ARG; + } + status = wc_MXC_TPU_SHA_GetHash(*msg, *used, digest, algo); + wc_MXC_TPU_SHA_Free(msg, used, len, heap); + return status; +} + +#else /* WOLFSSL_MAX3266X_SHA_ONESHOT */ + /* TPU hash helpers (bare-metal SHA accelerator) */ /* Reset TPU, select hash function, and restore intermediate state into @@ -948,9 +1318,360 @@ static int wc_MXC_TPU_SHA_Init(unsigned int* digest, int stateWords, 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) +{ + if (sha == NULL) { + return BAD_FUNC_ARG; + } + (void)devId; + XMEMSET(sha, 0, sizeof(*sha)); + sha->heap = heap; + return 0; +} + +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_Hash_Grow(&sha->msg, &sha->used, &sha->len, + data, (int)len, sha->heap); +} + +WOLFSSL_API int wc_ShaFinal(wc_Sha* sha, unsigned char* hash) +{ + if (sha == NULL || hash == NULL) { + return BAD_FUNC_ARG; + } + return wc_MXC_TPU_SHA_Final(&sha->msg, &sha->used, &sha->len, + sha->heap, hash, MXC_TPU_HASH_SHA1); +} + +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((const unsigned char*)sha->msg, + sha->used, hash, MXC_TPU_HASH_SHA1); +} + +WOLFSSL_API int wc_ShaCopy(wc_Sha* src, wc_Sha* dst) +{ + if (src == NULL || dst == NULL) { + return BAD_FUNC_ARG; + } + return wc_MXC_TPU_SHA_Copy(src, dst, sizeof(wc_Sha), + &dst->msg, &dst->used, &dst->len, + dst->heap, src->heap); +} + +WOLFSSL_API void wc_ShaFree(wc_Sha* sha) +{ + if (sha == NULL) { + return; + } + wc_MXC_TPU_SHA_FreeCtx(sha, sizeof(wc_Sha), &sha->msg, &sha->used, + &sha->len, sha->heap); +} + +#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 0; +} + +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_Hash_Grow(&sha224->msg, &sha224->used, &sha224->len, + data, (int)len, sha224->heap); +} + +WOLFSSL_API int wc_Sha224Final(wc_Sha224* sha224, unsigned char* hash) +{ + if (sha224 == NULL || hash == NULL) { + return BAD_FUNC_ARG; + } + return wc_MXC_TPU_SHA_Final(&sha224->msg, &sha224->used, &sha224->len, + sha224->heap, hash, + MXC_TPU_HASH_SHA224); +} + +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((const unsigned char*)sha224->msg, + sha224->used, hash, + MXC_TPU_HASH_SHA224); +} + +WOLFSSL_API int wc_Sha224Copy(wc_Sha224* src, wc_Sha224* dst) +{ + if (src == NULL || dst == NULL) { + return BAD_FUNC_ARG; + } + return wc_MXC_TPU_SHA_Copy(src, dst, sizeof(wc_Sha224), + &dst->msg, &dst->used, &dst->len, + dst->heap, src->heap); +} + +WOLFSSL_API void wc_Sha224Free(wc_Sha224* sha224) +{ + if (sha224 == NULL) { + return; + } + wc_MXC_TPU_SHA_FreeCtx(sha224, sizeof(wc_Sha224), &sha224->msg, + &sha224->used, &sha224->len, + sha224->heap); +} + +#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 0; +} + +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_Hash_Grow(&sha256->msg, &sha256->used, &sha256->len, + data, (int)len, sha256->heap); +} + +WOLFSSL_API int wc_Sha256Final(wc_Sha256* sha256, unsigned char* hash) +{ + if (sha256 == NULL || hash == NULL) { + return BAD_FUNC_ARG; + } + return wc_MXC_TPU_SHA_Final(&sha256->msg, &sha256->used, &sha256->len, + sha256->heap, hash, + MXC_TPU_HASH_SHA256); +} + +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((const unsigned char*)sha256->msg, + sha256->used, hash, + MXC_TPU_HASH_SHA256); +} + +WOLFSSL_API int wc_Sha256Copy(wc_Sha256* src, wc_Sha256* dst) +{ + if (src == NULL || dst == NULL) { + return BAD_FUNC_ARG; + } + return wc_MXC_TPU_SHA_Copy(src, dst, sizeof(wc_Sha256), + &dst->msg, &dst->used, &dst->len, + dst->heap, src->heap); +} + +WOLFSSL_API void wc_Sha256Free(wc_Sha256* sha256) +{ + if (sha256 == NULL) { + return; + } + wc_MXC_TPU_SHA_FreeCtx(sha256, sizeof(wc_Sha256), &sha256->msg, + &sha256->used, &sha256->len, + sha256->heap); +} + +#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 0; +} + +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) +{ + if (sha384 == NULL || (data == NULL && len > 0)) { + return BAD_FUNC_ARG; + } + return _wc_Hash_Grow(&sha384->msg, &sha384->used, &sha384->len, + data, (int)len, sha384->heap); +} + +WOLFSSL_API int wc_Sha384Final(wc_Sha384* sha384, unsigned char* hash) +{ + if (sha384 == NULL || hash == NULL) { + return BAD_FUNC_ARG; + } + return wc_MXC_TPU_SHA_Final(&sha384->msg, &sha384->used, &sha384->len, + sha384->heap, hash, + MXC_TPU_HASH_SHA384); +} + +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((const unsigned char*)sha384->msg, + sha384->used, hash, + MXC_TPU_HASH_SHA384); +} + +WOLFSSL_API int wc_Sha384Copy(wc_Sha384* src, wc_Sha384* dst) +{ + if (src == NULL || dst == NULL) { + return BAD_FUNC_ARG; + } + return wc_MXC_TPU_SHA_Copy(src, dst, sizeof(wc_Sha384), + &dst->msg, &dst->used, &dst->len, + dst->heap, src->heap); +} + +WOLFSSL_API void wc_Sha384Free(wc_Sha384* sha384) +{ + if (sha384 == NULL) { + return; + } + wc_MXC_TPU_SHA_FreeCtx(sha384, sizeof(wc_Sha384), &sha384->msg, + &sha384->used, &sha384->len, + sha384->heap); +} + +#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 0; +} + +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) +{ + if (sha512 == NULL || (data == NULL && len > 0)) { + return BAD_FUNC_ARG; + } + return _wc_Hash_Grow(&sha512->msg, &sha512->used, &sha512->len, + data, (int)len, sha512->heap); +} + +WOLFSSL_API int wc_Sha512Final(wc_Sha512* sha512, unsigned char* hash) +{ + if (sha512 == NULL || hash == NULL) { + return BAD_FUNC_ARG; + } + return wc_MXC_TPU_SHA_Final(&sha512->msg, &sha512->used, &sha512->len, + sha512->heap, hash, + MXC_TPU_HASH_SHA512); +} + +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((const unsigned char*)sha512->msg, + sha512->used, hash, + MXC_TPU_HASH_SHA512); +} + +WOLFSSL_API int wc_Sha512Copy(wc_Sha512* src, wc_Sha512* dst) +{ + if (src == NULL || dst == NULL) { + return BAD_FUNC_ARG; + } + return wc_MXC_TPU_SHA_Copy(src, dst, sizeof(wc_Sha512), + &dst->msg, &dst->used, &dst->len, + dst->heap, src->heap); +} + +WOLFSSL_API void wc_Sha512Free(wc_Sha512* sha512) +{ + if (sha512 == NULL) { + return; + } + wc_MXC_TPU_SHA_FreeCtx(sha512, sizeof(wc_Sha512), &sha512->msg, + &sha512->used, &sha512->len, + sha512->heap); +} + +#endif /* WOLFSSL_SHA512 */ + +#else /* WOLFSSL_MAX3266X_SHA_ONESHOT */ /* Non-callback path: provide the wc_Sha* API functions directly */ #if !defined(NO_SHA) @@ -1368,6 +2089,8 @@ WOLFSSL_API void wc_Sha512Free(wc_Sha512* sha512) } #endif /* WOLFSSL_SHA512 */ + +#endif /* WOLFSSL_MAX3266X_SHA_ONESHOT */ #endif /* !MAX3266X_SHA_CB */ #endif /* MAX3266X_SHA || MAX3266X_SHA_CB */ diff --git a/wolfssl/wolfcrypt/port/maxim/max3266x.h b/wolfssl/wolfcrypt/port/maxim/max3266x.h index 7f357d6b95..67c5c2fe39 100644 --- a/wolfssl/wolfcrypt/port/maxim/max3266x.h +++ b/wolfssl/wolfcrypt/port/maxim/max3266x.h @@ -62,6 +62,12 @@ #ifndef WOLF_CRYPTO_CB_COPY #define WOLF_CRYPTO_CB_COPY #endif + /* 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 /* Crypto HW can be used in parallel on this device */ @@ -255,6 +261,108 @@ #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 + #endif + + #if !defined(NO_SHA) + /* Define the SHA digest for an empty string */ + /* as a constant byte array */ + static const unsigned char MXC_EMPTY_DIGEST_SHA1[20] = { + 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, + 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, + 0xaf, 0xd8, 0x07, 0x09}; + #endif /* NO_SHA */ + + #if defined(WOLFSSL_SHA224) + /* Define the SHA-224 digest for an empty string */ + /* as a constant byte array */ + static const unsigned char MXC_EMPTY_DIGEST_SHA224[28] = { + 0xd1, 0x4a, 0x02, 0x8c, 0x2a, 0x3a, 0x2b, 0xc9, + 0x47, 0x61, 0x02, 0xbb, 0x28, 0x82, 0x34, 0xc4, + 0x15, 0xa2, 0xb0, 0x1f, 0x82, 0x8e, 0xa6, 0x2a, + 0xc5, 0xb3, 0xe4, 0x2f}; + #endif /* WOLFSSL_SHA224 */ + + #if !defined(NO_SHA256) + /* Define the SHA-256 digest for an empty string */ + /* as a constant byte array */ + static const unsigned char MXC_EMPTY_DIGEST_SHA256[32] = { + 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, + 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, + 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, + 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}; + #endif /* NO_SHA256 */ + + #if defined(WOLFSSL_SHA384) + /* Define the SHA-384 digest for an empty string */ + /* as a constant byte array */ + static const unsigned char MXC_EMPTY_DIGEST_SHA384[48] = { + 0x38, 0xb0, 0x60, 0xa7, 0x51, 0xac, 0x96, 0x38, + 0x4c, 0xd9, 0x32, 0x7e, 0xb1, 0xb1, 0xe3, 0x6a, + 0x21, 0xfd, 0xb7, 0x11, 0x14, 0xbe, 0x07, 0x43, + 0x4c, 0x0c, 0xc7, 0xbf, 0x63, 0xf6, 0xe1, 0xda, + 0x27, 0x4e, 0xde, 0xbf, 0xe7, 0x6f, 0x65, 0xfb, + 0xd5, 0x1a, 0xd2, 0xf1, 0x48, 0x98, 0xb9, 0x5b}; + #endif /* WOLFSSL_SHA384 */ + + #if defined(WOLFSSL_SHA512) + /* Define the SHA-512 digest for an empty string */ + /* as a constant byte array */ + static const unsigned char MXC_EMPTY_DIGEST_SHA512[64] = { + 0xcf, 0x83, 0xe1, 0x35, 0x7e, 0xef, 0xb8, 0xbd, + 0xf1, 0x54, 0x28, 0x50, 0xd6, 0x6d, 0x80, 0x07, + 0xd6, 0x20, 0xe4, 0x05, 0x0b, 0x57, 0x15, 0xdc, + 0x83, 0xf4, 0xa9, 0x21, 0xd3, 0x6c, 0xe9, 0xce, + 0x47, 0xd0, 0xd1, 0x3c, 0x5d, 0x85, 0xf2, 0xb0, + 0xff, 0x83, 0x18, 0xd2, 0x87, 0x7e, 0xec, 0x2f, + 0x63, 0xb9, 0x31, 0xbd, 0x47, 0x41, 0x7a, 0x81, + 0xa5, 0x38, 0x32, 0x7a, 0xf9, 0x27, 0xda, 0x3e}; + #endif /* WOLFSSL_SHA512 */ + + + /* Check for empty message and provide pre-computed digest if so */ + WOLFSSL_LOCAL int wc_MXC_TPU_SHA_GetDigest(const unsigned char* msg, + unsigned int msgSz, + unsigned char* digest, + MXC_TPU_HASH_TYPE algo); + /* Compute hash from accumulated message using TPU hardware */ + WOLFSSL_LOCAL int wc_MXC_TPU_SHA_GetHash(const unsigned char* msg, + unsigned int msgSz, + unsigned char* digest, + MXC_TPU_HASH_TYPE algo); + /* Free HASH_KEEP message buffer and reset fields */ + WOLFSSL_LOCAL void wc_MXC_TPU_SHA_Free(unsigned char** msg, + unsigned int* used, + unsigned int* len, + void* heap); + /* Free HASH_KEEP message buffer and zero the full SHA context */ + WOLFSSL_LOCAL void wc_MXC_TPU_SHA_FreeCtx(void* ctx, + unsigned int ctxSz, + unsigned char** msg, + unsigned int* used, + unsigned int* len, + void* heap); + /* Copy SHA context and deep copy HASH_KEEP message buffer */ + WOLFSSL_LOCAL int wc_MXC_TPU_SHA_Copy(void* src, void* dst, + unsigned int ctxSz, + unsigned char** dstMsg, + unsigned int* dstUsed, + unsigned int* dstLen, + void* dstHeap, void* srcHeap); + /* Compute hash, free message buffer, and reset fields */ + WOLFSSL_LOCAL int wc_MXC_TPU_SHA_Final(unsigned char** msg, + unsigned int* used, + unsigned int* len, + void* heap, + 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 */ @@ -300,6 +408,8 @@ MXC_TPU_HASH_TYPE algo, unsigned char* hash); +#endif /* WOLFSSL_MAX3266X_SHA_ONESHOT */ + #endif /* defined(MAX3266X_SHA) || defined(MAX3266X_SHA_CB) */ #if defined(MAX3266X_MATH) From 8404459918d9bef8facafaef53a91ead342ed104 Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Thu, 4 Jun 2026 21:04:34 +0200 Subject: [PATCH 069/118] Update README --- wolfcrypt/src/port/maxim/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/wolfcrypt/src/port/maxim/README.md b/wolfcrypt/src/port/maxim/README.md index e759472b94..171251fc18 100644 --- a/wolfcrypt/src/port/maxim/README.md +++ b/wolfcrypt/src/port/maxim/README.md @@ -84,6 +84,12 @@ hardware. - SHA-384 - SHA-512 +By default `MAX3266X_SHA` drives the TPU directly, feeding the message to the +hardware incrementally so hashes of any size are supported. Defining `#define +WOLFSSL_MAX3266X_SHA_ONESHOT` in `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): From 99bf36bb6176367c30d6996ec4e14e103eae1b29 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Thu, 4 Jun 2026 14:12:01 -0500 Subject: [PATCH 070/118] wolfcrypt/src/port/arm/armv8-32-curve25519.S and wolfcrypt/src/port/arm/armv8-32-curve25519_c.c: fix MPI overflow in L_curve25519_inv_8, similar to fix in #10536 (efabd1844a). --- wolfcrypt/src/port/arm/armv8-32-curve25519.S | 43 +++++++++++++++++-- .../src/port/arm/armv8-32-curve25519_c.c | 43 +++++++++++++++++-- 2 files changed, 78 insertions(+), 8 deletions(-) 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" From a7b0b3ebc2af634c4e93fa3cfe8f06158c77a8f8 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Thu, 4 Jun 2026 14:18:34 -0500 Subject: [PATCH 071/118] linuxkm/module_hooks.c: tweak wc_linuxkm_malloc_usable_size() and my_kallsyms_lookup_name(), moving wc_linuxkm_can_block() to where it's really needed in my_kallsyms_lookup_name(). --- linuxkm/module_hooks.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) 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 From ca599842001eeff09d9a163fefa5b06dbacfa2a8 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Thu, 4 Jun 2026 14:20:50 -0500 Subject: [PATCH 072/118] wolfssl/wolfcrypt/settings.h: for WOLFSSL_LINUXKM, force on NO_STDDEF_H to avoid conflicts with linux/stddef.h, which is always included indirectly in linuxkm_wc_port.h (via linux/kernel.h); fix indentation in WOLFSSL_uITRON4 section. --- wolfssl/wolfcrypt/settings.h | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index e7d9b568f6..22749a527b 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -1539,18 +1539,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) @@ -3925,6 +3924,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 From 5d810f4625a1838448025c156c0ce27dd241a9b4 Mon Sep 17 00:00:00 2001 From: Michael Rogov Papernov Date: Thu, 4 Jun 2026 21:02:59 +0100 Subject: [PATCH 073/118] fix membrowse report group --- .github/workflows/membrowse-report.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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: From bd022d995adc90381b8dcc7b784f1f332dbef379 Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Thu, 4 Jun 2026 23:11:53 +0200 Subject: [PATCH 074/118] Update README so the #define can be grepped by CI --- wolfcrypt/src/port/maxim/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/wolfcrypt/src/port/maxim/README.md b/wolfcrypt/src/port/maxim/README.md index 171251fc18..3970fd896f 100644 --- a/wolfcrypt/src/port/maxim/README.md +++ b/wolfcrypt/src/port/maxim/README.md @@ -85,10 +85,10 @@ hardware. - SHA-512 By default `MAX3266X_SHA` drives the TPU directly, feeding the message to the -hardware incrementally so hashes of any size are supported. Defining `#define -WOLFSSL_MAX3266X_SHA_ONESHOT` in `user_settings.h` instead buffers the whole -message in memory and hashes it in one shot using the SDK, which has slightly -better performance. +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): From 50166aab3683328232522127274319fa8727ca5e Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Thu, 4 Jun 2026 16:28:08 -0500 Subject: [PATCH 075/118] wolfcrypt/src/port/ppc64/ppc64-aes-asm.S: use TOC-relative addressing consistently, and add ELFv2 global-entry prologues. --- .wolfssl_known_macro_extras | 1 + wolfcrypt/src/port/ppc64/ppc64-aes-asm.S | 150 +++++++++-------------- 2 files changed, 61 insertions(+), 90 deletions(-) diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index fe9146dca7..1615350b9b 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -979,6 +979,7 @@ _ABI64 _ABIO64 _ARCH_PPC64 _ARCH_PWR8 +_CALL_ELF _COMPILER_VERSION _INTPTR_T_DECLARED _LINUX_REFCOUNT_H 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: From ada6c5f95b4825e03456d08f715577f71cb1f0cd Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Thu, 4 Jun 2026 18:57:03 +1000 Subject: [PATCH 076/118] SP gen: FP_ECC init mutex improvement F-1379 Better handling of the lazy mutex initialization to use atomics where available. Improved atomic code when no system support: - add types - used types in functions Add --no-ec to unit.test to not run wolfCrypt tests. --- tests/unit.c | 6 +- wolfcrypt/src/sp_arm32.c | 384 +++++++++++++++++++++++++++--------- wolfcrypt/src/sp_arm64.c | 336 +++++++++++++++++++++++-------- wolfcrypt/src/sp_armthumb.c | 384 +++++++++++++++++++++++++++--------- wolfcrypt/src/sp_c32.c | 192 +++++++++++++----- wolfcrypt/src/sp_c64.c | 192 +++++++++++++----- wolfcrypt/src/sp_cortexm.c | 384 +++++++++++++++++++++++++++--------- wolfcrypt/src/sp_x86_64.c | 368 +++++++++++++++++++++++++--------- wolfssl/wolfcrypt/wc_port.h | 26 +-- 9 files changed, 1704 insertions(+), 568 deletions(-) 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/wolfcrypt/src/sp_arm32.c b/wolfcrypt/src/sp_arm32.c index dd10cc64ad..d2bad638b8 100644 --- a/wolfcrypt/src/sp_arm32.c +++ b/wolfcrypt/src/sp_arm32.c @@ -75775,9 +75775,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 +75844,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 +75867,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 +75916,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 +76180,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 +76249,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 +76272,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 +76321,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); @@ -93808,9 +93856,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 +93925,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 +93948,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 +93997,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 +94277,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 +94346,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 +94369,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 +94418,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); @@ -120967,9 +121063,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 +121132,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 +121155,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 +121204,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 +121504,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 +121573,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 +121596,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 +121645,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); @@ -150732,9 +150876,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 +150945,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 +150968,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 +151017,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 +151214,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 +151283,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 +151306,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 +151355,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); diff --git a/wolfcrypt/src/sp_arm64.c b/wolfcrypt/src/sp_arm64.c index 59751ebe0c..01bce22285 100644 --- a/wolfcrypt/src/sp_arm64.c +++ b/wolfcrypt/src/sp_arm64.c @@ -24586,9 +24586,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 +24655,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 +24678,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 +24727,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 +24998,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 +25067,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 +25090,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 +25139,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); @@ -45088,9 +45136,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 +45205,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 +45228,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 +45277,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 +45548,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 +45617,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 +45640,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 +45689,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); @@ -73076,9 +73172,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 +73241,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 +73264,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 +73313,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 +73602,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 +73671,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 +73694,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 +73743,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); @@ -116561,9 +116705,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 +116774,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 +116797,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 +116846,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); diff --git a/wolfcrypt/src/sp_armthumb.c b/wolfcrypt/src/sp_armthumb.c index f56e1d9091..264fd2376a 100644 --- a/wolfcrypt/src/sp_armthumb.c +++ b/wolfcrypt/src/sp_armthumb.c @@ -101395,9 +101395,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 +101464,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 +101487,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 +101536,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 +101800,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 +101869,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 +101892,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 +101941,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); @@ -111863,9 +111911,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 +111980,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 +112003,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 +112052,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 +112332,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 +112401,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 +112424,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 +112473,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); @@ -125126,9 +125222,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 +125291,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 +125314,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 +125363,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 +125663,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 +125732,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 +125755,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 +125804,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); @@ -209386,9 +209530,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 +209599,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 +209622,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 +209671,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 +209868,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 +209937,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 +209960,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 +210009,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); diff --git a/wolfcrypt/src/sp_c32.c b/wolfcrypt/src/sp_c32.c index 8262fb2f73..25fb6fc576 100644 --- a/wolfcrypt/src/sp_c32.c +++ b/wolfcrypt/src/sp_c32.c @@ -23319,9 +23319,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 +23388,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 +23411,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 +23460,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); @@ -30437,9 +30461,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 +30530,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 +30553,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 +30602,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); @@ -37617,9 +37665,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 +37734,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 +37757,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 +37806,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); @@ -45757,9 +45829,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 +45898,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 +45921,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 +45970,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); diff --git a/wolfcrypt/src/sp_c64.c b/wolfcrypt/src/sp_c64.c index b0dd93cbd9..2c9875fd3a 100644 --- a/wolfcrypt/src/sp_c64.c +++ b/wolfcrypt/src/sp_c64.c @@ -23947,9 +23947,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 +24016,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 +24039,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 +24088,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); @@ -30492,9 +30516,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 +30585,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 +30608,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 +30657,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); @@ -37510,9 +37558,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 +37627,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 +37650,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 +37699,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); @@ -44832,9 +44904,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 +44973,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 +44996,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 +45045,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); diff --git a/wolfcrypt/src/sp_cortexm.c b/wolfcrypt/src/sp_cortexm.c index f9d22092d9..cd9361516d 100644 --- a/wolfcrypt/src/sp_cortexm.c +++ b/wolfcrypt/src/sp_cortexm.c @@ -37881,9 +37881,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 +37950,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 +37973,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 +38022,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 +38286,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 +38355,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 +38378,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 +38427,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); @@ -47989,9 +48037,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 +48106,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 +48129,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 +48178,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 +48458,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 +48527,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 +48550,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 +48599,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); @@ -59986,9 +60082,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 +60151,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 +60174,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 +60223,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 +60523,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 +60592,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 +60615,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 +60664,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); @@ -74469,9 +74613,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 +74682,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 +74705,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 +74754,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 +74951,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 +75020,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 +75043,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 +75092,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); diff --git a/wolfcrypt/src/sp_x86_64.c b/wolfcrypt/src/sp_x86_64.c index 7ce9b9ab6a..a720f91843 100644 --- a/wolfcrypt/src/sp_x86_64.c +++ b/wolfcrypt/src/sp_x86_64.c @@ -10441,9 +10441,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 +10510,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 +10533,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 +10582,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 +10872,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 +10895,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 +10944,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); @@ -29217,9 +29265,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 +29334,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 +29357,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 +29406,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 +29699,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 +29722,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 +29771,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); @@ -53703,9 +53799,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 +53868,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 +53891,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 +53940,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 +54233,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 +54256,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 +54305,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); @@ -94505,9 +94649,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 +94718,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 +94741,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 +94790,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 +95066,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 +95089,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 +95138,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); diff --git a/wolfssl/wolfcrypt/wc_port.h b/wolfssl/wolfcrypt/wc_port.h index 042551bfc0..f1e88c9b4d 100644 --- a/wolfssl/wolfcrypt/wc_port.h +++ b/wolfssl/wolfcrypt/wc_port.h @@ -581,6 +581,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) @@ -639,31 +641,33 @@ */ #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) { + static WC_INLINE int wolfSSL_Atomic_Int_FetchAdd(wolfSSL_Atomic_Int *c, + int i) + { int ret = *c; *c += i; return ret; } - static WC_INLINE int wolfSSL_Atomic_Int_FetchSub(int *c, int i) { + static WC_INLINE int wolfSSL_Atomic_Int_FetchSub(wolfSSL_Atomic_Int *c, int i) { int ret = *c; *c -= i; return ret; } - static WC_INLINE int wolfSSL_Atomic_Int_AddFetch(int *c, int i) { + static WC_INLINE int wolfSSL_Atomic_Int_AddFetch(wolfSSL_Atomic_Int *c, int i) { return (*c += i); } - static WC_INLINE int wolfSSL_Atomic_Int_SubFetch(int *c, int i) { + static WC_INLINE int wolfSSL_Atomic_Int_SubFetch(wolfSSL_Atomic_Int *c, int i) { return (*c -= i); } static WC_INLINE int wolfSSL_Atomic_Int_Exchange( - int *c, int new_i) + wolfSSL_Atomic_Int *c, int new_i) { int ret = *c; *c = new_i; return ret; } static WC_INLINE int wolfSSL_Atomic_Int_CompareExchange( - int *c, int *expected_i, int new_i) + wolfSSL_Atomic_Int *c, int *expected_i, int new_i) { if (*c == *expected_i) { *c = new_i; @@ -687,31 +691,31 @@ } } static WC_INLINE unsigned int wolfSSL_Atomic_Uint_FetchAdd( - unsigned int *c, unsigned int i) + wolfSSL_Atomic_Uint *c, unsigned int i) { unsigned int ret = *c; *c += i; return ret; } static WC_INLINE unsigned int wolfSSL_Atomic_Uint_FetchSub( - unsigned int *c, unsigned int i) + wolfSSL_Atomic_Uint *c, unsigned int i) { unsigned int ret = *c; *c -= i; return ret; } static WC_INLINE unsigned int wolfSSL_Atomic_Uint_AddFetch( - unsigned int *c, unsigned int i) + wolfSSL_Atomic_Uint *c, unsigned int i) { return (*c += i); } static WC_INLINE unsigned int wolfSSL_Atomic_Uint_SubFetch( - unsigned int *c, unsigned int i) + wolfSSL_Atomic_Uint *c, unsigned int i) { return (*c -= i); } static WC_INLINE int wolfSSL_Atomic_Uint_CompareExchange( - unsigned int *c, unsigned int *expected_i, unsigned int new_i) + wolfSSL_Atomic_Uint *c, unsigned int *expected_i, unsigned int new_i) { if (*c == *expected_i) { *c = new_i; From 089f1f7c919810d7c6187078f8c02e1f2014256b Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Wed, 27 May 2026 10:45:53 +1000 Subject: [PATCH 077/118] TLSv1.3 PSK binders: always use id protection Removed WOLFSSL_PSK_ID_PROTECTION from use as it is now on by default. Always check whether the server has a certificate (not a CA chain). If there is a certificate then continue, otherwise, report a binder error. Added test to ensure binder error returned and alert sent when no NO_CERT. test_tls13_bad_psk_binder already tested no certificate. Allowed memio test harness to be built when NO_CERT is defined. --- src/tls13.c | 35 ++++----- tests/api/test_tls13.c | 156 +++++++++++++++++++++++++++++++++++++++++ tests/api/test_tls13.h | 2 + tests/utils.c | 4 +- tests/utils.h | 25 +++++-- 5 files changed, 199 insertions(+), 23 deletions(-) diff --git a/src/tls13.c b/src/tls13.c index 5128f6097f..c46fdce97f 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 @@ -6527,20 +6526,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); @@ -6647,6 +6634,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. @@ -6817,14 +6818,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); diff --git a/tests/api/test_tls13.c b/tests/api/test_tls13.c index 09a5dfacd1..4f61244643 100644 --- a/tests/api/test_tls13.c +++ b/tests/api/test_tls13.c @@ -1775,6 +1775,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) diff --git a/tests/api/test_tls13.h b/tests/api/test_tls13.h index cd201c3673..81bb7800b1 100644 --- a/tests/api/test_tls13.h +++ b/tests/api/test_tls13.h @@ -61,6 +61,7 @@ int test_tls13_hrr_bad_cookie(void); int test_tls13_zero_inner_content_type(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); @@ -113,6 +114,7 @@ int test_tls13_cipher_fuzz_aes128_ccm_8_sha256(void); TEST_DECL_GROUP("tls13", test_tls13_zero_inner_content_type), \ 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/utils.c b/tests/utils.c index a6d37b89d5..ebcd12f377 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. */ @@ -784,7 +784,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 8a7942086d..1102076d88 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 @@ -85,7 +100,7 @@ int test_memio_move_message(struct test_memio_ctx *ctx, int client, 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 */ #if !defined(NO_FILESYSTEM) && defined(OPENSSL_EXTRA) && \ defined(DEBUG_UNIT_TEST_CERTS) From 0796519a99fb2239ac0ec68c21d3041818c5dcb3 Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Fri, 5 Jun 2026 11:30:53 +1000 Subject: [PATCH 078/118] More regression testing fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Leak fixes: free existing ssl->buffers.key before overwriting in SetSSL_CTX() (internal.c) and wolfSSL_set_SSL_CTX() (ssl.c) UAF fix: wc_CheckRsaKey() — mp_memzero_check(tmp) moved before the free (rsa.c) Build guards: #ifndef NO_ED25519/ED448_VERIFY around forged-sig test data (test_ed25519/ed448.c); guard equal()/cmov() for verify-only builds (ge_operations.c); guard unused pointers under WOLFSSL_MLDSA_SIGN_SMALL_MEM_PRECALC (wc_mldsa.c) Test cleanups (test.c): fix UB from out-of-range enum in hash_test(), always free AES dec object, fix der buffer declaration under small-stack builds --- src/internal.c | 3 +++ src/ssl.c | 3 +++ tests/api/test_ed25519.c | 4 ++++ tests/api/test_ed448.c | 4 ++++ wolfcrypt/src/ed25519.c | 2 +- wolfcrypt/src/ge_operations.c | 7 +++---- wolfcrypt/src/rsa.c | 2 +- wolfcrypt/src/wc_mldsa.c | 6 +++++- wolfcrypt/test/test.c | 22 +++++++++------------- 9 files changed, 33 insertions(+), 20 deletions(-) diff --git a/src/internal.c b/src/internal.c index dcd8fa8ab6..75bc485128 100644 --- a/src/internal.c +++ b/src/internal.c @@ -7329,6 +7329,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); diff --git a/src/ssl.c b/src/ssl.c index 5e4613b734..9d34fed324 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -16073,6 +16073,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); 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/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/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/rsa.c b/wolfcrypt/src/rsa.c index e265d69cf4..a2850b57f2 100644 --- a/wolfcrypt/src/rsa.c +++ b/wolfcrypt/src/rsa.c @@ -978,10 +978,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; } diff --git a/wolfcrypt/src/wc_mldsa.c b/wolfcrypt/src/wc_mldsa.c index dca96173a6..3e08dad88a 100644 --- a/wolfcrypt/src/wc_mldsa.c +++ b/wolfcrypt/src/wc_mldsa.c @@ -8593,10 +8593,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 +9029,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 +9114,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/test/test.c b/wolfcrypt/test/test.c index d9f62a7337..07beb6fe59 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 @@ -15258,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; } @@ -55727,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) { @@ -55781,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) { From b0757c1cb74a2f01aee7074c6553ebe200e8d5c0 Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Wed, 27 May 2026 16:10:05 +1000 Subject: [PATCH 079/118] TLS 1.3 plaintext alert: ignore before seeing encrypted Change to ignore plaintext alerts when WOLFSSL_TLS13_IGNORE_PT_ALERT_ON_ENC is defined only until first encrypted message from peer is seen. Negative testing added. --- src/internal.c | 42 ++++++++++---- tests/api/test_tls13.c | 123 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+), 12 deletions(-) diff --git a/src/internal.c b/src/internal.c index 8b34e20c37..8cdbf608b8 100644 --- a/src/internal.c +++ b/src/internal.c @@ -22420,6 +22420,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) @@ -22448,9 +22451,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; @@ -22481,16 +22494,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) { diff --git a/tests/api/test_tls13.c b/tests/api/test_tls13.c index 09a5dfacd1..cd6314b080 100644 --- a/tests/api/test_tls13.c +++ b/tests/api/test_tls13.c @@ -4542,6 +4542,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. */ From b06ced11664298cbe95eabfbd0700f6259473673 Mon Sep 17 00:00:00 2001 From: Hideki Miyazaki Date: Fri, 5 Jun 2026 12:20:09 +0900 Subject: [PATCH 080/118] Addressed Copilot comments --- wolfcrypt/src/asn.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 099921cc7e..1a85dc97b4 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -8272,10 +8272,12 @@ static int DecodeRsaPssParams(const byte* params, word32 sz, if (ret == 1) { ret = 0; } - else { + else if (ret >= 0) { WOLFSSL_MSG("DecodeRsaPssParams: trailerField must be 1"); - if (ret >= 0) - ret = ASN_PARSE_E; + ret = ASN_PARSE_E; + } + else { + WOLFSSL_MSG("DecodeRsaPssParams: fail at trailer_value"); } #else if (ret > 0) { From ef5c5f8ecb1f26ade5dd02cab7405372dde6705e Mon Sep 17 00:00:00 2001 From: Yosuke Shimizu Date: Mon, 8 Jun 2026 10:11:42 +0900 Subject: [PATCH 081/118] Fix the error handling on wc_PKCS7_DecodeAuthEnvelopedData --- wolfcrypt/src/pkcs7.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index a4091890fd..e7474d0c69 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -15319,8 +15319,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) { From a6f69ec09ca1c36d776e48ffa4836d2a21aeb9b8 Mon Sep 17 00:00:00 2001 From: Yosuke Shimizu Date: Mon, 8 Jun 2026 11:12:38 +0900 Subject: [PATCH 082/118] Fix odd-length CertificateRequest signature_algorithms acceptance --- src/internal.c | 8 ++++ tests/api/test_tls.c | 104 +++++++++++++++++++++++++++++++++++++++++++ tests/api/test_tls.h | 2 + 3 files changed, 114 insertions(+) diff --git a/src/internal.c b/src/internal.c index a3be7ee448..f49644b67c 100644 --- a/src/internal.c +++ b/src/internal.c @@ -32374,6 +32374,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) { diff --git a/tests/api/test_tls.c b/tests/api/test_tls.c index 9053aef376..a5b173bbe8 100644 --- a/tests/api/test_tls.c +++ b/tests/api/test_tls.c @@ -401,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) diff --git a/tests/api/test_tls.h b/tests/api/test_tls.h index 0e140af98c..5c8ddb1878 100644 --- a/tests/api/test_tls.h +++ b/tests/api/test_tls.h @@ -29,6 +29,7 @@ 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_etm_failed_resumption(void); @@ -52,6 +53,7 @@ int test_record_size_cache_invalidated_on_renegotiation(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_etm_failed_resumption), \ From fdda31b5c3245c2c347182fd9c1cd93be51670ea Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Thu, 28 May 2026 14:05:19 +0000 Subject: [PATCH 083/118] Allow RSA client certs on ECDHE-ECDSA mutual auth The TLS 1.2 server derived the single advertised ClientCertificateType and the signature_algorithms list in its CertificateRequest from the negotiated cipher suite's own signature algorithm. On an ECDHE-ECDSA suite only ecdsa_sign was offered (and only ECDSA sig algs), so RSA clients could not authenticate even though the server could happily verify an RSA certificate. The same was true in reverse for an RSA server: the CertificateRequest only advertised rsa_sign. Refactor SendCertificateRequest to advertise certificate_types and signature_algorithms covering both sig families when both are compiled in. Three static helpers in internal.c keep the logic in one place without mutating ssl->suites: GetServerCertReqCertTypes - certificate_types to emit GetServerCertReqHashSigAlgo - signature_algorithms to emit InServerCertReqHashSigAlgo - membership check used for verification The advertised lists are written to stack buffers in the caller. To keep DoCertificateVerify in agreement with what we actually sent, the SupportedHashSigAlgo call site there is replaced with InServerCertReqHashSigAlgo, which rebuilds the same list locally and looks up the client's chosen algo. Replace the magic certTypes buffer size with a new MAX_CERT_REQ_CERT_TYPE_CNT constant declared next to ClientCertificateType. Add two end-to-end mutual-auth tests covering both directions: test_tls12_ecdhe_ecdsa_rsa_client_cert - ECDSA server, RSA client test_tls12_ecdhe_rsa_ecdsa_client_cert - RSA server, ECDSA client Update test_certreq_sighash_algos to permit RSA / RSA-PSS sig algs in the ECDHE-ECDSA CertificateRequest; the previous assertion locked in the ECDSA-only behaviour that this change corrects. TLS 1.3 is unaffected: RFC 8446 removed certificate_types from CertificateRequest, and TLS 1.3 cipher suites do not bind a signature algorithm, so the server's hashSigAlgo already covers both sig families when either has been compiled in. --- src/internal.c | 208 ++++++++++++++++++++++++++++++++++-------- tests/api.c | 34 ++++--- tests/api/test_tls.c | 110 ++++++++++++++++++++++ tests/api/test_tls.h | 4 + tests/test-fails.conf | 18 ---- wolfssl/internal.h | 4 + 6 files changed, 307 insertions(+), 71 deletions(-) diff --git a/src/internal.c b/src/internal.c index 45a1f809fc..74f6b3ec5e 100644 --- a/src/internal.c +++ b/src/internal.c @@ -25828,6 +25828,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) { @@ -25839,16 +25986,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 */ @@ -25901,43 +26056,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 */ @@ -38959,9 +39087,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); diff --git a/tests/api.c b/tests/api.c index a2873fd747..a2d68fca49 100644 --- a/tests/api.c +++ b/tests/api.c @@ -30950,8 +30950,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) @@ -31012,17 +31013,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; } diff --git a/tests/api/test_tls.c b/tests/api/test_tls.c index ee2e112bfa..a71dc9c3d7 100644 --- a/tests/api/test_tls.c +++ b/tests/api/test_tls.c @@ -1219,3 +1219,113 @@ int test_wolfSSL_alert_desc_string(void) #endif 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(); +} diff --git a/tests/api/test_tls.h b/tests/api/test_tls.h index fb796244d7..48f200ce8b 100644 --- a/tests/api/test_tls.h +++ b/tests/api/test_tls.h @@ -36,6 +36,8 @@ int test_tls_set_session_min_downgrade(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); @@ -54,6 +56,8 @@ int test_wolfSSL_alert_desc_string(void); 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) 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/wolfssl/internal.h b/wolfssl/internal.h index fc918fbc77..59d4686572 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -4525,6 +4525,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 }; From a3bc7c96a0db8b9518691b9e2a0f6a2b84093721 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Fri, 5 Jun 2026 22:27:11 +0200 Subject: [PATCH 084/118] tests: relocate TLS 1.2 mutual-auth tests to avoid merge collision The two new tests (test_tls12_ecdhe_ecdsa_rsa_client_cert and test_tls12_ecdhe_rsa_ecdsa_client_cert) were appended right after test_wolfSSL_alert_desc_string, the last function in test_tls.c. Another in-flight branch appends its own new tests at the same anchor, producing a spurious add/add merge conflict even though the additions are independent. Move these two functions just above test_wolfSSL_alert_desc_string so the two branches insert at different locations and merge cleanly. Pure code movement; no behavior change. --- tests/api/test_tls.c | 80 ++++++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/tests/api/test_tls.c b/tests/api/test_tls.c index a71dc9c3d7..fd4e968453 100644 --- a/tests/api/test_tls.c +++ b/tests/api/test_tls.c @@ -1180,46 +1180,6 @@ int test_tls12_peerauth_failsafe(void) return EXPECT_RESULT(); } -int test_wolfSSL_alert_desc_string(void) -{ - EXPECT_DECLS; -#if !defined(NO_TLS) && defined(OPENSSL_EXTRA) - ExpectStrEQ(wolfSSL_alert_desc_string(close_notify), "CN"); - ExpectStrEQ(wolfSSL_alert_desc_string(unexpected_message), "UM"); - ExpectStrEQ(wolfSSL_alert_desc_string(bad_record_mac), "BM"); - ExpectStrEQ(wolfSSL_alert_desc_string(record_overflow), "RO"); - ExpectStrEQ(wolfSSL_alert_desc_string(decompression_failure), "DF"); - ExpectStrEQ(wolfSSL_alert_desc_string(handshake_failure), "HF"); - ExpectStrEQ(wolfSSL_alert_desc_string(no_certificate), "NC"); - ExpectStrEQ(wolfSSL_alert_desc_string(bad_certificate), "BC"); - ExpectStrEQ(wolfSSL_alert_desc_string(unsupported_certificate), "UC"); - ExpectStrEQ(wolfSSL_alert_desc_string(certificate_revoked), "CR"); - ExpectStrEQ(wolfSSL_alert_desc_string(certificate_expired), "CE"); - ExpectStrEQ(wolfSSL_alert_desc_string(certificate_unknown), "CU"); - ExpectStrEQ(wolfSSL_alert_desc_string(illegal_parameter), "IP"); - ExpectStrEQ(wolfSSL_alert_desc_string(unknown_ca), "CA"); - ExpectStrEQ(wolfSSL_alert_desc_string(access_denied), "AD"); - ExpectStrEQ(wolfSSL_alert_desc_string(decode_error), "DE"); - ExpectStrEQ(wolfSSL_alert_desc_string(decrypt_error), "DC"); - ExpectStrEQ(wolfSSL_alert_desc_string(wolfssl_alert_protocol_version), "PV"); - ExpectStrEQ(wolfSSL_alert_desc_string(insufficient_security), "IS"); - ExpectStrEQ(wolfSSL_alert_desc_string(internal_error), "IE"); - ExpectStrEQ(wolfSSL_alert_desc_string(inappropriate_fallback), "IF"); - ExpectStrEQ(wolfSSL_alert_desc_string(user_canceled), "US"); - ExpectStrEQ(wolfSSL_alert_desc_string(no_renegotiation), "NR"); - ExpectStrEQ(wolfSSL_alert_desc_string(missing_extension), "ME"); - ExpectStrEQ(wolfSSL_alert_desc_string(unsupported_extension), "UE"); - ExpectStrEQ(wolfSSL_alert_desc_string(unrecognized_name), "UN"); - ExpectStrEQ(wolfSSL_alert_desc_string(bad_certificate_status_response), "BR"); - ExpectStrEQ(wolfSSL_alert_desc_string(unknown_psk_identity), "UP"); - ExpectStrEQ(wolfSSL_alert_desc_string(certificate_required), "CQ"); - ExpectStrEQ(wolfSSL_alert_desc_string(no_application_protocol), "AP"); - /* Unknown alert description returns "UK" */ - ExpectStrEQ(wolfSSL_alert_desc_string(255), "UK"); -#endif - 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) @@ -1329,3 +1289,43 @@ int test_tls12_ecdhe_rsa_ecdsa_client_cert(void) #endif return EXPECT_RESULT(); } + +int test_wolfSSL_alert_desc_string(void) +{ + EXPECT_DECLS; +#if !defined(NO_TLS) && defined(OPENSSL_EXTRA) + ExpectStrEQ(wolfSSL_alert_desc_string(close_notify), "CN"); + ExpectStrEQ(wolfSSL_alert_desc_string(unexpected_message), "UM"); + ExpectStrEQ(wolfSSL_alert_desc_string(bad_record_mac), "BM"); + ExpectStrEQ(wolfSSL_alert_desc_string(record_overflow), "RO"); + ExpectStrEQ(wolfSSL_alert_desc_string(decompression_failure), "DF"); + ExpectStrEQ(wolfSSL_alert_desc_string(handshake_failure), "HF"); + ExpectStrEQ(wolfSSL_alert_desc_string(no_certificate), "NC"); + ExpectStrEQ(wolfSSL_alert_desc_string(bad_certificate), "BC"); + ExpectStrEQ(wolfSSL_alert_desc_string(unsupported_certificate), "UC"); + ExpectStrEQ(wolfSSL_alert_desc_string(certificate_revoked), "CR"); + ExpectStrEQ(wolfSSL_alert_desc_string(certificate_expired), "CE"); + ExpectStrEQ(wolfSSL_alert_desc_string(certificate_unknown), "CU"); + ExpectStrEQ(wolfSSL_alert_desc_string(illegal_parameter), "IP"); + ExpectStrEQ(wolfSSL_alert_desc_string(unknown_ca), "CA"); + ExpectStrEQ(wolfSSL_alert_desc_string(access_denied), "AD"); + ExpectStrEQ(wolfSSL_alert_desc_string(decode_error), "DE"); + ExpectStrEQ(wolfSSL_alert_desc_string(decrypt_error), "DC"); + ExpectStrEQ(wolfSSL_alert_desc_string(wolfssl_alert_protocol_version), "PV"); + ExpectStrEQ(wolfSSL_alert_desc_string(insufficient_security), "IS"); + ExpectStrEQ(wolfSSL_alert_desc_string(internal_error), "IE"); + ExpectStrEQ(wolfSSL_alert_desc_string(inappropriate_fallback), "IF"); + ExpectStrEQ(wolfSSL_alert_desc_string(user_canceled), "US"); + ExpectStrEQ(wolfSSL_alert_desc_string(no_renegotiation), "NR"); + ExpectStrEQ(wolfSSL_alert_desc_string(missing_extension), "ME"); + ExpectStrEQ(wolfSSL_alert_desc_string(unsupported_extension), "UE"); + ExpectStrEQ(wolfSSL_alert_desc_string(unrecognized_name), "UN"); + ExpectStrEQ(wolfSSL_alert_desc_string(bad_certificate_status_response), "BR"); + ExpectStrEQ(wolfSSL_alert_desc_string(unknown_psk_identity), "UP"); + ExpectStrEQ(wolfSSL_alert_desc_string(certificate_required), "CQ"); + ExpectStrEQ(wolfSSL_alert_desc_string(no_application_protocol), "AP"); + /* Unknown alert description returns "UK" */ + ExpectStrEQ(wolfSSL_alert_desc_string(255), "UK"); +#endif + return EXPECT_RESULT(); +} From 243926f5dad31dcc205b1864c4cb3a6ef2b05986 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Mon, 8 Jun 2026 10:14:24 -0400 Subject: [PATCH 085/118] Update wolfssl-wolfcrypt Rust crate to v2.0.0 --- wrapper/rust/wolfssl-wolfcrypt/CHANGELOG.md | 26 ++++++++++++++ wrapper/rust/wolfssl-wolfcrypt/Cargo.lock | 2 +- wrapper/rust/wolfssl-wolfcrypt/Cargo.toml | 2 +- wrapper/rust/wolfssl-wolfcrypt/README.md | 38 ++++++++++++++++++++- 4 files changed, 65 insertions(+), 3 deletions(-) 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 From 9f7c536e232f63e988e3adce12285c55e0865463 Mon Sep 17 00:00:00 2001 From: Eric Blankenhorn Date: Mon, 8 Jun 2026 09:16:43 -0500 Subject: [PATCH 086/118] Harden PKCS#7 FlattenEncodedAttribs --- tests/api/test_pkcs7.c | 209 +++++++++++++++++++++++++++++++++++++++++ tests/api/test_pkcs7.h | 6 ++ wolfcrypt/src/pkcs7.c | 88 ++++++++++++++--- 3 files changed, 289 insertions(+), 14 deletions(-) diff --git a/tests/api/test_pkcs7.c b/tests/api/test_pkcs7.c index 4aae3382ce..004a280222 100644 --- a/tests/api/test_pkcs7.c +++ b/tests/api/test_pkcs7.c @@ -3873,6 +3873,215 @@ 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; + /* 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; + /* word32 wraparound trigger: valueSz + encoded header sizes overflows */ + attrib.valueSz = 0xFFFFFFF4U; + + 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; + pkcs7->heap = HEAP_HINT; + } + + ExpectIntEQ(wc_PKCS7_EncodeEncryptedData(pkcs7, output, sizeof(output)), + WC_NO_ERR_TRACE(BUFFER_E)); + + wc_PKCS7_Free(pkcs7); +#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 5e3f3939fb..01ecb903dd 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); @@ -111,6 +114,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), \ @@ -133,6 +137,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/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index a4091890fd..eb3a251b2e 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,13 @@ 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. */ + if (attribSz > (WOLFSSL_MAX_32BIT >> 1) || + (word32)allAttribsSz > (WOLFSSL_MAX_32BIT >> 1) - attribSz) { + WOLFSSL_MSG("PKCS7 attributes total size overflow"); + return BUFFER_E; + } allAttribsSz += (int)attribSz; } return allAttribsSz; @@ -1759,7 +1782,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 +2250,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 +2314,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 +2333,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 +14373,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 +14440,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) { @@ -15577,10 +15629,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, From 8eaebaa7e825907415c3aeb4cb80685674d7b28b Mon Sep 17 00:00:00 2001 From: Eric Blankenhorn Date: Mon, 8 Jun 2026 09:48:16 -0500 Subject: [PATCH 087/118] Fix from review --- wolfcrypt/src/pkcs7.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index eb3a251b2e..779f211a69 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -1671,9 +1671,11 @@ static int EncodeAttributes(EncodedAttrib* ea, int eaSz, 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. */ - if (attribSz > (WOLFSSL_MAX_32BIT >> 1) || - (word32)allAttribsSz > (WOLFSSL_MAX_32BIT >> 1) - attribSz) { + * 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; } From a36ada8d531ffa322bac844ee9d8f94f487268de Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Mon, 8 Jun 2026 10:59:09 -0500 Subject: [PATCH 088/118] wolfcrypt/src/wc_port.c and wolfssl/wolfcrypt/wc_port.h: add * wc_local_InitUp() * wc_local_InitUpDone() * wc_local_InitDown() * wc_local_InitDownDone() * wc_init_state_t * WC_DECLARE_INIT_STATE() * WC_INIT_STATE_* * union wc_init_state_bitfields * WC_INIT_STATE_RAISE_BAD_STATE() * WC_ATOMIC_INT_ARG and WC_ATOMIC_UINT_ARG, pivoting on WC_16BIT_CPU, used to assure operands to atomic operators are 32 bits, and that wc_init_state_t is 32 bits, even on 16 bit targets like Arduino. fix&refactor thread safety mechanisms in wolfCrypt_Init() and wolfCrypt_Cleanup(), and fix a few preexisting error-handling flubs in wolfCrypt_Init(). --- .wolfssl_known_macro_extras | 1 + wolfcrypt/src/wc_port.c | 535 ++++++++++++++++++++++++++---------- wolfssl/wolfcrypt/wc_port.h | 164 ++++++++--- 3 files changed, 511 insertions(+), 189 deletions(-) diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index a1ebaf7562..36ab8ace03 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -662,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 diff --git a/wolfcrypt/src/wc_port.c b/wolfcrypt/src/wc_port.c index e7463732ce..02706d49c7 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 with initRefCount <= 0."); + 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,51 @@ 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); 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); 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 +1797,35 @@ 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); 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); 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 +1860,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 +1914,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 +1962,52 @@ 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); 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); 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; } -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); @@ -1774,38 +2020,39 @@ int wolfSSL_Atomic_Int_CompareExchange(wolfSSL_Atomic_Int* c, int *expected_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 (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); diff --git a/wolfssl/wolfcrypt/wc_port.h b/wolfssl/wolfcrypt/wc_port.h index 20a5436c8c..37e6fe8954 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,8 +535,8 @@ #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) @@ -593,10 +601,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 @@ -604,32 +612,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 @@ -639,35 +654,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(wolfSSL_Atomic_Int *c, - int i) + static WC_INLINE WC_ATOMIC_INT_ARG wolfSSL_Atomic_Int_FetchAdd( + WC_ATOMIC_INT_ARG *c, + WC_ATOMIC_INT_ARG i) { - int ret = *c; + WC_ATOMIC_INT_ARG ret = *c; *c += i; return ret; } - static WC_INLINE int wolfSSL_Atomic_Int_FetchSub(wolfSSL_Atomic_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(wolfSSL_Atomic_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(wolfSSL_Atomic_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( - wolfSSL_Atomic_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( - wolfSSL_Atomic_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; @@ -690,32 +717,33 @@ return 0; } } - static WC_INLINE unsigned int wolfSSL_Atomic_Uint_FetchAdd( - wolfSSL_Atomic_Uint *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( - wolfSSL_Atomic_Uint *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( - wolfSSL_Atomic_Uint *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( - wolfSSL_Atomic_Uint *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( - wolfSSL_Atomic_Uint *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; @@ -945,6 +973,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); From edf1439151c765a6e6b3518939b6116401f72a33 Mon Sep 17 00:00:00 2001 From: Kareem Date: Wed, 13 May 2026 16:55:02 -0700 Subject: [PATCH 089/118] Properly set ret and error out when tsip_RsakeyImport fails. Fixes F-3772. --- wolfcrypt/src/port/Renesas/renesas_tsip_rsa.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/wolfcrypt/src/port/Renesas/renesas_tsip_rsa.c b/wolfcrypt/src/port/Renesas/renesas_tsip_rsa.c index 732120be2c..eb1ca93d86 100644 --- a/wolfcrypt/src/port/Renesas/renesas_tsip_rsa.c +++ b/wolfcrypt/src/port/Renesas/renesas_tsip_rsa.c @@ -260,7 +260,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 +366,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 = From 8c4ad8d573433b2bc4fcc08ef3f87338220edd49 Mon Sep 17 00:00:00 2001 From: Kareem Date: Thu, 4 Jun 2026 16:40:51 -0700 Subject: [PATCH 090/118] Confirm rng pointer is not NULL before dereferencing it in wc_rng_new_ex. Fixes F-3979. --- wolfcrypt/src/random.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/wolfcrypt/src/random.c b/wolfcrypt/src/random.c index 8635354550..a75d3400e7 100644 --- a/wolfcrypt/src/random.c +++ b/wolfcrypt/src/random.c @@ -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; From 47bebc64417f8f3ff3fc82c20486f3716b336778 Mon Sep 17 00:00:00 2001 From: Kareem Date: Thu, 4 Jun 2026 16:51:14 -0700 Subject: [PATCH 091/118] Fix wc_tsip_MakeRsaKey ignoring errors and not freeing buffers in some error cases. Fixes F-4005. --- wolfcrypt/src/port/Renesas/renesas_tsip_rsa.c | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/wolfcrypt/src/port/Renesas/renesas_tsip_rsa.c b/wolfcrypt/src/port/Renesas/renesas_tsip_rsa.c index eb1ca93d86..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 From 00c84ced250ef9dc0a8b415453638b1ac7bf2457 Mon Sep 17 00:00:00 2001 From: Kareem Date: Thu, 4 Jun 2026 17:02:10 -0700 Subject: [PATCH 092/118] Confirm keys-params is not NULL before dereferencing in wc_XmssKey_GetPubLen. Fixes F-3980. --- wolfcrypt/src/wc_xmss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 { From b2d5cbf6f1053fce167504c875430e6f3c5ba2d7 Mon Sep 17 00:00:00 2001 From: Kareem Date: Thu, 4 Jun 2026 17:06:54 -0700 Subject: [PATCH 093/118] Reject auth tags below WOLFSSL_MIN_AUTH_TAG_SZ in the AES-EAX encrypt path. This matches AES-EAX decrypt behavior as well as other AES modes. Fixes F-3759. --- wolfcrypt/src/aes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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; } From 8e268dee1311d009bfe14c7a40daa382f2b46fd6 Mon Sep 17 00:00:00 2001 From: Kareem Date: Thu, 4 Jun 2026 17:12:49 -0700 Subject: [PATCH 094/118] Avoid suppressing error from Cy_Crypto_Core_Sha_Finish in wc_Sha512_224Final. Fixes F-4002. --- wolfcrypt/src/port/cypress/psoc6_crypto.c | 3 +++ 1 file changed, 3 insertions(+) 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); } From 147c8085626544ba285ac201215f83d499616fac Mon Sep 17 00:00:00 2001 From: Kareem Date: Thu, 4 Jun 2026 17:15:06 -0700 Subject: [PATCH 095/118] Change no_renegotiation alert to warning level to match RFC 5246 7.2.2. Fixes F-4113. --- src/internal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/internal.c b/src/internal.c index a3be7ee448..7b989d5da4 100644 --- a/src/internal.c +++ b/src/internal.c @@ -18819,7 +18819,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; } From 4a854b0a711b72561d625a1da2ed45f065781cca Mon Sep 17 00:00:00 2001 From: Kareem Date: Mon, 8 Jun 2026 10:29:01 -0700 Subject: [PATCH 096/118] Add unit test for wc_AesEaxEncryptFinal authTagSz below minimum. --- tests/api/test_aes.c | 9 +++++++++ 1 file changed, 9 insertions(+) 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)); From af0db53e867c1330304f4629b8a7c4dfd198536a Mon Sep 17 00:00:00 2001 From: Colton Willey Date: Mon, 13 Apr 2026 21:53:39 -0700 Subject: [PATCH 097/118] Fix negative count and NULL pointer checks in group-setting and shared cipher APIs Add count < 0 validation to wolfSSL_CTX_set_groups and wolfSSL_set_groups (src/tls.c) to prevent negative count from bypassing the upper-bound check and corrupting numGroups via byte truncation. Widen count == 0 to count <= 0 and add NULL groups check in wolfSSL_CTX_set1_groups and wolfSSL_set1_groups (src/ssl.c). Add NULL buf and NULL cipher checks in wolfSSL_get_shared_ciphers to prevent NULL pointer dereference. --- src/ssl.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/ssl.c b/src/ssl.c index c215101175..89cd4543f7 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -1295,10 +1295,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; @@ -3321,8 +3323,8 @@ int wolfSSL_CTX_set1_groups(WOLFSSL_CTX* ctx, int* groups, int i; int _groups[WOLFSSL_MAX_GROUP_COUNT]; WOLFSSL_ENTER("wolfSSL_CTX_set1_groups"); - if (count <= 0) { - WOLFSSL_MSG("Group count is not positive"); + if (groups == NULL || count <= 0) { + WOLFSSL_MSG("Groups NULL or count not positive"); return WOLFSSL_FAILURE; } if (count > WOLFSSL_MAX_GROUP_COUNT) { @@ -3360,8 +3362,8 @@ 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 not positive"); + if (groups == NULL || count <= 0) { + WOLFSSL_MSG("Groups NULL or count not positive"); return WOLFSSL_FAILURE; } if (count > WOLFSSL_MAX_GROUP_COUNT) { From 00a21b0bfa086bc5106164d9f3bc332e1d672636 Mon Sep 17 00:00:00 2001 From: Colton Willey Date: Tue, 28 Apr 2026 13:05:44 -0700 Subject: [PATCH 098/118] Add regression tests for group-setting and shared-cipher API guards Extend test_tls13_apis with negative-count assertions for wolfSSL_CTX_set_groups and wolfSSL_set_groups, and NULL-groups assertions for wolfSSL_CTX_set1_groups and wolfSSL_set1_groups (tests/api/test_tls13.c). Add test_wolfSSL_get_shared_ciphers covering NULL ssl, NULL buf, and zero-length inputs (tests/api/test_tls.c). --- tests/api/test_tls.c | 26 ++++++++++++++++++++++++++ tests/api/test_tls.h | 4 +++- tests/api/test_tls13.c | 8 ++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/tests/api/test_tls.c b/tests/api/test_tls.c index 9053aef376..8829822491 100644 --- a/tests/api/test_tls.c +++ b/tests/api/test_tls.c @@ -1354,6 +1354,32 @@ int test_wolfSSL_alert_type_string(void) return EXPECT_RESULT(); } +int test_wolfSSL_get_shared_ciphers(void) +{ + EXPECT_DECLS; +#if !defined(WOLFSSL_NO_TLS12) && !defined(NO_TLS) +#ifndef NO_WOLFSSL_CLIENT + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + char buf[32]; + + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method())); + ExpectNotNull(ssl = wolfSSL_new(ctx)); + + /* NULL ssl - pre-existing guard; pins the contract. */ + ExpectNull(wolfSSL_get_shared_ciphers(NULL, buf, sizeof(buf))); + /* NULL buf - primary regression case (pre-fix: XMEMCPY(NULL, ...) crash). */ + ExpectNull(wolfSSL_get_shared_ciphers(ssl, NULL, sizeof(buf))); + /* len == 0 - pre-existing guard; pins the contract. */ + ExpectNull(wolfSSL_get_shared_ciphers(ssl, buf, 0)); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif /* NO_WOLFSSL_CLIENT */ +#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. */ diff --git a/tests/api/test_tls.h b/tests/api/test_tls.h index 0e140af98c..dae0527cbe 100644 --- a/tests/api/test_tls.h +++ b/tests/api/test_tls.h @@ -43,6 +43,7 @@ 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), \ @@ -67,6 +68,7 @@ int test_record_size_cache_invalidated_on_renegotiation(void); TEST_DECL_GROUP("tls", test_tls12_peerauth_failsafe), \ TEST_DECL_GROUP("tls", test_record_size_matches_build_message), \ TEST_DECL_GROUP("tls", \ - test_record_size_cache_invalidated_on_renegotiation) + 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 f9deabd573..4f3362609f 100644 --- a/tests/api/test_tls13.c +++ b/tests/api/test_tls13.c @@ -590,6 +590,8 @@ int test_tls13_apis(void) #endif ExpectIntEQ(wolfSSL_CTX_set_groups(clientCtx, groups, WOLFSSL_MAX_GROUP_COUNT + 1), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_CTX_set_groups(clientCtx, groups, -1), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wolfSSL_CTX_set_groups(clientCtx, groups, numGroups), WOLFSSL_SUCCESS); ExpectIntEQ(wolfSSL_CTX_set_groups(clientCtx, bad_groups, numGroups), @@ -617,6 +619,8 @@ int test_tls13_apis(void) #endif ExpectIntEQ(wolfSSL_set_groups(clientSsl, groups, WOLFSSL_MAX_GROUP_COUNT + 1), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_set_groups(clientSsl, groups, -1), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wolfSSL_set_groups(clientSsl, groups, numGroups), WOLFSSL_SUCCESS); ExpectIntEQ(wolfSSL_set_groups(clientSsl, bad_groups, numGroups), @@ -648,6 +652,10 @@ 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)); #endif #ifndef NO_WOLFSSL_CLIENT #ifndef WOLFSSL_NO_TLS12 From 6211210c866255a30521c46f2e8fd577265739fa Mon Sep 17 00:00:00 2001 From: Colton Willey Date: Tue, 12 May 2026 14:04:44 -0700 Subject: [PATCH 099/118] Strengthen regression tests for group and shared-cipher API guards --- tests/api/test_tls.c | 14 +++++++------- tests/api/test_tls13.c | 20 ++++++++++++++++---- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/tests/api/test_tls.c b/tests/api/test_tls.c index 8829822491..7150ebd0b1 100644 --- a/tests/api/test_tls.c +++ b/tests/api/test_tls.c @@ -1357,25 +1357,25 @@ int test_wolfSSL_alert_type_string(void) int test_wolfSSL_get_shared_ciphers(void) { EXPECT_DECLS; -#if !defined(WOLFSSL_NO_TLS12) && !defined(NO_TLS) -#ifndef NO_WOLFSSL_CLIENT +#if !defined(NO_TLS) && !defined(NO_WOLFSSL_CLIENT) WOLFSSL_CTX* ctx = NULL; WOLFSSL* ssl = NULL; char buf[32]; - ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method())); + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); ExpectNotNull(ssl = wolfSSL_new(ctx)); - /* NULL ssl - pre-existing guard; pins the contract. */ ExpectNull(wolfSSL_get_shared_ciphers(NULL, buf, sizeof(buf))); - /* NULL buf - primary regression case (pre-fix: XMEMCPY(NULL, ...) crash). */ ExpectNull(wolfSSL_get_shared_ciphers(ssl, NULL, sizeof(buf))); - /* len == 0 - pre-existing guard; pins the contract. */ 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 /* NO_WOLFSSL_CLIENT */ #endif return EXPECT_RESULT(); } diff --git a/tests/api/test_tls13.c b/tests/api/test_tls13.c index 4f3362609f..24950cb6d5 100644 --- a/tests/api/test_tls13.c +++ b/tests/api/test_tls13.c @@ -590,10 +590,11 @@ int test_tls13_apis(void) #endif ExpectIntEQ(wolfSSL_CTX_set_groups(clientCtx, groups, WOLFSSL_MAX_GROUP_COUNT + 1), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - ExpectIntEQ(wolfSSL_CTX_set_groups(clientCtx, groups, -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 @@ -619,10 +620,11 @@ int test_tls13_apis(void) #endif ExpectIntEQ(wolfSSL_set_groups(clientSsl, groups, WOLFSSL_MAX_GROUP_COUNT + 1), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - ExpectIntEQ(wolfSSL_set_groups(clientSsl, groups, -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 @@ -656,6 +658,16 @@ int test_tls13_apis(void) 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 From 68144a81da6594fccb150d9856df68de7369dcd6 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Mon, 8 Jun 2026 16:52:06 -0500 Subject: [PATCH 100/118] fixes from AI review: wolfcrypt/src/wc_port.c: fix several missed refactors to WC_ATOMIC_[U]INT_ARG. wolfssl/wolfcrypt/wc_port.h: * harmonize the return type of WOLFSSL_ATOMIC_STORE() (always void). * fix MSVC WOLFSSL_ATOMIC_LOAD() and _STORE() with correct atomic semantics, and add gating on USE_WINDOWS_API. --- wolfcrypt/src/wc_port.c | 26 ++++++++++++++++---------- wolfssl/wolfcrypt/wc_port.h | 16 ++++++++++++---- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/wolfcrypt/src/wc_port.c b/wolfcrypt/src/wc_port.c index 02706d49c7..63c1bb57f5 100644 --- a/wolfcrypt/src/wc_port.c +++ b/wolfcrypt/src/wc_port.c @@ -795,7 +795,7 @@ int wolfCrypt_Cleanup(void) ret = wc_local_InitDown(&wolfcrypt_init_state); if (ret < 0) { if (ret == WC_NO_ERR_TRACE(ALREADY_E)) - WOLFSSL_MSG("wolfCrypt_Cleanup() called with initRefCount <= 0."); + 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 @@ -1766,14 +1766,16 @@ WC_ATOMIC_INT_ARG wolfSSL_Atomic_Int_FetchSub(wolfSSL_Atomic_Int* c, 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; } 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; } @@ -1812,14 +1814,16 @@ WC_ATOMIC_UINT_ARG wolfSSL_Atomic_Uint_FetchSub(wolfSSL_Atomic_Uint* c, 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; } 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; } @@ -1987,14 +1991,16 @@ WC_ATOMIC_INT_ARG wolfSSL_Atomic_Int_FetchSub(wolfSSL_Atomic_Int* c, 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; } 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; } @@ -2002,7 +2008,7 @@ 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, @@ -2015,7 +2021,7 @@ int wolfSSL_Atomic_Int_CompareExchange(wolfSSL_Atomic_Int* c, return 1; } else { - *expected_i = (int)actual_i; + *expected_i = (WC_ATOMIC_INT_ARG)actual_i; return 0; } } @@ -2060,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/wolfssl/wolfcrypt/wc_port.h b/wolfssl/wolfcrypt/wc_port.h index 37e6fe8954..0bd5f793a2 100644 --- a/wolfssl/wolfcrypt/wc_port.h +++ b/wolfssl/wolfcrypt/wc_port.h @@ -539,7 +539,7 @@ 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 @@ -567,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 @@ -577,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 From 41c09a734ca1f7da964462b9981f50cc8c96c40e Mon Sep 17 00:00:00 2001 From: Colton Willey Date: Mon, 8 Jun 2026 15:10:51 -0700 Subject: [PATCH 101/118] Address review cleanups --- src/ssl.c | 2 +- tests/api/test_tls.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ssl.c b/src/ssl.c index 89cd4543f7..f9270f9803 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -3361,7 +3361,7 @@ int wolfSSL_set1_groups(WOLFSSL* ssl, int* groups, int count) { int i; int _groups[WOLFSSL_MAX_GROUP_COUNT]; - WOLFSSL_ENTER("wolfSSL_CTX_set1_groups"); + WOLFSSL_ENTER("wolfSSL_set1_groups"); if (groups == NULL || count <= 0) { WOLFSSL_MSG("Groups NULL or count not positive"); return WOLFSSL_FAILURE; diff --git a/tests/api/test_tls.h b/tests/api/test_tls.h index dae0527cbe..14cb5b935a 100644 --- a/tests/api/test_tls.h +++ b/tests/api/test_tls.h @@ -65,7 +65,6 @@ int test_wolfSSL_get_shared_ciphers(void); TEST_DECL_GROUP("tls", test_tls12_peerauth_failsafe), \ TEST_DECL_GROUP("tls", test_wolfSSL_alert_type_string), \ TEST_DECL_GROUP("tls", test_wolfSSL_alert_desc_string), \ - TEST_DECL_GROUP("tls", test_tls12_peerauth_failsafe), \ TEST_DECL_GROUP("tls", test_record_size_matches_build_message), \ TEST_DECL_GROUP("tls", \ test_record_size_cache_invalidated_on_renegotiation), \ From 0278d3a72e9aae12704dfc6a86de5ae19c4d3950 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Tue, 9 Jun 2026 15:28:55 +0200 Subject: [PATCH 102/118] Reduce flash size for Arduino examples --- .github/workflows/arduino.yml | 2 ++ examples/configs/user_settings_arduino.h | 5 +++++ 2 files changed, 7 insertions(+) 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/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 */ From 7ea94c9a997f09d43ca508faddde8959b0844272 Mon Sep 17 00:00:00 2001 From: Colton Willey Date: Tue, 9 Jun 2026 09:49:43 -0700 Subject: [PATCH 103/118] Docker/OpenWrt: accept exit 4 or 5 in negative TLS tests uclient-fetch intermittently returns 4 ("connection reset prematurely") instead of 5: with ML-KEM enabled by default the larger ClientHello is sometimes reset by the server before the cert is evaluated. Accept either on all four negative tests as a band-aid. --- Docker/OpenWrt/runTests.sh | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) 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." From 4ef8d52abba91895f56c6e1fd876304fe80a02ec Mon Sep 17 00:00:00 2001 From: Eric Blankenhorn Date: Tue, 9 Jun 2026 16:37:44 -0500 Subject: [PATCH 104/118] Fix from review --- tests/api/test_pkcs7.c | 53 ++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/tests/api/test_pkcs7.c b/tests/api/test_pkcs7.c index 004a280222..84ab3c3bad 100644 --- a/tests/api/test_pkcs7.c +++ b/tests/api/test_pkcs7.c @@ -3891,6 +3891,13 @@ int test_wc_PKCS7_EncodeEncryptedData_AttribOverflow(void) 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 }; @@ -3922,30 +3929,32 @@ int test_wc_PKCS7_EncodeEncryptedData_AttribOverflow(void) #endif XMEMSET(&attrib, 0, sizeof(attrib)); - attrib.oid = oid; - attrib.oidSz = (word32)sizeof(oid); - attrib.value = value; - /* word32 wraparound trigger: valueSz + encoded header sizes overflows */ - attrib.valueSz = 0xFFFFFFF4U; + attrib.oid = oid; + attrib.oidSz = (word32)sizeof(oid); + attrib.value = value; - 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; - pkcs7->heap = HEAP_HINT; + 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; } - - ExpectIntEQ(wc_PKCS7_EncodeEncryptedData(pkcs7, output, sizeof(output)), - WC_NO_ERR_TRACE(BUFFER_E)); - - wc_PKCS7_Free(pkcs7); #endif return EXPECT_RESULT(); } /* END test_wc_PKCS7_EncodeEncryptedData_AttribOverflow() */ From 7d74caac6d35c10b20e65a3d46ae89f31dfd77ab Mon Sep 17 00:00:00 2001 From: Hideki Miyazaki Date: Wed, 10 Jun 2026 07:02:46 +0900 Subject: [PATCH 105/118] Addressed review comments --- ChangeLog.md | 11 +++++++++++ tests/api/test_asn.c | 14 ++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index ef01745e95..d1ea4c31ff 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** diff --git a/tests/api/test_asn.c b/tests/api/test_asn.c index e40ff8cf4a..d6e5ce522b 100644 --- a/tests/api/test_asn.c +++ b/tests/api/test_asn.c @@ -1136,6 +1136,20 @@ int test_wc_DecodeRsaPssParams(void) (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 */ From 6853bf1d93f35e792e82d983adbe21294d619d1a Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Fri, 5 Jun 2026 22:05:47 +0200 Subject: [PATCH 106/118] F-5606: don't enforce DTLS 1.3 2^48-1 epoch cap on the receive side RFC 9147 Section 8's 2^48-1 epoch ceiling is a sender-only rule; the same paragraph says receiving implementations MUST NOT enforce it. The KeyUpdate receive path was rejecting a peer epoch that crossed 2^48-1, violating that. Guard only the genuine wrap-to-zero (Section 4.2.1) and let the receiving epoch advance past 2^48-1. The sender-side gates are unchanged. --- src/tls13.c | 11 +++++------ wolfssl/internal.h | 6 ++++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/tls13.c b/src/tls13.c index 5e377f40ef..d2e9888a13 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -12411,15 +12411,14 @@ static int DoTls13KeyUpdate(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #ifdef WOLFSSL_DTLS13 if (ssl->options.dtls) { + /* Increment on a local copy so ssl->dtls13PeerEpoch is left + * untouched when the check fails. */ w64wrapper newEpoch = ssl->dtls13PeerEpoch; w64Increment(&newEpoch); - /* RFC 9147 Section 4.2.1: the epoch must not exceed 2^48-1. Reject a - * peer KeyUpdate that would advance the receiving epoch past the - * limit. Validate on a local copy so ssl->dtls13PeerEpoch is left - * untouched when the check fails. */ - if (w64GT(newEpoch, - w64From32(DTLS13_EPOCH_MAX_HI32, DTLS13_EPOCH_MAX_LO32))) + /* 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; diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 8b3231227b..326e7c8c51 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -5950,8 +5950,10 @@ enum { DTLS13_EPOCH_TRAFFIC0 = 3 }; -/* RFC 9147 Section 4.2.1: the DTLS 1.3 epoch is a 48-bit value and must not - * exceed 2^48-1. Expressed as the high/low 32-bit halves of a w64wrapper. */ +/* 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 From 359e688dc3b6695dd42f3a9f05778ee8c6f0e655 Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Thu, 4 Jun 2026 10:40:51 +1000 Subject: [PATCH 107/118] ssl.c: Move functions out to own files and add testing ssl_api_pk.c: added Public-key APIs (min/max key sizes, DH key test, signature NIDs, tmp ecdh. Reworked code of new functions. ssl_api_cert.c: added more SSL Certificate APIs. Reworked code of new functions. ssl_api_ext.c: TLS extension APIs (session tickets, max fragment, groups, etc.). Reworked code. ssl_api_dtls.c: DTLS APIs (cookie secret, etc.) Improved test coverage for functions moved. --- CMakeLists.txt | 3 + src/include.am | 2 + src/ssl.c | 4110 +------------------------------------ src/ssl_api_cert.c | 787 ++++++- src/ssl_api_dtls.c | 1462 +++++++++++++ src/ssl_api_ext.c | 2727 ++++++++++++++++++++++++ src/ssl_api_pk.c | 1246 ++++++++++- tests/api.c | 6 + tests/api/include.am | 6 + tests/api/test_dtls.c | 842 +++++++- tests/api/test_dtls.h | 51 +- tests/api/test_ssl_cert.c | 406 ++++ tests/api/test_ssl_cert.h | 44 + tests/api/test_ssl_ext.c | 688 +++++++ tests/api/test_ssl_ext.h | 92 + tests/api/test_ssl_pk.c | 567 +++++ tests/api/test_ssl_pk.h | 62 + 17 files changed, 8980 insertions(+), 4121 deletions(-) create mode 100644 src/ssl_api_dtls.c create mode 100644 src/ssl_api_ext.c create mode 100644 tests/api/test_ssl_cert.c create mode 100644 tests/api/test_ssl_cert.h create mode 100644 tests/api/test_ssl_ext.c create mode 100644 tests/api/test_ssl_ext.h create mode 100644 tests/api/test_ssl_pk.c create mode 100644 tests/api/test_ssl_pk.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/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/ssl.c b/src/ssl.c index f9270f9803..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) { @@ -1329,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( @@ -1389,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 */ @@ -2371,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; @@ -2979,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) @@ -3045,936 +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, - ssl->options.side); -#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, - ctx->method->side); -#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 (groups == NULL || count <= 0) { - WOLFSSL_MSG("Groups NULL or count not positive"); - 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_set1_groups"); - if (groups == NULL || count <= 0) { - WOLFSSL_MSG("Groups NULL or count not positive"); - 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 @@ -4367,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) { @@ -6108,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)) @@ -10466,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. @@ -10499,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 @@ -11989,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 @@ -12849,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 ***/ @@ -12942,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 */ @@ -13040,20 +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 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). */ - return WOLFSSL_X509_V_ERR_APPLICATION_VERIFICATION; - } - - return (long)ssl->peerVerifyRet; -} -#endif #ifdef OPENSSL_EXTRA @@ -13228,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[] = { @@ -13873,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) - 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) - 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 < MAX_CHAIN_DEPTH) { - #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) @@ -15763,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 */ @@ -15933,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) { @@ -16143,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"); @@ -16199,27 +13287,6 @@ 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) @@ -16312,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 @@ -16758,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) { @@ -16870,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) { @@ -17205,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)) @@ -17599,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 */ @@ -17716,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 @@ -18682,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 @@ -19122,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..15fbe1b40c 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. + */ +int wolfSSL_get_chain_length(WOLFSSL_X509_CHAIN* chain, int idx) +{ + int length = 0; + + WOLFSSL_ENTER("wolfSSL_get_chain_length"); + + if (chain != NULL) { + /* 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. + */ +byte* wolfSSL_get_chain_cert(WOLFSSL_X509_CHAIN* chain, int idx) +{ + byte* cert = NULL; + + WOLFSSL_ENTER("wolfSSL_get_chain_cert"); + + if (chain != NULL) { + /* 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 < MAX_CHAIN_DEPTH)) { + 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/tests/api.c b/tests/api.c index 550a04ba14..9cac424dca 100644 --- a/tests/api.c +++ b/tests/api.c @@ -235,6 +235,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -35268,6 +35271,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), 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_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_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 */ From c78fb5f41b61c03802d03828d3db9ce6ad2d3ae5 Mon Sep 17 00:00:00 2001 From: jordan Date: Wed, 10 Jun 2026 01:28:12 -0500 Subject: [PATCH 108/118] dh: fix subgroup check in wc_DhAgree. --- tests/api/test_dh.c | 143 ++++++++++++++++++++++++++++++++++++++++++++ tests/api/test_dh.h | 6 +- wolfcrypt/src/dh.c | 4 +- 3 files changed, 149 insertions(+), 4 deletions(-) diff --git a/tests/api/test_dh.c b/tests/api/test_dh.c index e90e4bba20..16467920b4 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/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; } From 0640b2ef99d4c52f51b1876c9d16dd9e1ff57839 Mon Sep 17 00:00:00 2001 From: jordan Date: Wed, 10 Jun 2026 01:39:18 -0500 Subject: [PATCH 109/118] dh tests: fix define gate. --- tests/api/test_dh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/api/test_dh.c b/tests/api/test_dh.c index 16467920b4..4b6c81c4a6 100644 --- a/tests/api/test_dh.c +++ b/tests/api/test_dh.c @@ -84,7 +84,7 @@ 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) + (!defined(HAVE_FIPS) || FIPS_VERSION3_GT(7,0,0)) DhKey key; WC_RNG rng; byte agree[64]; From e05a453944e799480c0c7958a4ae1b27bd2e9cf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Tue, 2 Jun 2026 14:21:09 +0200 Subject: [PATCH 110/118] Support RFC 9802 LMS and XMSS in X.509 certificate and CSR generation Extend wc_MakeCert_ex/wc_SignCert_ex/wc_MakeCertReq_ex to issue HSS/LMS and XMSS/XMSS^MT certificates and PKCS#10 requests, building on the existing RFC 9802 verification support. New LMS_TYPE/XMSS_TYPE/XMSSMT_TYPE selectors, wc_{Lms,Xmss}Key_PublicKeyToDer SPKI encoders, runtime signature-buffer sizing, and sigType/key consistency checks. Generation is ASN.1-template only, matching where the verification path lives. Tests generate self-signed roots, CSRs and a CA->ECC-leaf chain in-process and verify them, replacing the patched Bouncy Castle fixtures (only the stock RFC 9802-aligned LMS interop anchor is kept). --- certs/include.am | 1 - certs/lms/bc_hss_L2_H5_W8_root.der | Bin 2923 -> 0 bytes certs/lms/bc_hss_L3_H5_W4_root.der | Bin 7439 -> 0 bytes certs/lms/bc_lms_chain_ca.der | Bin 2638 -> 0 bytes certs/lms/bc_lms_chain_leaf.der | Bin 2637 -> 0 bytes certs/lms/bc_lms_sha256_h10_w8_root.der | Bin 1735 -> 0 bytes certs/lms/bc_lms_sha256_h5_w4_root.der | Bin 2631 -> 0 bytes certs/lms/include.am | 11 +- certs/xmss/bc_xmss_chain_ca.der | Bin 2787 -> 0 bytes certs/xmss/bc_xmss_chain_leaf.der | Bin 2786 -> 0 bytes certs/xmss/bc_xmss_sha2_10_256_root.der | Bin 2781 -> 0 bytes certs/xmss/bc_xmss_sha2_16_256_root.der | Bin 2973 -> 0 bytes certs/xmss/bc_xmssmt_sha2_20_2_256_root.der | Bin 5248 -> 0 bytes certs/xmss/bc_xmssmt_sha2_20_4_256_root.der | Bin 9536 -> 0 bytes certs/xmss/bc_xmssmt_sha2_40_8_256_root.der | Bin 18754 -> 0 bytes certs/xmss/include.am | 12 - src/internal.c | 12 +- tests/api/test_lms_xmss.c | 882 +++++++++++++------- tests/api/test_lms_xmss.h | 6 +- wolfcrypt/src/asn.c | 304 ++++++- wolfcrypt/src/asn_orig.c | 24 +- wolfssl/wolfcrypt/asn.h | 5 +- wolfssl/wolfcrypt/asn_public.h | 13 +- wolfssl/wolfcrypt/settings.h | 8 +- wolfssl/wolfcrypt/wc_lms.h | 11 +- wolfssl/wolfcrypt/wc_xmss.h | 11 +- 26 files changed, 945 insertions(+), 355 deletions(-) delete mode 100644 certs/lms/bc_hss_L2_H5_W8_root.der delete mode 100644 certs/lms/bc_hss_L3_H5_W4_root.der delete mode 100644 certs/lms/bc_lms_chain_ca.der delete mode 100644 certs/lms/bc_lms_chain_leaf.der delete mode 100644 certs/lms/bc_lms_sha256_h10_w8_root.der delete mode 100644 certs/lms/bc_lms_sha256_h5_w4_root.der delete mode 100644 certs/xmss/bc_xmss_chain_ca.der delete mode 100644 certs/xmss/bc_xmss_chain_leaf.der delete mode 100644 certs/xmss/bc_xmss_sha2_10_256_root.der delete mode 100644 certs/xmss/bc_xmss_sha2_16_256_root.der delete mode 100644 certs/xmss/bc_xmssmt_sha2_20_2_256_root.der delete mode 100644 certs/xmss/bc_xmssmt_sha2_20_4_256_root.der delete mode 100644 certs/xmss/bc_xmssmt_sha2_40_8_256_root.der delete mode 100644 certs/xmss/include.am 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 824d5664af818cbe3d57d9fb4f6cc74ffa97a072..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2923 zcmXqL;!Zbc{Ih_WiIItkmEpj9L2UzGHg2spkGAi;jGO|@f(9yvN(KsS%%LpIJd)-4 zIcdScJ_DZHnb+_biKPh-AYc*H5Szc~sn+V@m^(9+xe_6yR#2CA~ zk7aM#2V;ZZ5nBB31s5wDC>rpyF^9?uGcx{XVKrc8Wc+Wy2NK{139v9TF}9&w*~AqJ zvXl`-fGnNWP&t3YG^Wo_maRxpd=w<=Ws&&dR{E)#Cwt8*8ud)B9p2v@HZLKh+fKhv zTAGi)vP3xhs`wg@*S4Eh&aV2Fx>r4Sg8Hg8EWWw7_e&>lPTV4U=f}e30?VxvyB?`d z@p%v^XE5Vg>6hqJ+Bb#wUd>C{v*q~YKCTwQD>dwEH{P{B;anr55iPO%+tXqLf6-*M z3-4Js2At-~Q!gx-G1u{#`)V0K)*itf%TD`j=1FN?rj+(THG98Jy3U==tiNU~Td-hF z%H~9--^VJ}E#&t2@iWx%!_=ot^=o&>{yFjPpxS?a(oqkp9KHSy4|8PVRg-E%48$&2G%>u16XcC)GSyC|dvU z!mO(`kvAs0=(a!lb9`FO*%d!`PM$5zTU_$De$heE)dwdn<9+wev!Eu#%{jcqtn{XU zc=uj;*xwtgcl6`G#y6`< z9JWr)R5Cgv>U{ZM*dBkmt@*sHT4!8l?D^_n_2;H?(cK!E2IsprYi)n$XMHTG_j8)pSe>nTa9_Ib`<=0G-Js&;0 zO4CX>d+x-YyQZBzobLBCyfweCU#zw9lqrYq-Y21tUx+{Kee1o;?A!}C)}=KwS9Utb zg(SIM;=6oe_Ew1i*UCR_8lP7l&}I{{Z~f%Jb$)#kJSjQ8}LNTGjg zR!{srVT#GIW#>;8n-#mTs?HJ0a96wb?K(?p(!zju3YpH&=IHiR>fK{jh^Xcy?d>^ZobyYY6$PzQorJ{#)+E;ZRhDQ2iwoN&|$}?EBM9VPBLlV6-mDq@j|U5 z`SV|X^lXxl7T97x;jqN?86VfMeNNxg#5!?l*aT1gUiVe~6Sd5;7ED-}DtVEK?OaQ$ zgr&S@eT|Hr>mtsKOPhAia&`UD;aS)k^0((;{QrbGo1Y%vabW6Id+}R5SEqhXmj0p0 zc6)8a4-4g8Q$$|BkrQtAjjLfzx?cGEtnhlJ{L1s!tY)geeYd0XoX7#GK$Bno=8S6t zyaOcyW2E~}ZI?P0>+ovbhRGki7ii5W$yw5JHS=F^`(1|}x(ia0E|;}s%j?$jO_V+u zcUA4`qOVgJ15;I%lII=Z-2C?6kpe%X=UOW&c~_b)ebVs9QGKCB3+KhKk5{?hU5YQe z`lfQxKA|6}cPAZO+5Ap^)s@RjR=j@x&cefp^R{1QXI+v}gL{^y+amA7LIKh;vZoWy z2P^W=`NV7N$@O0D^Tn->4d29%KJW<(fBs>c@7Yw*k22f#o4Tl7_`=Bir0jtgsBjZ| zG+#JQr%zKtHaTK*&9&KU?Vs1q^@x%6s&!YFoYrKzJv1-hS(H;|-TJWW``lKn*tsuu zQdmzp+ZmRlhf8y+Ru&i)FY{|${rfCWQQ?fHce?Jrzl^>IZp_}4^N}%;Vee^{@AH?i z3-C$C$a<&yH;5d$?!|UN`>w~eYLQ@LlNuYg^om`Q=S$|;e41$Tp>*c!Blod4w1 zjOLzV!GikoiL<|Ri^9rK{of^b`v3KG$Za$ZeHDDzVS^+4`6a*C?J<7;clp!R-8)%5 zg&uucxOmO#dydCeRbK5|aYJ|?Ti^4g341t2Qh6#(!dgFdO3&TARrO$%hHL07lXCUj z`=6Lx+}@|FS#W4yx~#jZ`jqcxuIXR%&OPVMP_nU#FsR;liqYxm%VWu3Q-xDojn{d) zm+7RwUFGy~hVCv4za&MmB9%>3vMuKbr~d6byIE3we%fE3Sp7BU^YRt%u?C6dwOQU) zcHYHwZf)Q7FXywL>rO1)Se$yx;dadSBMaV(N~XzbG`5|cIcvt;6*|WIT+?OL1LQ0X znEmH>7{;V4T>rxRh~;6-a^}{fix059v-RT(P zj>SdGxS8)iF<4pDV)M)O`i-*WD*cG-e8r zaNTYt?!IZPHeoGanQO#YbQ{{X6))(1FnxDG^UYhLB_}t@d7pYUZ5q$fl(c~D@636A z$xk@CYUVW$J{}gGvkYSUu1;i@Uek6~$T+KK8YU*)H{oC{0^WK?Vv#94i0VWzF^ zWaZSm(|Iftj!YL%jO3j?!z9o2ONbQfs|n}y@7d_ceXU=Stol~(VA}hPrB+&oEQ{`~ zmHTOw#K^me^UKRiKlp>X)`iSn_VrA}w?qZsb84-#Sn}Hroprh_z+odE$aa5o-_#8^ zJ5M=uhg`p1^mz5>pu;~8Wxl?wa`TnZ;=^5=44heS``F|iH9xgNWrLZ!qFZs*#_l;S zLh0KN&T}%0n0!R+`|3yUHJ;Q*C7YHQrySj)z5cg`?8cd=7U>=QS#`lc{(Nq|5ntp= z!5(5bG=`ttzO*_vq@eL_9q4PF;c$mb#*R3z-__}VZS6V^pUwkr(8l(C`o-kIP zepV;={^=u`?a6G@T>G9as_jy+y>m)1^k*Q4>tBtxVMk9{TFLbPJk70IbVpQaYUy+9 z7Et+QytZl0mB^w8Niw#v0bM3je#b0X#?tdtpi@*dSWIZKb@H?c6O~&eWYr>WhUq2k z-|;il(c^yM?dKI+*MD4Io8#-y?mxBlNlfXQOxsggw^-u%o{4fz{@2zd7*J6aw6f;e zE!Be8wlnHBF;AS$S|g$+5_$U7lYPPOOS^*(uQ2DOS&91-L0Fv}vh5!Hn 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 43904f7ae7aea724d28b006fd8924bee016c94fc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7439 zcmXqLlI1pN{Ih_WiIItkmEpj9!Ds_sHg2spkGAi;jGO|@f(9yvN(KsS%%LpIJd)-4 zIcdScJ_p@Ut<8$_g_w{%2t|U}j|eZ@>o<;0Fn?Ff%c>p6i6UX?hJWr1RC+>Yf-K5=ZDe?i4w?nRiYBj1L?hq2w2 z=X<_yxAT&csZ-W&+g!OL?5S;&eokDJScF~p*Qwt!JTGXgY8+;~*WCBP zE9BX-^-Pn0o^9>+x#M5>=)1jO5l@UZGhTRS^o~RcfRvBI$m^RwC~I~wKn#N7TZ<$2UC=FPc6)gX?m%KcyM??3%>BWLr`m%(RSV-Bn{ zJnf?3b1kTS`JSc*vqim`59iliYd-5YCI8f`dHt`SDt!*>sWp9N#d~+_rP*JZyOl2- zZtM$-`*F!XM z96R3M?Q8he{Z{z%10qKzPBJZV?AdlD+Dp}`Z10bXka-Sk4QK0R?@tox-o?tYAns7s zxs@z)3OY>K>u)A(KdZh<=#-~wn~wCiWqMcl{`f6weQ)LSm$TH@zBklsSy7ZW8fEmzEuVWtEy=a5uI73iE`wJ#D{VXbD@l zee+)5cTi$!Nut;hG0AQxCF^T=KMBhsUN^m(9BIcmK9)pG5mK zCP(SpuDDm6c3_78ljyi(^BTNDr%X=L@e+WN>cvZ3$Fad(F3Axw**QJBri-7wkST+eI{0bm1f}{Z&&U9~BF^J9J-FlHH?UqciKot%MY>pCLaoeHE%z zje_n@Et$Vte#Z3E%k4C-Og?|BYJ-a7)(y(RC%63Rp7Q?lF^1nSR#lbVQWO&X&a(Qz z=i|~13xAQy6xuuhyZ#L*QITvVg>5YSL zYDikP#M|T&_Ktk#;;9ENOmQ{h8`ywwIxff=Qj;-VzBo2K;ZOsq_}aO>LS zEYEDCbJjt#{`~qP`a9>lTC&nty;wKj^aHQn2+wv;K3m(l`02;Iixam`o4@Zt#>Qn6 zXM`jyxVg19^5&IHeWrW)cAs=P4a;`MTewZQK7D7iSm6)#j|E4X4%og=YyZkwD0rb& zQ@vM|W44jt!{|J%ZoiH9m(9qTTEsT#i!=A0>rDqNcK@5$@c3)?VOfTX!`VN(uWuAO zKATzMn6TN!{poN1D`rdPhHdk=_`jX=Wsu43_PD&KTjnyP&$4~yRnIBXZK0vXHoIxX zhqXcP4GOV8fEf;%F7+ez!TLm3~=C8?#}UZHz1cFmc{bHNUcpQk-&`t#Xl zr{F{Nn1^x8+21nDFziX#x@YSl>AL#5Cn=w%S$#_>eNparU~1t%`J7~hgpcQ=pH9=* zGD#);?wizY4qiejXVYXpuAhEonb_rfLJkT~7u;ss?X_3-5oHWPRDP zeg2d)M#~dc8%Qn?-=yQ_(D;7k3V)uSOR<=dk!Rm#baSan`KO(X*FOgp75&e-!um1D zcIB6s@~TTK?=WE3M;o-KL!UdVuAy z#rY7YGbPWIGLEHw+;qP3yN0RG&hszok2ZLl3NFlv`_KJ6{=ZF?Ny&c(hY3Nytgh{j z-g@ze-I{akzK=qL{{4SmVku}?85{S{$zq4E$ht*Wntmsumj1@|y zdztq%XZE?4n#c1@>Pb`kr~b34MU{c;^8^cRQ`gvi~u8yTKJ>t4s6U-txeGIHUrJvo6c_pYL6g4B_pHl1O z((`Y(t8ANG^;U7Z^AvuQIjvhR6<)mUTR;D|hWYe0^QT6fF4x-Bsl2 zZ_fo$vR93Ga_SiZdWvcniY|V3WizM9CjOMK>%+a)t%_i&W-`$3igJn6G(UYHxc%Y2 z45|IX9@W!@R~`+Bu0PW?^=xv;ipe#51oZNoezJ)y{%-dt*ywpt&^ocr;<$3S6aL)S7 zUdWhQHGSXhmCT-pSwaMN2OFLFd1|dj#Vv&wZ#ETfySjX;SjN-BJrl&w%$k|@cJ>|R zM==TO{=STk$rSixc2?bgU3mL4E!RU*dHOH2!dm_m`JNO!{`;C?Yfh_@<6@N)7p1gg z*9-4HnzHfm&DI?fXM?7TZaMi*asE@GFZ!S3d*hDJD;Lk7?t-gq(K)dbep=ACRN4;Kr}>$)DBsA+$wbj!V$ zV%>7jV@}sMyT$G}$dcm`u+UPS`{%x;bN`<m`bNM&-Lr$g7$G6KTzALEC zTYSc+S&wTr$AYk>XRa?^B7O68K(E2CISs}jH-g$qn$j1&L-%AfD$}MpI+~yL{jF!&4*0H{VisKcP8iU->3!pYH44or&v8X6=Z+JGJhP$hrEf z3k&s`m7eO|y zy(LE@gH8lX%h)UI49jJI;-2+`XLe%lixt(5|DNq;j+u7N!bxny@@2F0AI?5H{eI39 z|GYEes)nb1QGI==eTH2m#8@42{s-=BNN-|Z&6KFhMAyLRRA z6>P`$6kGWjlx@4dVEWgXH})?dXw{xe@d>u7KDq1N>%cu1=HHnsQl$68S!jmNU7f|Up?-BdrsA-tMwu6^E8#V z{EJuL;~OloXOflp&oq|*I&Gi&9{GKG{+Z#PuwA^JS=my3Z|PeyYdJ4g{jvZ4&GO%y zYpcz-1hqZ2dAZAZrw70Hdh>o2_0Q>bvwsvkG0fv?G2?fd9jmM_e_FLrsU@x? z)<8op$^T|y(ubwCHzjs_%25lRR$YTySS=< zY50=Up1j@Lrv)oA21mQ{a7%71vM5doHNRJK$j;z-x52X@rIZKv0{y-fEb#i_rj|do zyvL|UC0z3DkKol!fA*K$-F06tdnB1KZWz+uIx>E3#NVWC%H_s1h zSvVe|J=6dQt>`9RdDUX{%_8FhdRro56_UF^KuJ9AEf{({C_oe9VK zIJ>GU-^*`(q;o{+PTsw_-iJM9PrQFFRnU1YrmJ#IWE`JqWjfA57Q-Y>s*wM^&X0u85)&2N`GoWAR~;!XWKHs^c1Wwq-# zMR!(noD!^iv~E$4_S2df6OSqHTQzwy(@8D)b@FdjnyUS?bMq|@O}E%Tt{Im;_uz1QP!tl88+Q~Vct`IYyFD0u3be{Oiy*bsih@Zy30IYFQF+K7hh;O%-Q<7c@B2d}|FN@TpYpObyHX-n?2%HFXvl6nxj)Qr`#j~%;m2Lx zF>hg3JfKsjl=DzJx~gCL&P?u)Pr@}6n>-42&mR)#S-440>d28dGfa>5W>hWB`I)k! zVe;=SlCGF%P?Uzj?FXZCM`kF1h8~CMR+q_!{qaw!S8C`NBdQvr~VL2?Z|6 z{PKAEdj8K*1-Eb9k%=~+x;iyk*}ayRIlZW;soj0WR;A5{zw(P$uALMbw9<9qp*Ne< zpLgzi%JWrwvkk z8=ea9`!mDsTEccciMi}&(YQSsjAib&0xOYWF7gnTW&AnxANrMR%=-%zqb8&+E>}w zwBXFiJV#eI@lH7went0s=JXOFg%?wH)g3&0{!GvjsVQ@VivDk3v`|(*)QBu-2 zi45r?CIuolZ!TVWHEB*nnf$9!Y8O@V+{+p$IGj>_B&079t z@&Sdl)la>`uutzO7>Gnmda0KM*hUhVNTfTS~8Q zn{x%^Mo=58Q2got1^82y~t^!IQ;iOWCKUY~@GuR&VTi zF~|Mg*;f-`Z7ff-WseJw?OY{rsZY8n^3)dAweOm5-g>#R?HTvS>MwIroHI<@rb|~% zpE$X5{%#?Q5BY}<|BhcTR&^!ghPbwe-PP5}H`^!tzsJ?vn3!vL|Nop0W83CtuIjI9 zeh+>xSFOLS zS*+>DpWaNld2;K#(%aIC$pR0*&)A@vAo(EXW9$;wfOnI$o==0SNlx^kDryoAEaIw?-Svsd( z5|!n?akY5GX}`bd_*<#c%4z0_3vV5)k{#X&=E!nCi#$-*et+BJ&*v9D*q^li$cbpx z1yUb9GeqQ)rknp#vwi#ONi%Cg#b0I5*|EPn^`nk6%g6__9C@@=Z_e^!BUUTsz;!d- z_x)R@vV>={d^qF!rgIjaJ_j;-JHGG~#Z6qs?yoIBsYE-yP}5&vX_?;ct)CW)w~H10 z6AIk9u6D-3d%UXem#j73qsc7%*4%jWOErdsfM0FGiBt7`r{;Wl)U(nmOEar=ufdfs zGI~#LEVPr`JNK@)&d0c)0p&jBoMF@5?!TJ()IG)a{NGHMPcz<_$}|-gbR_t;SucxB zc2pAJS$(uC*lFp)=Z@`%mM3)^_S{$}srltnvv1JhUWxCnFKQm2NU;1Ym??9!XZ~~@ z!!++n1_$@eiM#uLt)Tt%)4%+UFFbMW|M0Cw{#>u+6~k>g$&&RmUdcKB{;-oJ{J8Jr z?S?a7lzEhI%ZYOI?)UFwae6<^UG;OY#7w7~f;^APzccDSKDM&ug@ygK{|jX9eV)~P zQSQE`-(_ZpJP{g9gjPwBl(CyC!yxjx*Wj=GkjJ(?2K`Ez-(l`A#lh1x-B2Ybl)mHo3-pr z=M;-GN1ki^mGNv1{q+9eS^Jh>N$+|*&M#^Dp_HMOdi{UijyDDedwH#?Yd2 zSLGeCrgi`49$U?O{PGgZ-$rqDSK^mMdw)LjvT*UX&AuNGa>NDrtFHU!msPxXgQ~F3 zqqk>sX2?$znX)3u=Dp+Tt!+-5cXua6ZdbYZAc^&z)dGo`iC?XM9Jy37s;kyoE2ET7 znfdP*YFQBz@rN<^)r;-6UNddBgn39MU)eG7z3BI#h4Zt7c3bd2Ua`tQEZEw%e&W&Z zPlN;B7_?VxSl-JZwcw28F6W#JYQCXvixQ{geuz)_@@E0VCxs6`PTlGHoEe~McV+K# zQ7J>Ca-ZqqqMzcMo@VX8uC!Nuoxxn6or&uu6Ebu*D^Ir2W1Lwz^|`Obv-X|B`;L6N zzi8)wtzCMX_lTcnNZ(`GyM30)&B^VIla^?7B|N!sKZt+U-rZ^oIG-9knsCqerot?r zcPTF?7V!Fe<^JQF#A~>I(n0BMeM}oJY4=XulIa#+cGoks!7o^etKn~u?&{~~%j-C; zW$tZ`E)owCt5-}tmlQu^UF43E{d@d&byx&%%#nT^6}^^O)6Q)BcY(`>ogV|&=PI3_ z^epDghx8d&9qv|r)9+r-W34(@*Ld>U>&1%?rU>~?Tl~$(YtQW)mmFVftcr1)X)ByQ z`@#Hs;spVVxlg6eKG3H+ed-=gJ&_8=724t7N(vP;^|~J}OLhGkwKkp8E$l*@$8qKJ zKW0x6n0wH};*;Bcn*@#=k8k1&O1PBQN-92N6+biiOu${EngW+EQa@fTR(yQ?>~qWS zS6EKuu2AskNmr_yAAH8;i{IWe$IfhTo$2j+I!9mj)A>C%+jzu%qF+4~^32gtRcVb_ zx75P@BIo+N+qOdXmtU#ub=l-1WE*qG+EtQg&(6sUQfgx&?sZ%>2zqJo^-#)^XQKL@ z%r$~d5BvWgTdVP+F(@GW=b@)7&hDOUFtfU-MgR75_uie4#Euo+_ZkvXCz@AS7>hidAAHWTP1m{h zdh(VX%?gYDu5X+1$2@(-&S$mUhP-N1GR|h$CN6#N5*B`gZ{aK9V4f@9XR=fEs-~NM zdH3+oZ_6P4iE*pi5-!S}y|#OU`2xK!2Oj)T(2o84?A%GiWfJwjba`|*4W#+EZuORZ zYOVP-ag&Kl@}~Zp=Y={m4{R!E37gKn$h*RFT^!p2kLJw>Yu3BBi|p>zdziY?Lg`hj zo*?hN&2getU*^1B{%pR+{SDD!A3qp*t^6=)mzd*(i0ua|_t>pDWxqOo))7nY&z~Rm zpLFhv6?xulp42R0BO}2idT`pmBH0^EXZHr*wLiu;TO+dg(t+>k)27QQ`Rxq zT}We0k&RROt+}J4a`p2rS=Z93a z)6PD(|NPu`!y4BPh1rix|0SJRtoP(%{mg)k29ei)-TugUU1Q}9^QFym86QgCynN`j z74zm-+b(ZUVP@SrcXF{KSFpX%iT&$##+m+zl#qC&wlrJ%+F!-|NV%Z6mh2KE!m)G2XT{+*lCv%EEOt$X4@Z~{f#IM*Z;r$Dr zXFpxJVg8nyi(e-M7Ba6&X`Qg`Ih*9Mj&I`Ao<6hU>0;UIr7rN?FXH22UC$p|+f??y zli&T5UHf@N^TLBx+)MtZ-?A7f<#>uRFyOgHSpM9Q{r{@06DJPQ_`OlVYnE;zu?AOb@ti>Lb2ngHXC<>8AJ@kB+Z5;=cp{73Vn| diff --git a/certs/lms/bc_lms_chain_ca.der b/certs/lms/bc_lms_chain_ca.der deleted file mode 100644 index e3cebcccbb16897d85ad7e89550eac0c92a55d8d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2638 zcmXqL;_@}7bH)jP)3j-sClGNf71s~sF1!qSCIdNViGXoPN6GKZQV*}GDab6>HBrfp= z`Jp+1*_MHUfq{{Mfq|8Qfq^;XmdWxtd?MbCa?YQ+O}{)ppdnp8TPgYS^n<$%tmAg- z^M!5aDv>GQ?lb@W46T!P>Wh^P6b<;_eRl0-&acDY)UG8SUGw$Hf$7Y< z?<|m56fSyh4xeOw+QsF#HL;@YCes!HheF8-E|FP~u*%?sT_H|IV+|QJiZm7EP&UR{z1+ zTgUUZs;s?Y(fqYlnzAO-R2;=?Uq7Ddl(o#8Mf1^h-uS8S`_|xXpzO`xkol?lx4nIs#rf;DegygLGp3iH18v49M1oL$IEJ>>7-p_ z&2T1l>YUrZ6Jtb0tuLPWnY2&k-p5VvTs?nC^y)vA$Pj-q*@kIj#hEk5jSO6zN|z*X zN9*i6x@*a#FaBqpOupw`C4Gw^0{=siu?v~wR6w9r!8F(psBdz2Issx+~=d! z`pVmOmc}I=6#sufut56K)AtR_RZpKex^T)m^`*ze=UrdcKhZfxIqi1l0lC##v8#%k z7du`E=$P^H(U*wyFUr64j$VIl*HbwA(2+}@7qL&=bmjOt%T2RZFIbVgD5AQ1leuT~ zjn{s$=0Ci1)h9i9p`*L})U&r<59-Um-3Zoo6GjcS8dV4+-|iNZ?=Ln zssA=7UrJx@ChK!Vm0vYAYF_u$)jSc37xyf)Ge7Y2dt~g9WFwZ={Cfv31+RWH>CYwA z+moVaXFM#NR9gEMgYr`Y_*|u% zL_Xc0A35V<=_96_JAOUuoPj8P9LlDAhXin)}C6 zZ;SpFcmB8kNM=a-`m&la#3%aIC*N6JC29XR3oh8U!~XgiQPG2Uoiuq3|0LJ$3r)Y$ ztn~Uwz*)uIgSAGF8|#)I_he;W9?ZbO#I?%0X+@~BT2514p6rVQSJoM2w76aD=NBxM zy&{rW{_=3!su_uVNz=u=ME!Esrrvn5Pm;AZ-+)!a!(Q;lw8r=T^%+dz8pou9B88X! z_1+nKPLVD8+e~|v+m0!IzK;z1qpt=PCM@3{A@s;teBA@1YdQ;JPb)K+c+}3c_`G=I zs#E%h6rVj<-W{@rDdCJ8Y{@~H0_3V3Mxt=hb z^=jq6EX=ic%go}0hgD{}Urdt4+*GHFU6q-?pyThPr+TX;xc%(6YV#b*`0hC8%)`d~ zMXeT}81rKnGd}Kpx^++b#sl`QU$gxV-?iMwDjzH;lDKYV@7B@>8cP2*Y}JviJ-{K< zTYixH`Qq@6yw?+t{ZABsyivMu(wB%oX_@@DkLo?@_-yne-ecdire@<)G3PqxW~tr& znsLzl_Mh|Rm&Lus++y!XExkD1OkZc?8ILT!sMqtdqskbJjc1m}{%zge+I6Am!^6{F zbGGHz7tC4`u<7P(&)O+g-uoIZaBq0zd{cCh@fn{7HaWb7>A`tVuZ7id*w-DZu zzo~z+k(t_A@zpvZ!YW4FadvKN)zb3Ldhr>YA4E>B`1vdTYa!3~B~Au`-bSszS&ubD zCM|CYpP;wwdttTL89kMwtC{{A=xJS$TI}V)Rj^zBP~jSpV@GFowcpWsYc@M&=Pm#A z=mOoWRB@&`YkD6YF#olcan{UIC)rzGPd`rI5cFA=^Vf3)(G%yjH@(U`n!|bf+w&iy z;lG#U{o%-&t8vEf@VmIW+CRH(br_xre_%E(TfB8~aoof$_iFBLw^?p6`H9UT^X+Q{ zHHB_GOAZzdU%>Y>H0tO>x%GW>pNnU1jA{P)wO2p|E~MLc{b(B>XjaTcJ5=_shg~a7QeY&yUPB@<*Bv{>IIt5xg2SH_A$o7Xzovw zbDp_N{+IZ7@YKf%_qfhEA$H=!`R2dsp3D1HZ!LWlH1Ti6+=6=@Wtm~cTGGqaebkM0 z7HP&ryswx!Co?Ti^tJo(4_e#g?kP3Kx9_#HHb22o@n(zT?*;5Pqgc*Np42m|-QeU@ zXPq~3>rB)q8ccgo(lzJGb|1O00tF4Fo()^IpWo%`I)7L+ZObyAoqR?KjXU!E!^8Y* zuT4+l4g4p3A-*czP%f)PxYoUW(TB>Og7PFsQDx3AO;!0?w$^ z-`eo>qH{ovAD=x-w$Ea6>%SLjz`x`m%Z|SFWs`IET{$Wq$)0e*e*b^} z9`^|WH#lBJrS+^*_4Ktpe#Ul*Oq15@Cr@vDoI5>->k9XzJcpPI?baKA2Nv}mR~2bi zO_62`*pe^O_$}M1;NV-9*yAs6*8K2z8R0OyQOA_!&CJ=Rhd*5izaU&`I)CfV>&w3K jpZoj#lvJ{R&hqH{$Cict+VtY_%=3?4RQi;@>3#zMc4XGe diff --git a/certs/lms/bc_lms_chain_leaf.der b/certs/lms/bc_lms_chain_leaf.der deleted file mode 100644 index 4346b7aa159ee40a73703db29c8389df485c9108..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2637 zcmXqL;_@_TVq{#v%*4pV#L95slWdRyFB`X3n@8JsUPev}7bH)jP)3j-sClGNf71s~sF1!qSCIdNViGXoPN6GKZQV*}GDab6>HB(8y` zp}K)8#2`7`2IZtCrWyF5IfB`ifq{X6k%57Mm4ShQh1oJg_oGfrs#@TK4L)4G=FTYv z6?fi9h4LwQ?D&69WP2j(CfArPE$d`VLOKFgy<}UgU?69}!^RvcE6m9FpM}YQ!GI6M z;|K9rn3>oPpxf8PX$Z0rgh944&n-F9I48ZqiSd_vpT*DJzb>3mD4DgY>DH!C6&J1< z96J7Uslkz*J}11rYHF*uSJ^H4=De}&YfR7tW35T8eTruf9|=3)HuGhdp7tZB!;5o8 zeRKp8)nr`a?Eme4|6OF)neEzA>_R(_KL6|VsE&2**8|>Lw5tmE@5#MgHA#KKMD^a= zN^=edJN$mY<+q^Y%gGGE#P3lvyq_!xcL-*c&98^55Ti zN1gruw)#^q#1nw|iu8&?-h@RivRog1B&5}(OrI*B37pXNt7Okbq5c$3 z-W@6a=u6?x880SCp42&V^{p1KZmpq^$fQO5Qr~vf9RKjnq0~?4l|z61vOb>mN^-%D zVP|V*yz#L5?IZO>Kl$1Aw1nH$>lX5@3|M*Zt#u)*py&%*o3iT>k{90<7j3??-Kxz% zl6U6$=$Xeh8iW~LHhTZWUjAj}n|X!N$r@^QTVstGX8n9)z3N%nwTFjfSgl))+Si_$ z`Q@bI_d}b?+EqTjocC<+kAyAkFM?%G*4W2CWOzG6>sm{r&4hpHFa0)ned3;8D)(mB zu1Nu17miw{FXpgdg~pl(RG6lE6zUckY8}*-`|43;GRE6U+obTsy?;p>?X}Nk%D4d6W-HL z5Bv*TJD-=yDfCI!D>m)fenqpd1+)J7rgha(wY&FRK++xIbeEb(O`EQ2@%tT5JXE+P ztE?qLewMvs)A#$w6YdH|aLimk*T`tvf_DXbTrae)-hSwCr}c*PdZ7(}Yj;i>xIkB9|(ygB}-) zD_xw}jCZUqFapB#^51Aft>L~8c zHM3?`U{Al0x_9=?gUhFdH%^;TB~`oU&qJQ`|NSrJ3kTM(6}ej0bX+jHe9x2DX-C9s zZ3K2Nw~&0Q#iryUVOZ($>s_gmP@b3B%7fG998{RVGjzx!V)CuH@zT-->YP`-`A<7sloo+5ZCqY5Me8tE6OD9Rh z?fJ9tMeXzM-J2=`!gt?cJ+^)UfAo>=R3Wz$Pp)a5a5`?spMUU3f1KT(No&i(rk@Jr zNl=(nZ7MWz%KK-}HyCQ$iS5@|+ctYr?glmIqZz-mCftf;-OzvVp0)e21Fgpt;Ih9Nv7yj)QM2Uqsm(GOB0YAz-`rj1^1F9e@M@htf8d(tMG-53 zV{i$m@y{m%g`MYD=188(`?b;Xzq`Yg4a-m7oe)1e zmm}|Hx@6cn3yIjQc?+GHzOa3tEa|{pt0f;*knaXURg6sGlub(uPn=E+v8yqR(`lp%Gmnq1+Qtx`I8g=S5(!l&sraA(%H7% z;l`n-qLu&3x0e0pJJpa->RZ>kVf!;(E%rr!!i_hd-CSn>G~#}Bmh3mL$e8Eng~E@s zOp(xebKa@;QsLREilEBBzZJU_e`(G!C@+&(blAJL?T%QAd*n4^&k$XQ+Tis<=K>{~ z>?Zg!+r3S_Rp_}yhjIBf>y2%4>puLB%5@h{`qtB+Xg0@Xd|8!mBxi0nA zh>_KI$|{GMY2_0vZCPIFY({>*<`cKg4P=<*8XeV9vXgb-m3p^ zMD7`CHXM|w4?kDN|H9IHXWPQ#kGikjyX*er;mgJL+w`Z3v+Q6yn`<8%a*}WQBwnyuOgwuPnKW(xsxM&=>sIEO#>f9HzC0sMFEPs9L^P*3O=3QKD zux%daoQCVS7+*dqHD0dLq_Olx!jFTAVN;!Ir~Gk$JngF{pQK~Cz1m#qEAxuJ#%2mu zx-hO^|8pu&^5sQ}?NakC9Sz^Vlv!kR*jN83OH1;hF0NCHmmNO1=m0M#Pa$*Pn;jjm zG9~|TI;LKk{Xzf1>Qk&~GQJ9?g1;tu%;(;6Ro=_o#rEd4d-IdrQy$Nn{p*~W7vtpE zgFbRcDtO~krYZ5vugY3weM?f-@AOOY%_^P?uD|kD63$ySbHnk>#~YIJR&{fh3G91) z^@He?b@n1pHtm?Vc141$hbq_B%(4ongFT&~md~O;*>9h%Xz_a+9F=PZxDe{5OUuT3u=&piL=MWs*ao9;INJVMR# 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 c9ca9bf226c2e81bd15dafc96a0d8579b49c9aa2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1735 zcmXqLVmoZm_-6q#6C)E7E5m{JjL!{t*|@dZJlekVGI9zq3mT{xDj6uSF^94+^GKHG z=cEM(`zQptIV)IN7#Jy(q!yPb`1l4J$cghBnHiWEnHX9cTACO|iSrtnBXNl|#ShJL zW?KdZ1_nk31_m|;1_qW7kqc~ZsR|#S_hftXtuD*lTW$bf&!j2@=v@KRPP&D9YV-A%SW@P-&!fL?G$oSuY4zC*HtH&k}GtTD~~e)U9HLjS8* zd_lqvH!m7Y@+|HXHoG(7qy5e__ni+^TimCK?AfOh28JvS<1UB$oi zOgVJZK%#kR>p4?J;Wze~TXvl|oX__slwFWZIN7V`RtUS!?BWULFLlZ{gr$r3?>SH_ zZFoItLC1+H)@y!Uwu`pBU}*8Q(uLou_w)IG`|IaebMf8~Ke%4kKT`E@)%T-`OP4JA zamuyttik6^g{*E?R^8SvOAjoL)Nt6Mem2)TWkW0b2lW{u?=xmbb=I^yEwm}g-p(5y zSsC6qwf^dS*I&ZxB?@bUmfDE9ykP3x%CGpNMRnYoel9&5s z((Mg5uh=9W*=sZZn#zZ-mp8S>bu4`E@H{pBrQ^r&iN=0*K$a5;WT&g$Zoo^o{jZdB1zUGATXT!Sm~)%!TEL-}6Ss|2aAB)%kVa zbK5+Q9JJo`nkS3iN@QO*GF}E>E0Lnm*J+p$gaxc>52ufy#-`WPP$EQt5cW!7J63GyKnn*hF7c>As)ed8Bf(jf0JJJW!lAl$EW%Ewq_?7&DU8~9KJEv zR!;Gb*Igd_0Jq@0KXK3Wtpa!ON6nqa_1S>Yz;DURHvQA0nn`P~&-K66X#X$p=&D7V z0^?=5qdcx@Z;bzcJK*zYjTd*f?YwDJ)T**gF`_G=*WjE$F>~I(_+=uhC!02!vMpk< zS6ISxat~jDaBZufQRWln?&L#CUyfx-C^)%%UY=7Ez<-U~!8G=mAJY?=^pBrSH4>}e z8>su=I2|n@7!i8v7)Mi&zgmlZN!Z;fCHEe^{4_;^zx8an)&1s~S9I1~o$G$W=!Vtd zN4}Yo8hSkcN*AXu>##PT9uWBDwZz1)9|P*{L_6N^E!)B_tY5Q~x6Yhz<%g|Rn)^Gi zeP9xP#4aeae7@6>DtV$Ro}DJv}uYCr#4#?SsOlsnmO zHA8m56R!7LZ9+pjz8UH~&e+P7UA>O8NJV1di9L3PIyV+9N!nzS;=d}0anky`iAFvZ zN~O&E_Qo&07SX_1JURXA(=|=qcia@26FI(xEL;%DF)#DQp-?;X+4CZO1DB*&iXB{+ z60PhU*32TR@g-M!+5cOC?DyD9y5lUESTCBJKU*Di!}(rtCGR=6{i1iD{Ob?w{w#IZ zed(3(vb>ipGhG+jCqHtp{olBKVOxEcbrqa{pRG(ZM8Y=*7Y-Uh4KB_=T5}1-plq^k!d*0?&TrjrLFnnMNf*3 zT68QAbMVab=MVczFM7HE`E`Y7Gfm#ba4;+_toF>`rNUv@b7iYY==m?VOKOkmL~+ec z-g@p|+vN9thn@*56dvflq+e^#J6rGb?~;>uAF(U|F@MQZ+@2JBrj|CWyIQi&^IULcJJ5|;Bizngkn%}a0 zVwNodON+fO$4n{Y;jEgV( TxiYgaIR-qGv(V2{F`EPcB+~(l 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 ef4941ee8c087f9b6441bcecf2d8dee29f91c961..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2631 zcmXqL;&L`<{Ih_WiIItkmEpj<&tV3?Qj1Fze0+lqMy0|O%i0|P4q0|T?;yzN_fDl^`#^7#CswfNOG@p7G?8_JKTgx<50-<5l(Duq*G zgU+OzHE$Mkc+@YhnYUQkK+%AojX6|Sn33^63#$P$BjbMqK9B%ENPvZziLnjc$|g=j zkfkupY!-2{k~JgfRQ1;!!(X%GI8*})t zJ6JvP)cJK?*R)y{N?XFjLXLj0ZRsqN?~C>GxFpl>RNvlu=e7A2OOeg4UEg^ow!}rT zuFtT$us8VsoWzhjuO`2__o>Q9A@RnwZi&oKpH&l92Jkc)|B+;_uRpL-Me@h77bg@S zaqpeQrzTOCs8yYKNlg6gtvx(JZ*J|EIB9>TUOS@e)xp}kV!t^$&&!^_-rTI`sWG>w z#^y)4vv5#Oy?jZC_tM=x%yccWOt8 zAOD-lp~+TRnZKOgZS{C5elO(%?*`p>#(Tg0I_09~q+#*Xdxztrud`HlToKuwvM!}r zQO+?ZrS05FQ~Qdp;CUa_a^7tf@B7I9ZRP>Fa|yei$k)!h@rFT5_ub^QPmFioaeQsL ze)|5}3-@|=X`f!Z|5>ZJ=x?7^onPXP=FMWI%&(8H&X5}SOb$h|POFo-SH)zm=y{Ql*eZTNDfEA-5{^F@!o^Koo_ zRj|sTGEC~>nR{+OY^}HQi`G=T7=-V#H=BF#YO3_T=iU3WdK8)`mRqmdb(7~-+v6%$ z-IQ;aU;1t~T7CQC%4?rDyT6udX?8s^M{1{u*#x$d6WZ4q7WC`>J-$}K;8?i5yTZEM zh0JF|fAt;~EnKMi(^&T%`%Sh(eZ3cIC+;cu=Q(fro!c!Y0`{j@2iy6qxgC`I;+7?U zoB!#C7n4dPA6PsUy`%oeXX4Sokool=;*}i&mVZ}V|MJ2oj%j;co}9CPkb78ek>32& zkJofJovJjAuG~F2CZXT`VBGxEl{uDqKF5VmUHL!#lS#oJyQB|{O{_JU6>>gd2Zbyi zYAqIMUL0g~x@qbffsH(G9IC&+JvW)xTtd8Sqs_-&{X1MtetJ`{yH7~^{Be?<>)A)I z-A|qq<`>>nIO*9k_cU|1C-wJQB3HgTS@4bTb8>)<-E|QGMT-L&#qD+%&#d3lBYu-% z`^w+D#TSXSCY>-7ny~uc;t!t!+CMsM;Js>8Epk*~J8SIx8;7p`=?d{TUM^)jMX*!W`q9;$>EpLVE(IXR9vZlHGI-DZg$-L)np0ISuQ!(|7KMej1SK9e5=dYPC zZI-Zj%iSd9q7NHi62<9vgXa*z6ZpZ6^G zQ|^DTxB5@aQ-&oO^Y%9v&2@Kv^CaYVLXy6&*X-Yyys!RTwl2GUN6(`8kcA@dixkS1 zaVX8Yc&yXr?}aeC>|XJjKT}!i*qS!34M?5xIsLO0>w=SMhU=ehlW*3#XcO1YZuKZh;vR*218&_rG$zBnQR|bxS>7MSo z&uXQP7n&b1xZD)U=rG^sOJkarP%V@DvTF|&PRstwtJyR&F6g-9LjJy^6|-x1zB#i( zc}Gm&>SfnM(!AbAadvWP&y`ibmZF&ce(HwBj;jLrvyMk5-v6bM#wSty^Do!Ln~po& zf4w*5w_LtP>Wb>p_b$azvv)JU*%-GxOTx+2>y(UHz2C=ETQ)21j%z-i+93ba)?YK@ zQ}u(AZGF4c%_NUU6w3ThSoXKbtmgP1i?yl;`_C5|O%Fo`kGTf@k&JH(fiiCs}yb^vn;kR*UP@6L!(IQ%jGy8fNCo_8<6Fc*?_}95qSGB?|>-wkXo!`gfcwBPN z!zt2!)1Jo6fAaY?zr|JY1A)Es4nF>VSl8uZ)G5v2jAF5649At%%*r+NdA{mSiKfFx zkr^D18IRw0sj*{PEcCX+;VsVs-P2N`f%eYfHLN5y8x+|txOidi=8nhN=HbDcw>vJVa8WQ^!O7vu`gGf!b=>YZ3p45)E$;n~j0*UA z?vTIXdzmL6G){)h+4A9J$h@;n>AM%d7TW0V!o9@&eR68=i+>BZMapzPHjlphVy4-o zq6059^EhQb*#&z3UlC|Mk5_?5E~D|{dA|3HnOsrzL1+3s08T_gL~CEI83=jF=Z%=~B9e{pkMMtghe7h%n&4^O_? zPj7A%`EEMn#u?qc%YT{V_^h!kWZ}u!5NuceH|@6Uf@rJGCjsjENt@RM&k)@9=TL)* z^q-2uKfgLHXUTAr6*eij8mVSocj?+s_bgTS`#X3Ry`G*w!_)Vkg4M0(4-^@0&;K*w d!qNC&!ZF8wN-@yBr2>^jK&QJgV 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/xmss/bc_xmss_chain_ca.der b/certs/xmss/bc_xmss_chain_ca.der deleted file mode 100644 index 31c8690e5b5e0b1ef2d5e300c976182f4a60a673..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2787 zcmXqL;<|6p#K^XQnTe5!iIw3`%FAa4Tx=ZLY>cd|>}*N~8ir~HDs0T5EX+Kz<@q^j z!NEQXL2k|pmKFv^3MHw!N@LP zc4c5-U|`&3{d_5-P5AGpRtKDxX@~e<6IYI&%n^Fv&7-Kgr7s`8F)=r0nH%sv-gV(S zosB=cv+`5z6efcqttY>6ubO7bg4b zzT`D9J^EtLDqDZOhm`_PN^MyV7d32eiDwG%T$a9W@~cO@uF_nt_ue!oov>H>Vwl*P z<@1emj&JWy75}tbjB|M_YCnEzKES`pw)&5BrdH45OZunPYV}V}8P(ZBy=F+b>%7%(-XV{?l6@S$l4{@-8U+P#oW!bH0*#>-+=nYTR0y z>*;&^f5)18t(p#HG8>sEZJT|?Pine)sC)5+&y#%SPg7I0^3l&~{WDunal*;#U)ty8 zGEFy#Xx=Ok<;~?%{mJ#h(znly(w}i}V)7{G@vBrZd2P0E`>MmcGTtnATX|XEfPdwq z?YojRIm#kyrv%=(aCp9}ZqXLu>n}bmJ(a55^~U}3@(}%*6_U%D1?*0}R9dpU!ZE3< z!AnGXPQk&>f{VrLFZanTsT0nPpYwI8_^WmPmTq>$utEJ8aSw zy%KgVa-JKN56P{1c{+2(^yx_oRk_{u#`mqF?B`hhkiGtW+RVfmS<$&OPPU&ko9U=z z^M-qOs#8buoaq}}%O~8+{8)eYT=$JARYS*rrH^~U^q-no>$dfw*40WnAAle|um|C4@>0!r{|dYPJFQSL72aP z=(UxTLQSUbIyjMk@61crVtvjro!Dx2Zn^Oc6WgNK2|9Cx<~ttFUb%X2sWi(oo9D*M z@7X>#w-U5}(=B*=SE9t_mz#N{X6`!g)Bp0;`?pKg?PsktyL)}jhb`>R{g-3@g`K}u zm1O?;!>=t5cf~Aqs92#bm)*GYcM|K-GTF+ICAS4vI#!#io{azMqdSd1ddJrgRK~eD9;Mf~c=FHrmcc|E8Pw@BMzU^H@s-dv`%WIN~Q=QyPeBT6Y+`99h zwV&ZsD{g@Y!U1=mO_=_&Dnwc_-k>FF3U7cBhft;Q|Hbm_{}pZ!>xqgKJEF$ zmMhlzd-)fCC_MM=+?rnVMsSel`YmeW8#h&-eLFq5%~#?>2jjX60i27<-=DmFAVkCN zhok$q2m8A@^~I|AdQEOGj9FNDeA83^-I;tlB*Ol#6u&6{&OplYJo6c2=7_rw=1;8D zFWS9~@nMyY+TX*g)ZSHw_FYT77x|o{`H19#X&q;#PfvVj^hEL63;7Mr-Ce#{Qva|^ywx@ccDH0Q?DAc-eeW>+<3<=(f09H$DP#~mX8f*M+b>}MkTNu-JySs-(%nT zlkHBd=WJHyuJH30xsdlOaoL^1w&j2GPG0u^5XEom9`Pwd!(HWW3j?dvlo;7;M$a8z zwQkIhG0Dx}{C@`fk?ltnZpXze*s+6M>v`@}!6TX4o4%Y?vQ-Lp`x>nc#})hji_J8QqF$S>4UfyE@&v z`_A_lJ2b@}t8-Zp%|U)mRT4&0y5~aVg43KH>^?Dbd-|v4eH+w5=iSTx zBEr(o7kW-An2CRq$HI3kw?3}FE4DH`jPnV{#^%*WKWGJbi#Bk1dZieD>3pl95i>=v zYH`vF$E~N{>tB5R{k!*sBy9|+;K zk6raT$K2(>`ViPY@x^?xhX8k%=(E)el-TN1B(q9Xp< z%$q+XCr^4Wwm8YzzgM<+>b;LyLZZ|}QeZ2Qocc3D0<`djnGZ96QF zhzB}nJZYIAbjb0Kt-{v}9xokjE2pRmJGGX6UjFB8tWHlef4$e5CK-AE9#@Vc5uvY) x-;KFMj&$F%74=GHF%`%R3)H*u<iS8jMbcgz2EXKm(|TFy!D1^`FQ6dnKo diff --git a/certs/xmss/bc_xmss_chain_leaf.der b/certs/xmss/bc_xmss_chain_leaf.der deleted file mode 100644 index cf168ee3e2bf21d23754d284d75458e11fbee347..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2786 zcmXqL;<{(h#K^jUnTe5!iIw3`$}1NGE;bHrHbz!fb~Ysg4MQ~p6*lHj7G@sV^8B2% z;9wtxAU9_POA7-dg_6|b5`_rg;9v!3M*}%=UL!LDQv)*t3lJS8&TC|j#5K?|)G$zk zm?V$Kq@2{mG=pGdH!!<0FfcGMvbd~zklcO!S@hq(H%}Jv+wixmvy40za>LuG{-8UM2| z888^|fq48N9t$%Q+W{0yn>dextvwfM@!~1#=Ejex)CKI6Z}DCbIkhm0aj|U{cVzkctP&t!S-}kb)LsH!adWs&u(WEd~wgWh2iu`ga1b&SDbtMprhI-B>CDB*JZ~< z+OBUD@B3S8?EB@A{H%#t>jeZ`&HZcQ7;cK_v+Bvbb~!WgSV{1$f30cSZBYu5Qd8Hn zhBmTT$~$Hl)H*B{y-;aVaAtN~#vP`+%C8k&_bI2AkSu z_NHi?!wFgMqBhx>s3zMXxs7G#H%PW;$Nvv@~Lu-162#Jd9zPzT~YeyGDKF-D>m$r|;bgn^ZxySL zz5J>bNunQL99cANZ<)cBtHxJvK0UvGdDY7k-ZQ2CG5%umofo1j{ka@p1-SeVfse*u-J&~QU%k40eVXFoLs!`9J^fhE`n!S zM3wU?W3AGyPh4)TWuNu>(u}WV#(AcUCw|m0O<{V?d))QG%J!g`=tXBT-hQ2wKlSki z(Y{Fb?fUyi5zTOfJyviQy-1|tk z&^TI7Vqx61J$5fY#xg}3KdTkot-%x>SM@yqkWy)5dTQQlL3QP?yTz&u9({g#;GXjn zJFUyooae+nb+-DgdRu z%6{KC`f8UPUs&$Zg$2UTC$c$QaVz+jxcu(ji2Loc)`nbN>v%HH?&24J>lu2!5B@Bj zS!+@gd$Rd-tLU$pyKjo=cSy-Bz7|(3kjY`Y!#H2`$i@eXM}IDR{#f+2oMLAUj}>Rg zih_IWEVq}LNVv+%M9i5v|FD|RymrO2YVIE&HR*r3yu{?khIvvxmKDLvrK@)P{@q}5 zxcpq6^NnYw3LE6*Z_HEsA@V=G^f8l(kk8d3$1`7^SF6ACnE7zeQ?}c3zjeNB_^aGy zJ)dbq^Se4}{&eA-Wh_So=U$llIrgi_+~oRv!%Ja#+ujv^C@8b;-JJ4v!3kc0w|S8c zd)T8=9PxLRPx6b~SAHH^Kdz#sMqe^*8Ts0HpYS&XT73T!j z&($^KbJ{N^cyrQ=h?u78wMQN_#Pa`hn8y8gG5;!NofS8>GOjamaI&!n9V^K|fm0aBil|@eLp69+P{aoOrZvDt! zGjH+oLpQD#KXm!ncu|1=i1M7L9!vpE{RfuFODtF3xM0S5znQJAkEcGqQ=%ndFj;rD zcV}AZfe(kD%h>s(w|!#dn{5B9cx!)w)aD|i1fd^K9&$HUcI}b4V`jQTO=91=QiGmv z&*#0F*0b;bGVgDNVJaVUzj^x3Kg+mEU8vn$P(K6uy|8##e-->szBLH|_eL@4}m^K{!>?7j4>K!?aa_K*wP zlCR!$EWwaT8UOSiQf$t>fTY4tR6eG=z{i$_@)t%Z3vPt%Zp zqI86&?OEPmZd5u1{`D$#ms3K3)L%aZQH7VKQd`(Qa99*Jwm7{Gj$oX4^hCJs(wC*_$BroV9MGP9 za9)7R%KhOFZ%&Q>7Fm7UwyA%Ie*lMrOxX$s32u3=X^P$ zv+aM;c|7OD?i{734%KOF28`*YNAp$%3!84NYn2i^Wy|`0?Y?d0u_mWCdQ?=LH|yB! z)hxLqe`W97jYsXX7_*9nwpJQ__f-4(sq#Yf9j(|II_`g$CH(JrbNxl(YyKTEd>xNU zk4dj$UKbxxta9@})AH4Jd{1?zKj-9Mb=y^_!(WqmuhqII=dC&Ct(bV)?bCaKCpTCw zs05koF^U?nxu&YL+kP`&mlb;LVyWvY&CuZ7ncF%=6oQjVJr7H7H+d6R7xL(v1yAFe zr+xO~NiQ6?o_eo;@%8ub-V>6z1Jy2Wbl~T^leBp4?5dgW_k_>!7i_w^Ie6~mZ3m;< zx|H9wTboX4G<&pW)8ttUj4>(Af*XIIuZZ}rb$t(8>6{{QNiS8cXKJF~Hc$DXWtn~; zgx5ZH)$1H{pNIanh8t|cZuzWVUl1iyv-b;|;zT9?%B9!;tyF7h-m$qr#ItQlyzYsL z_-iw7{*atJ>Al$EBxnC#+2X19K4uAtMjzbAoy=D5`h&BR-6^o`Ltolu`RwR#%@?=r zusk9j=$!GSWrENl$3M0TUoUvPbhNFUqAKjvTKakUpSQ6(Jr4tU 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 12d70a002ef6c68bccaffa7120a31b24dc83ee04..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2781 zcmXqL;<{x$*q z#?>%YT0A(h+5PyAvPRiG7FUmYT33YuSvB&oL z3k>9r@wE$1j;;5Wt4?+Ld`Ca_o5U26fLQB%hkS>Oe9O};@+Xfidr?!ppZ8_^%nQ4o zKkt|j_(-{XV&y0A^S(g_1#yXAGi?%>te>v&lb2h%F?x&V$O!m98efB4xV=3iFK1H)?O`E+*FK{+{=#!oPD@12&G%n3s zr@^aU^zZSHg@th|KgjVs-gxEQ+%IP?vzskr=)I_9v~T}%n-%tEJ&z83<|!8ts@f@D zs8=Ys-fvsUfm64S$rcMZq&_gM?EUBID|k1%{S~r&A|f)0LXo`_^)sj9S@mw(i6}jW-|o{T}Uz6<+$pwe#I)0iTq_#t9cHygBC7 z*oxeE_o}tT@7jb_i(kpwU0B$lRu-PwZ+N~T^yjD7zjQUW2JW|sb?&P?z8+3{CSma#l-^}5qsYCyzYC*XLFjT&)e3C|H|uU zuIJ>I&)#pwxxT|A`-b;9dXmG z6RNwFCw!7m+p{pbWRuMQlW(fJMQ@(s-KnNn#&K-lMcE4hSGNdgwY_(n9eB(5f1dnm z(|@7$1}DBV{oNM(@WM`ZRo#cFn^oTTOkNq^D&wntn#*r~nmN11vMXQzivM1}Z>_#@ zjjDLord4St4K6rWYd6je;+NXgRxhqPx%J?u+&3C)*8~VCB{|fFH{ zeV?ZmrJR;LqeblVsZ}pr{Bw2h?~vqmp15Iycfhqf!SMDMJ6a;3(w2D>Goez|El_Np>rE`>=-wdOxyIv z`|a@ZQiJ4`xUoJL=h%BA4W*z(NU2X~s`RBy^ezaWb zZuCjtuONH+j`AaSPAgU$TQ_zRP5L znAph&mgdeocx~7A_SYp#o=I}DMH^f`9jzlR6D>9A`R@((Q8TJTUk7ID_Y18S3%}^N z?`BZz*2v2@tv@m48Mi5h+?|>Kp*=Nt`|qk*tBz(zHz`jnv1loa$Ptj+9^4w!`f@wN z?xGOm>9ys@x4oNlOQP2Jk=5L;isa6jn&0(#ewf@}SeYbOqr32H^6{K2yDQ$=@lR@= zzh}=(pZ!;^Db+7}{&P~@jDwXQ)<1Y{P$*tiv#0U+!;I%rC$CDM>pt{yfzCIUS2p$> zUqw!@`ulZOjIL)%f?{pjy}f^yA1ax+>)jG@g}-lCNPn^Zv%i@wEr`X)xkvZUCy!Ys zu7CW0esg`_^*zF<%kj!n%YOcU+b7GdTfR3YE!JZfe}=EhH}xYozuI;G+;=kL(W=Qa z6Yo!tXH*iNWuUsjXyddE7yg~iYq45&Qn-BariVoubejSuuA>n?#@zm+m3x2^Bt4~Beu2yesxpz0Kq08G# zz*j=$;+JrX6Bp~dgj>Xa2h_G*v$8neksos4;g(&FOt5=n?TVW^E14xI@UV>_ z|C45KN#Cm`rhbx*3LoRyj`StAf0mT#pZVtdrGMW(9rHZoYVvJ=;IihQFQQ+ak3aq2 z`Af?G;MIXCFEZ^{Y_NY`e`iq^^NqNUdA)a}jP8$a=YTS_gv+7G^SGkJfDsWG&9PMulzujrpt zcMINB6kmQgJ>b*SKMWfdiGPfezEv7>Z`%5q`p+0rM+*aH-{%Qq}GSMe*e1rVA=Kj z*~x5uVJf)|n*XNse%|$jYo(RbjMlsZYT|AVe-~L+hR?}U?5lqDGUZ_5wdK<^RPvXf zerl;ZdC|pbg|(;l<_d8&T_eU<2pzke5+Kff0x*!r_>d$pbt-zMj|g4-&V?2XOY z)-LFs^3)}E9IXNxla_{VY`Ae3+tD2^vS*pf2iTTI;*Kx}l zH*&XM^?RdhRxWYK_f`)3jiaAlix+M5y0PSkM-p$7eMG0glruXGxxALmTj%!9Wb?&G z{apvG(t2#uBp(*I-})Tj{kms;>!bTyFKJJUyY~1%Pe+TUuf)}D5}Lc(YG+hWpTzcP z;a`rtz3aSps$N-Q50Cn8ps?Mm z$!0=>PHT|{+g&3eQP!FIKRZ`Px#Z2y$ZT%CYr*Bq&G>Ioy6wKTg}qn(s;YO}YA8>; zZtv{paOZ)nUzJo>WXpAr>m|O4ZR(2-yp?C?Za(3`HNS3ilz!{p-Fsf{5q$G;YImdD zr}TUNY<82*Z_eKEsGd7kRQJjS+Y@K(ZqLp;>1ES#wj*3fPDbn_<0n3`j)l5)tO2TC z$p>#*otf(8Sh&kVZ>5>=i6fCc!h+M5y_AVmeZcW6b6sXIUyng0=gAY>0_FS+`Z|u( tR4ttJWb=>NtW~E!oH0>~Y<8(!QTI8YG020<-fOXzfY*NQ1`F+mNdO#xDiZ(z 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 91f3bf554663ea897d637e2e3268baae26c35b49..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2973 zcmXqL;+|>H#K^FKnTe5!iIw5N$FD&KTx=ZLY>cd|>}*N~s)ou2ifqiGEX+Jo<@q^j z!NEQXL2k|pmKFv^3MHwM(^=wzms@U_ zPx$b}=FiER^8Al%|K*lshlOm}KWVYDfuaFF8*`|vFeBrC7FGjhM#ldJd>{dSkN^ua z6Jr~Sy-i%LAe$LvRPKD>xwH6ZexH@kR$pHKr{{uO8_QRgi|$r>JkQWLcdoh2?Ycf` zoqYliuWx*EY+sy76r(>A8A)_&>`fs{)D*v+689N^{uYE6L{rW;lyXxAE zv)k@oDm+xP_NV=M>3&7I^{N-wiM-hpaqUfA==!q{^DBRUUa4cbrz()SE$ziCw~)4Ffv>FO7kwEp8dDezuZR&(k>)2KRjUn{|s`>m6!IxG_B zhxlpoyTr%s*fK?a3(wy4rG8Hpb+ok)a3#2ic--C5ETW_CH=sjN?r^ z<^5>YqNRD;H~n{MOt0foJ7)CiVX0B-Db+QXG`W|}xZ0b@vu1umO;j#J-sAZm%|+Kb zZk~OltjDo7$TKM~`nmBgL-vv%e$h>W>=;sp->D&1k^U9^#TLGf>aFC0@$7M4#;)$sBEy!Dh1djr!qMc4ls3l16?UW#Yk5T9}F zYsi(~DuxSoDl|{2sy-cke*f*W`6tBk!zDLPHoKX&LSf={qrgpDZf(}isYx=OkujI= zD@(;cffXr|FHc{dRdD?9TaMNehLvm2E?klPyx`!b-e!Y2=XuY${$oD1u6I^XbVRFf zYP8syqxo-+^8GhHzQ*a;@qlYR`#7#im9pAf`_zwI;HxIS9q>hxo5m-s%VH}O?cOTwFe^iuRL*<3HDmA^1wwv zPiWSXQ$ezyU0+Y?5v`3sZ}-^8P9rlQCcS-!L9M67$udX#E9q}T1lsp(6W(=G;!v}k zz@C8Q-u<)g7THhSw&C2v=Nt5TUyGC}ze}88GCAZ?*9pa%j6~D;O;-6ozq_$?h991$ zGvCN?;z7p3HIHkh;(o1{yK8jy;>v})jI9JB);euJ&o$w??mCraU!GiM7GW%i@^$*l zyTCG0GV#s4l@D1YrhNR>cmLpm<%~a`@2vV8p*mxe?Ua`n`YS4?U-!4Ou5)Ot53#+R z^W0KW>$*_i(`v7SEi;Ptl>X^f|*Ed6+5 z!p`SPyjH>wbkakzjZ6Kf5U%)Yj0G)`X*abucsx8vuB@T|GrPrVE=)Cy(OPZ4MXL&zPWaE+R2E; zGdV@86;ABG5$<#ED*v^Uwwv=i;yswo^gp|L@%E%rUfKWFuXK%LH^eV$WS$+X@n5=I zSLo+|hR1i^*zR5SkGq@}?{=B%)SlYlmFDO7pO0L<&7}LTq+{cyGq=8;%ir*KF=J;` zxy*{cAO3J$6A)lLGDAje)Blf>YhFj)J@)Zbj3iHH$=;RyT4nVw{#QB&E-Y>5`>>}; zzVWl4d%&E4m8|c3YuEmmwka;nVyar^+0Q$iuHIMszby7lDr-b@eP zhY$DuZJqf>XZ!3A3_mX#-_uyyxTndd`)#B51@`0)V|}?Z+OhA>Tx8xK$oDsDkJ9CX zI+~rAPgT@i+jzrMH_?&tgw99BJu`Jp{^{|ouX(N~nX@p)KICrPyJQ9Bo4tk!nWbx3 znha;m?f7Z1(^g2hW+$(`>8>lLHA}Mc{ZzkmD81fa!wIpIlj-{+-V+uNq&@>WH?L*?!tLEArCD67Ko?n2!{; zg)*;{a$Ry*ahJ-{o%j3PDCbe7x+eXbKHk6A_^oSht(>Eg%xf4>1+_r?pkzB$1jy%C}bH(I3+=}!00 z*L|4K=ved5uHzRs^LKNlH$D?feN;NSJ1)xKY&c%>G*R!#%pXxHvm;!Mj;qRFezkdH z!+Di<>t&PI9AorY`s?wsY1i4htG?DuYF(;yLHN*TVLf*F1o>wbY)prmdNY!_}<0aRla!}@(BId9v+>q5SQtr9nrtiX($BzmC&43w*uVV~1m1=Zr9Yw_l+rW^a61 ztEX4?U-J*9^&RGw`72#}J4dD@ zZL-q3nZ^3Q9o=?Y%#b>45<6F6%B0EH)sID)-2AP-&&c$Zti6b~{4HMbQkFx;(j}c$ zcXq8`6F*f|teN4}r1yqW)Bi6>+rDzDed}DkTM-dWpcM2+#c=r-iaVE(-Q|-jc+6W}%y_}!3>m`R1@6Vp) z437ijpC#YWkX(GYEb*>ve(Yk^629!~S1;Za7WQ~9CRPT7sq&&HVT+DT)TC)}k8 zE_a^Cm>2UUp1$iHs<3n-qITW%sSkk582K)yMX2 o`_Xf)$}9HTx3miFW%pcs9$MHGeGfmk^3!^`i27Y$(_H2Q0O3G>cmMzZ 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 24b47019e1b811d41026dfccefa9b5d2d89a55a6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5248 zcmXqL5~(q0Vq{ss%*4pV#L95s6T?OWE;bHrHbz!fb~a@LbwgDHWj5we7G@rq^8B2% z;9wtxAU9_POA7-dg_6|b5`_rg;9%bn137VCBQpaNBNIbQBO_CbC~;mRb0jYD1_dMA z&+N*;z`(#*WN7MSF*&u_>9)qb8A^Z60#o|T{61d2e9g-~?S#_1rDC-TGHct-ZhY70 zRB}kz@UypZS*?1X_u^zO=EyBG#5)!%8z>s^voVLt3NtePXJIv9W@P+tzy}iG2MMq+ zGcmTI*xMwW0x!Z+U1?MuKmUD`}(P0w;m^}`1`eI4m?`8 ztGh$|(L%Fj7T3BgpI6LmmIyt^Fy-HAjlb$^?wSe)On(qIZAN>{frUhPoSVH{aQfou?S8Vq52Dx zJtcZp9F}zViplKYT@kxT-Hvsq%#AbJ0e{=11t%Yyafg*%d{JhxcGI+m`WjA#66u7=*9aKBQ!U;N3{ z9JhkAzvEg?ndzTSVAWg4all`HrAP5&qs!dU%HqoVE0wF7I8&aUe>G#(ihk>OQCns4l93qc7|UlbK~CB6?#w4=^d7T z(_?*@$D_pS&|Yg6nGY3&%hO=Kj zQrY~3RfkQ^KvT4OYLVQnU$%3#&p5}+IXfBNv3hiPvfeURlQOr0>74)e$IPFzwC2mU zx_^hKJP(uI^7fV5uIqP~rfzy!H}TifRPC#qV*d)b8lSIh2yS9ICi|2(_b)>xTYgbn zywG1mISF^eB?T2G%ty{!u?C7QdM#&?Tz^C9ljNf5wqJu<@2{|Uci4#Q%=d@?E`7PY zB6Ie!|4L?(k*@Iz1Rms^hdvs`I*+f4qQXdJ@~#iU)k zBJ++P+~-|==Lz$H^^5jfOlA4It7c>J5{qqFXWt!lY5sOe+(Fc}_|wWqpUfj>TKY$7 zM`~ZXE>kMH<{`K1>^Y|ECUkvy!0oJ4_;IS?r{f|$;TziG#QPb11E1_}oO|I#y4XV< z#t=8Tquv}lJ<7uR8ZCak^;+#ev+vcv)sGZD{IIEfA?RAhJ?n>A`O{PUm)5M?ef53i zxhuN_4F2l=kKNWIopMNe$#VHOu8FOCHoOV1Sam__Qpm?$GMBoRH8mQvY|ztNaHVO! z?HRVIMU!IQCB$(ashFl+d1I!*T|tRO*PU4(#0SQt-xv}EusmngmFWyYM>9wNM zbk_65+Rt3q$INH^qV9Q0 z4hltTq3yOy???TT*>`dOhMYrzv;F34MNByHT-4!}`ir+U`|H9sEHsjua^gWst(>L3 zBQIMY!@O0ylU8aaeCAg!4rDRYt9H#v+FO@kl3=B4v-QymG^0z>w#uMxaYUl-5;6Sp0%Di`gluk8_Tuo*Ut~JmbHq? zSzI{r*i*6TcTvsjN>2vSeWwmbJlGTy@$T`-)pyS|t~0uQuZ8nq!A0paCE`cdq}b{v z2&;x)p0MlPmu{Q5(7f~+Rr%A8e!tZqFj0o{K+dABiA&$gul3WvQoF$*+Hd`u6<;&; z5B%B2_u!4wf`WbO$DF72YB^M<3iz#RV4V5#U_@->Dc^`wXU(nmO%XbnX?t>Q;fGsK zwlgdY`ng15)|zCZKLr@()~Ke;l4xbF?y&P_kD#6Dha z#e^?8Z6z@^I)XkuNnhWu<(&JV^;3xT(fOZloqT*&*R4>Yf7#Bxrthy_eDQbj=?4I3BI464mn-l4*gQIPif43R^w~eT zt8Mw7d`FYhjPDlZ6u2i{H}N`BU9aT6?|1c~n?9fSuG`xfq3v?y@H>{A>Ukf_uEehB zy&Jk})%TO__w)F-ZBxIWwg1~K`*i_c#S3p_*XMH`oxdt>m87Nlso069f;LZTG4!_E zk?`qSy@KBf_v#sL+78;!_8mOx7T#QYaf{81OQH7Hs&{FA|0e&Vmm@O&;DWjBtkLS% zw>G&PoWg#%>GLsD0*PDWf@4DL{rI)|ObW7(+oq)rCreAW5 zEqu~$;jk+rq$*4EkzV~;x5vtr>n1eqJ}}!ha&L%!^OEYf&JKZwS6+WvHb=NBEAXhj zjq2I(y!TeIiq`28=2G#}ox%&|CLfQ`-6t65HA&|9^0`-}|J*$2c0p<4$2)x|gc$DM zXTN&zJFn33g|Uxq{+ZqH**3LpFN31D(~nbO&*gX(PJCF`eItQ;;i2;F`}!(gr4+t! zZ^=zyUwdn<<$uYYcWO#24&B;w?<_NWis_A~UENuIvbSQGF5drmH%PSD-!#zHZnf9W zhF1;tXZ4z2dbR&se`>*=cb68Qzhgb|?N;G4>Dg*6SC?@`T3kMPd^tmtTHsqQ$3RE1 zKKaJie_}+Y^}DzIX7W0FPNHXJTq5hS*FR-8JW&2yRe7pzZNfY4rVXV}ZyxoUc8WPZ zsZ)B(4b?q!U(B@0|Nmc7;7m%ERddaPSB?_hIy)-d_n#ApKEuAJY?9a|PAg`~H_pE5 z{0G=iUDxt#Ip1|*>FmI#*4tKdw_T46zsRsQa_Y`dosbU4M&-z$3MHXkY~>HQ>%uPV z;pjQPKK)bc*_OEbj?J;$%sVxmKG-c=_xVR`=_1LVQwk=0_wBz43*VQo5prI2<*nG1 zWqQ(!o3G!y`Y!a)xsHq1tnErT>RcJJi~1J+crR?YbKcL}kE_o7u771cZ~oE`=kAHb z>#Y7~uzV52M7vJSP2J813rjY?WSYKtQ!vY4W4CXwCr=S+Gkx^daZdH(7wk8FUZ1wD zFHOPY%!}ZC|3VAbK6nzjsIz6o-HodH(}Q(hUXErpT2j_IE%xZ+ih0osLbgcHXJCF6 zD!!K~Sy2Cz?@T3+_Cs$ko_yoj-*V<@weEq~Hcd|BIW--dSbxTAbVu|RIxjWg{&X|n z;^~|ezyA+ouZry{XZF4HrnqNyXw4#*c5~rHnW?Y(0@C!P94jlLcWk-PRUlElN%C2T z`_`;FbBnWqGkU&mshq>(bH_@xL8Ck3wP4`ompr~ztY;q2=ezEGQs9t!Z}1~6zSzq4 zH4ewP_66l?Pwa2k`753Fa7JlR(P5>g=Iu`TT$W7%(^UFTUHtRaxy*p~ONO7l&huw% zbA{t&_g>y}RNK{%nKi3uRY2*qf~Uvl&H3<7@l5j{K^>X3Tj%cL=({x4x^n%p%S^u~ zWtm@o`uJ#m{l*9r>&%BU+}Vq(PA#dL7v5{T>q1cY`WrW&*>4K2o4t4UTu$Xr$EL3T zaK>}Z%gh_Go%_ET?0KX8#)dcGb28p|eBVIN=Hs!4j~Q)>`|lXdd!l?c zUPu4N{O_;MY~Ikwtex<0{T`#Yt)ddaa}+o~THMdN{ZKUF$Hrnuoylp>3bywstX#<< z!l3i=-mOQr&-kw~R!p64^S6*q)s4&b?T6a8XRcgf?9{3IdL}LR=L4@4tDY~L-!m?| zsc}8O$I9S0Z%^0L{3)N7UTc$1SW+&ysZ)5#8X zF4q1u+tV6#TdiVFNb*{5{q8c~e8r5T(`G;F{G6TlO4)Pu&cfsK64U+_#R{l3e>ypN zMv`@Or@x$BqnlpG*71Dgfc19~Y_-*|3r*y{=eWrWIzt~<7 z7FBlPlQmezn#Eeikor|B^G#|qkBeJ)x5^R8w^yC3SH8X))jBu+kb6($oXqQDLHv&YRh^^p{F9#{}7B?Ec4HjrZuE zb9v2iOrEjg&IPv>^FAN@^+#x<`W%s2?UTAr&n%G=2o*e{Joo>`@_PT0zfF?@n3k;V z?BMh1&Rg#|D|w^Ro?k()m-9b=bJp2nWsdya)kl5KetdjAaP_36tD_YSdH?do?F#5U zxT?6+a&^uh_f!dt>$XgpQZ-UGL`T&v|#g#b~l>b?N3X%foGU zJwlJBZ(8JYKehDbg^!O6Y?K~8^Z(ZAZ!&3ygnG$Frejh$(^B#^7MGow7QFP|g1urZ zo)z3GxiYKPN6|fSC(RAcGc7*Z%rU##Q`V{1y{4Ww1 zFkdRQ(EOVKf70*V1@X&wFhpui{_(24Ei$6zmu^__=D6;_0;A=RrcJ$gST#o3efFQ1 zM*1nA4hRTX-i!|4u)S3y?pgE9#|G0bxq3GDm=+5D_r05OKPN_CGoa|?#7jX&g*``h z`7is#G?nMWoMxHQMxEuWsye3c-`2)p z{$Fxt?%Q+jX7;5`i5CAFdqPr{-#wBT_Ikomg(;Ry^$!F-2yXecA-3nj&ziXs1?>qD ztJnC{X-dtbWpt7@?-dJg+$@#J4sDb?j1Ohe!tvi``rJIdpY;Y zeO&chyYkD1MYF0+&O~=T{hBaG`B32dB7qN|?21|9as!wCKia_~?QGTVl~N|{+@!GV zTeQK?R8u3d-MmWMG8P_5Shl(~o^Oe!`AQ3`3tL@|HO@7?`t)?-t&e)O@>3?Nzg&02 z_lmMqooUl_q2Keg8d};_YkO96Y(Kem`Mdr}*~i&`>r7=Tik)F+wz@}=0AG<|Nq+|xOjD?fZL3p{yC?e1ZL;<%$v6_B#))= z_}qkLJKeYWhg=VeGrRgq^0QFLAN|b43pYyluXp{|=q&R6@WH?9H}6<>JWo77&ft&r z%WH`;kB>~5WGYxJ-f)sv#fsc*9$T;44S=##W zETgaF?uw2hGI}D7MVFYjT-bL@TeWlQVr2tG1AaEd^`LR0xIrF&KvUS0L(+09%n z6WM275j80n{T(@Ur*YMGzGl;#zIEF^huW8yruok3Q+Pk|)rZrIjIMT=HYTOqn3`ZL zGG+hXZD+kiJQ=ROKNIe!a`Ng*#RW<+fain2I- z&Es@adxgy2+Z73`{U;l;Et&V?nyz^J#3Qqs&!{zRcPa=F$kY}3oVPiTVH^87k?b6o zn%Z+R_cvS1sue!}vY6>nU3@;P!-MB(>74vMz(1~6Dv>rw9%XKq;DgOHP(Cg&W-@YC?y2@XE z>ZX+CJgXwZ5+lm(92M4m{*t|wcXg)1>oehEll_)I=*oL#r_$HmA{{21s`=bZB7V+X zqbn^_eLp?CaoJdtwf|M58*}iVr*qwf&qgn+n8_HKbV*PS}Rwsu90+aja>r>ZOuf9BVj8m2zKC~I=*h=F2o>hI*di<64kQ*M4QPWmk9 z@oMFh=Uy$BSh_wko?H50zVM>5u=ypNFOKizX4xZIbn~&!E5qYY!%p`8WxC~jBWh>t zk?R&6TjQ4$oHMie@sxpMIotL8_f9%@c%Ssmz4-9yz58u9eEKXHl=@=MiwK^4>s87M$5)t9Ex!NA}jadKm)kt7Fxad>8up?p+iwZ1AVN>9B)w)qUYZ zi@03ZoMkK34pS^ysnON=cUkWY`yM;T>y^tzZwKByBpT1VWJ%f42W1bgSiGN*v}a~Q zQq``I=~s6CINTz1=>)gi)GRG_g{zZo0(nKd~n3=an)} z=i@6`VkP&YDer}Jv+l%HiIvyB>1&xbb+%j)+DQ{&d9KPnBJT2#xU z8oR~B`3eWyNeA_n8#!m+^kw>asD>*}`iEvTW8}M~{r=Ay4n)VR_*VaS-YB!M>WJB$ z8&@rN)LFEg;NvO{;b7YLLc+@=nKPl+JK^=YQzf09ObSkC40Y>brqq0&n2vLW#-etgIF>&09KuV~xH2=}ad6xo3WD4Hx)q%`C0pJ$>_yt(SzA?dN+1sONJ1 zo3N&SO7zY>a^IA~r1m$rK6X%H>fe50dF8RI&bKOg?u!3?!TE{1;`XCY3g<&4xTe(I z-1K?#_3MjUdRMb0hi*8;{rbk%y0|54cz1o^Hp;VKYJMTTvYWN1iRs|GmTd)=%^9=& zOJ^x9G?Kg@==gONms90Yfw^;Y*M!7Y8r{$cW7CpYN=l`9JOrNK6Qhkrqv;NaD zD~#Ve{o?%|R-@j|ZZiMbnVFwd`uf8ERojS_X2n)cdfc!n!gK$p`p((JhjhfV+b zsHZGquPg58R6E2b5T_|1wCci)Lq4x2#m~CO`sn(^Ym7{jikEUe=AIS2&1}ia+lmYS zddF^k)M3Lujbr{M!<{!G%6v95ZCxr-aN%D3p(_`UUYO(JYWv+^*-)#XON%Kg)qT6L z{jWcJ7thK+zc-F)&hgA(5$0nh%oT?{wpgY-o8s)gZ)xE1Tke9P>DR^OA8&iA($;As zm7vLR-QoV!zjstWNa)|}EBw^`li^ZFh49f9#ftb%Z*&=4vUDC_GyV0eif3;%G{-$oN_$ex1&Yg8n*l~HnW7$J>A&fJP1%8`vC_BV<&i?My zgj`FZ-)}bwPqgW)dfDGnswDNGdrzW5>&%^Pj~89=>3cS%Nij^ptuFeqQk?IRlPk@S zEOUIlcl~+s*tj$68)ttLHxBpoO4vU8O0|IabHN#pJYP=vdfjMkrp|8H+-1`ulb;{6 znzLckEb~2!3(oI0xHI>fo7hc>p!6E8Z(NpXXL(MA{5%n7@m(UUaq^L_@1Ix29^l(u zb7||1Yky+ieUg~kEX;dm>%0YPHZF*ZFkh(c?HN9yKl_09y=Pf2$92NbufLc+LHE;* z#Y}S@R*5e4xfrzS+y-8@wI{nvsveY{QvCAw&b4eMaeWb^N9Ak>o?iU??aXJ_x6P9O z?w`zB@$JJNqx&*?#~ju=n{%mMXttiwoO07(<)usf=FWb;mt7eH4jhU&eDc;Alaumx zo?b^*f7-})mXkHNX7t%7@!_HU8ud7lpdma-J z@ws*3q4`^EI7)Up$gH`i;p?2f=F2T}lloJdJHGGSW@WZO?&1ye;I7kKa}OEu>g8+t z6zJT!_C}FsE{jtN*Nacj?awhRIl!3T_Go#^Do+i!$&ByY?yv4(FNzFP<4jstayu%B zvFC5#5sxD`GOlf3!TLJ+&OJpBwHyD`GWvf+tvLMri-*osxsdzCrnA%z{93Hpy~eJA zT|DY#cA3GRr@x97g`@;dcqo`pDmyl5&2-}<{XPkgGbVgKpE)tHUL#uWg{`=p%k$#s zeX6zHWws^$xvz2d!OrO^ zn>atH3%1|+_?h>w24jCu0q^n{-NTc$1^22gKgRR>wu(hjtl+lwQ=T6FFTc+sBgpiN zOvtjvxB&e%c8TYD!*1H%IJ&B8-;Sz{xwHP)@6J$2oV&Q&OWL9QtJ}Wb=D(AC8I9eO z*FRl0OWV$GxB2_9Sv)RHi_SR-Y&v_)D_wo1$GK-evN)d0_H`&1Bp)g1-+k=T6+hO= z6@T|meD#5QPoMR-xk<-QUe%a=sw+r_E8M1Z{x8;gmx!zHCuhsNzpc2&;%!2%TF5e$ zpXYTCry3v3unTk8`bFWDV^F?fpZ4{mKV2k|B z{VLaTTwbiGeb@XXyIOLBhoNwB&%drC0eR8#jR#-#F3&?qotPa)SdZ|@j&^971akXEHLF`S+!sK7X{Sz~)7JDP;1Jmw9m+sYjktvIj9Q>8C_-KDwq|C7|>;>36J zXy)**GX1@-pZC|}IUh_m7@aa*(h+}Maz;+m*_{!(f^yDn89od%1YYO9xSM(~Bq#Io}PDJ2e4kHpk!QOq;lCq3V+0 zNoj9QRqDPmcW7>x>wh8JSX5Hhs!-Kh&B=C@HPG5iYF}G*B-6x|(-nQ5Obk5Z?|tmS zT=z}SUP;fi<7o9WDX{qQ&~DNnro?`)LzaOl!aruNJ@L2w!udU)gRFIfH22+ob3GxZ zLTB3qDH)g9ujca3%{{&Kt=Ft&_Tj?sUwWuT-p@ur=b(RVNrC{-c-4>^Rkjf{lo>odACUK?QvJXC3xIWJjuT4RUX^_ zjqH<6b%XMY*GWFPGP~4uTWn`4{N_w<@fk7vwlG~2J!Wwqb0V&~N>C!J4s_9ojUhn<op9mNxYgHG8Vb@3tV~~8TT1qxD!QDfw{Cy=zuI{rN$bi# zRK$M0ZRN6fuIUVUx&HRoe`*zlmY0;Re#xZq?T^1-e$hpt>8`M{ZL@jnW^4vVlWT*V6FAiypF@JrI zD+>2q+^c(2*J0{(-q&m6%l#Xrq%O|QdUF2Wlr3NG$vZB5Qc&(xw*9@NSxCZ^9UHSw zJP8i2x+<-{%qA~w#p<-+kI9q%zK!q<6|_oW_ln_}Kf_gG^-jPhyikSVGWjwpD2V1e<_`CkS?d8d< z*;+Om?>Je`w_wg|CE<%)4ZHWsu8~l%?$fSbT+r>YJzRbE ztv~mK`nD_X7gW-@al&SgYwxz0*9Z1l-rU>5rgVEt?ayzFOfD9lDjLsb$Lvv*YIK%3 zZq4@9;%%f0mqL1TK=Mw8jJ!JJ`F!zQ zhx+FgH+9^8o6Jx?lOb_)%BGvoY^_V(a#t6w-9Bppd-YT|KB)yeGZe2JUy{Qecx&~P zjXyRXIeN;w^MIe6WJG4dqOzd(Qf`i%&Ubx{I2Yb;SvINe&LhsnE)u(6w??k$UU|+< z#IAq3o|(WYH3Q8x_Lol>u6GLC^Dky|p7DX@0u9oybC$)%*5yCHmAS2Rn!Lo!z;83| zB-PC<@4L%mXylZn$!f4I@4k>~m@22vnIe@JOuME(aZul>vd5)hs(P^ZrkEo0^xH4I zl%IL1HbgwoiTZxtI7Kli`iV`XqjpyFvXaPLb(p}bT&@Rwf^0|MW#Oq8^ z^)+W#pN-$tVPwblMmQ=YtMuY6uP^PzB5$(xF6ff`hvQ~!MTX}1Qdn1AbSJ@b~E$kQ6p5nSsa#}>rs&`K($a9<)j@0Qs z^irkUwqn8QRo}jGYRBt|rk5^CJoW9svLkEmY3Q_fMXp+ql`F2l;<4NO@;_dDVjs`H zkT|^Sb;k3prPJn}=aKzv?V`NAyh>r+-?{ttTCJ%6%&xASyd|S>OXE+MCe`kZ$9n2s zP5h}mbtZef{j*iNNz-4g)=S=|R=@80sjSUDJJJ&rB2 z*7JyD7fL3CKie()ch%DwJ^G85cz9m_WTYft!`o__4#5_3ql z@rt;nOU&^`mPNb58^bG)J7sM?6|OONQeg$tl6#vTwa@qZ_-bN~^`@zhKdjC>eUv|a zlH-O+Kja+NZuojk{LJCC-s~~4Jg;&&yrSg49TJUiVwkrq{g?dF3(Sk`PTO|0#2@=s z_qREHqVzFtvsoc_t{xm3@|Ql!8hEI#UUISiTOwaA+bWfa%3l{!@)8Av&AxpO*0WC0 zGiO(P6~=qmKXrBEq1)-xEy4E9@Obzb2r zN#FYPM%9NcExXQC7zW4pqA zdoL#o?CQO?WWU*wM>&UYc~OU^no$;P~KDS0prRz_5Uh(N0 zZf7g(Pk&8>w5oQ$uaMtn z^FZXZY86j&ZOxAG(AbyGClefdJ|tLO+p)jB@WYpbH|{LD`QTC}Ym8f4!D*#0cbpEs zc<|>$qTXidioJYuc>QYf@@iM`@11JZo&J6GB(=r!`M&;Iy|%1OUANgoCjD@fQ>5?C zM|Z9ytEM$=?O7OK&N=yEkn_2fTUyzcpE!``#HLbzs#Y?A@619$btYBav~Gj=sfI64 zWWQk6S#2W5d+dk!mib9jKMGxQZ$94Oac{q4uyKvJ$9cV&%t2 zzaF?fn;V@fVe9k#W^zH|v?E!r+fqq@PeOO&;9MeV=v zrpxkDivF!$TkKXkAGJ|#ut-sI=6$QweBrs!!s|hkFV}U%h0j!bX3~{d7nJ+u(TfQk z$Id3sO@44_O%3x)Hcy!U1cBu5O+~h0-RC zbu+|^*$??2`6SZ#IsU8Do4zA!t@&I!w9e)LGI266*3T-d%8wQdL2iFVp&(bQB zpEu>pJ#0VO5L&O-u`O}lwWN0+5)J=2OWIx3oLXQLX>=j?q2S!o$LF)BY`Ij_tLC+2 zgE+_j9a3-74*&L@AgtB7b+>i{?=thO_jYW`EBSW#Ol9%^?7}kbv94se;hwXGGF|sB zN-cetrTpQ-_pLt-E>B;<9&>AEDPN%YUAbKsHx%43e-&YBFrC$cb@BFS*5I=>mk-Z> zJS9GMmHT{VKlLSomG2f!pZl1*i1W_YMTg(NP6^+#eThxkwfdBjxQz+FET-xO-t$&E zwSHFk_Cs+htDepK?DXV&*wUwQCq6&ema%iM$dj)}R@;>F29<@sNb9@BBPOG4KWpLb zZ(hEC7fd=;ykybMqYmqoY9)m=G7_2QUg@9u>Z`M#B_GqqcXM;^pPp6y_-_taQ;hImN}e$Zr!XkYdJpom2G-l9QE#%)|EEl&)gMYG)+RV^{=-`4xHyxguvSF#fI`->Ct?EYN`tu`WlyYjzCA~)_p|<9iR|&lh;+|QV zSmS$%W0RMD_5H+apX4tez2_C#{L~|acdmbgtlruajO)}YP2VZTDWBY{{mZv;f>Gis zwo(qJS?Buoj$Hca*(51bI_JLS0=M{yBAdk-qN=8JMecAqt9|x1n2PQJKYKXKRzPYSo^Xp&57v6^cK6AuXFPdLv z$rhs?fsSVfx%Yo^NyxqT+t(tPSwDBG@0m(V_H8_AR$bMOuN5XU9leyZrg*`!H5Qz= zUCTeJDLyKYoO^z{|I{>2>FIHQ6yBPZ?}$Gcc4YnM*CvuPX z=*7=*Yxf+DJb%?+Z++~s)+gt8yj;t4CG&~mEMDG;P0yNa@A=*jNL;p5I{JMAqf=If zYbJyI!k;_za}0Pd&d+->P4NAR1mow6=9{f$ySZ)I(KmOOF0Xagn*Gvw%jN5m6H@~s z&d+S*Y`T(=y`*B9;g1=$A9$Y%+K7al_LY3xUgmb0A%*XEfcDd?{mb}vf2f#|Fkfq? z>k6a7z8Rs%ow@&iyfyEsoz{$pw||*tPLA`rk+5{ecc1y&BXf6L$dzqh#*laAn&;_< z4^@7b7+^8Rm_C@Mf2O!fBspU zI%k9AGo1yV$EO`wFXVnjptF?d25w!j5ET6`UuUjTfpCBj7v@T0|TSvsupj?Pm$HfwM|-bQ$1NXP;-5d5zHp~()@G*XWq%*9UR7V({XPBEqol+u z$~pdV(_jC)P}HzcY=U}lXw1^HAC$v*y3>yb99z%W{w8A4x2=ttzY7mN$$KujdZHcc z3s>IxJjt_FkDOj5y!*uNr$Jkv9zH8~w~F1_Ty*-jt3~(IGSnsBlAsGXFnPJhLG>*O1+qSgEC3tr`lwx2FqEBA}tYpLZz zkK`|s9}aMC^xV>&=Tf5iYo_;N*7RK_^L}s%)E+$lWwnIYjjGDTw`(4RbxbVgKYw4* z;l3@`#Yoxv$D8ulH{6_aF8i>PkIq+vS&t%bD{81%_^@>f%ol%|RPyw@o8;!LjPDmZ z%u0{ZVkLycV z8ee@_mJ#>ya+TVpziMkw+}mtfb7o<4Ufj0nZ`O5tN3Ho8&HFXT;^NuZbvyR@*+oa) zIkaVJ@ZQDO?wpvdpjmEFI5#)_=R^&=KQml89jBxVRSR7xm*zZTt-jCm!p!p2r1tz$ z@l}7)ay(P(FW%G%K5V~|)5d8-Mt|2rj#Q3_kgc9BCjt%Gi-bsN8?x%JV2K}pg)+`?hn7WLl&tAb3` z?)Q4~ytuyS)x6`;mh#(weKPX6YaSri=KMmSUUAi9sa)RAvo@y7{oCI+v0tc{y`rW= zJ@84$jURtbzvWrSw=QhcvwPaorCz*^riHT;FK2Ubb^qvd`8d^2`|bO$tj{g>iDiXG zYx0H~%_{x-$#=0Dm(qN_DZB69%Cq8{)u}CY;@Ab%*ifG*i3WySU-$m+n=W`-`k;m6h zoM|=vLyb}Ap@~L&`6G)hcJaSTv6WjY{Bgss#}EETFP7hQ^9r-F+GT0cm5xhzlyo^o z>c#HxJbbd?rrwQ;HtUlvXVwZVy27ih!>nyFpU;JA82l5mz4`Fh^EWe#9VR@D zU3_@&>dc>9Pdw-SPmWDK6e%{}`-hlzmrcQ=gA6P_yH)wzXV^)p1~oj+;AePJ(|XM4 zeWiYi{P(cmrSI3)e^c$?S36Vw=zgxjpQQ{=+nrWb?e?@hQL=mIxhWeM5?TT+^KZ27 zej=K2)_7H0f1a=@&+A}4hq_jk2MzM9DPl5#Gdwksf{yiL7J8MyGkazFF z)OQw@2kj;F)~R%;ZI;k0j6M({>M=3ONwAA=pT5V5-mHz!oXlE+S)9$w^e1vytX?2A z?NH6KT|B#IU8vt9?)l&6;gi5~9C)w1CnNlxaWdty+i7D4% z|JKewm;L!hu6liq+1Y0o^va)cD1CT4`p|y6G)C12`j7t@EM4O1vvbqCYZIn&2G5Uo zGHUCx3sT=Z@07f1rS$Ir&tBOVFRL{eYfp+Nt+ASu^6%-d&hMW)=gftl`_zosE;1`a71{zpp-edrPm*^)nv?zi+y5a2va~UimHm8%HKy zd6l@aN$LImcMNTNyH^~I)MD~DOO(>m|WiaFe_F~^FzE@3vG$issz zG3uw^h3<{S+Qx`RpN?eJU-3yao+V!Im&UN#tu_;+Xk)`k;hK_*z>E_^Plj# zv);CMze%sT_P}RZzVV*;aPbYP-!mG^SrGASuYo~9{ z{Sh0tYR$c~?=p{FT&uCa=I-fhE?HAfly(_kDPyjS?CUhQw{*Sy$d_^Hao7O!oJ+!)hk!d+7u}qHzjK~yIWWGiPdW7nE8ve+dY$}?)X`>xSl88)xj{sfWu>( zWspLTmv#|{c8tX-Gt;F{+0_)P&F*lq{tcdbzoOdRJ3MYLpF^+x{iE_zy1E^{%CFg~ zqyKY`8(;j?fAN!4USD*wpV_~9_ur*C5mlS+h1~rT@H=Z)amn85T}L9mS(YnYWH)~H zqC3FvhQQQ-kZ-HrwxoW@ck@sFD=C|3Vzj}pCz|D`{2fVXaNQ-k9oEADGA+uu1_-tE%f6!dvHU&j`M)ALkM2>#k zrQ3APMV|X-w_=*+`Avsjn@Xj~d8ju|*U39Ox#f1RaH!JzcN-Pzt?o|FHlBC2O5bm> z)PpV01W&Cf$gMu%dhPr5->)Zpowe?J$AP*(>JIN$y?k$$)48MjS;Vxa1*NVNb7Gd^i(`#j<~!>B4ZOL2Zf)Z^-f3osdy^manFJ;W z>Kh);FuJwzii1e{s#9Ly^ZI9W%+O0+qguyamsuHc$Zn$Oqqg%cU-McgsZCoH)G_b( z<3Ap@?_IKguh=4TRA9lfr#Iu@U5u>W-RPM3%izWpg@^M$)beTVJ$xV|fAzD{Q=A%3 z^~-)KoRR$Q+dEyiPdom4!#pk9xdltgx0JqKDy*S3b^5-NjX$q07jt`_vVD!=-&=}* zYS|Ok2@9PQi~4Mo{+N$d+N`N@$@B^CvvS*)?(@80Rmhhnc+yqF|Kl3X4T7^pH8=Wf zo3!tH;<4$67lmEhv~iD!@V=e3TLcv=y;n9g&h^{S_I>Ju{f8@FeK_Tv?Q&nc+}Ysv zI$H<}mzSJD5ysHnDN*7s*uG8tc)1zw)*_<0}Ge<#gQmZ-Bl zn;16~PSr`#`&eJP&BQ6I{D6<5VAAYWCM$X6X8l{hXmTQlqtgHFm z8y`}T|8c>QfS+#O&%XT*SbpHVg7%Jvr=CZ7**7 zamM&gS^R~tKglW+j~_S8)6?*{y>4;cg3|nUu7lDKk59c;`1`b}lh&oDvUlXvJm)`9 z5|}G|I`Fgjz4M#ZxVPSUFC4hT_Q|E+Turkch2}b6+OK_X*)*Zsm;6+}dnYQtopx|) z`_|~Ib+1&@x#wWm8U}IS#Hte-d1*v<80+=CLd#&MVniH*zBm@ zon`XESJl_+?n#TXEQaNuYj*xz6?vg&)2an~lDl6_&M_>KaLbzTGl@C1<7MXcmoMgC z{cYZR>M@&hUA3UsuCgl|FBEUx*zWrIOTb|*UYld{75v}ZZV#)O*KEfA4PMOfDv`Zd5 z%2F8-NfY%%eltJP(Z4F|b&N&6ZNZhjmggtFsyzFPVanYlF*e(M*G_u4R| zKHa5jS`+KEe}5N;xmeidz=eGh`qFMCqC&w=M`EU*k7!!peS^z++NAEeS~q>|F6!s+ zlJ?=P&v$OR-W9*?E^}&h?Je8y*AjPa@Y{Gb^91wd;}=x&R%UcRe zt+^m6>POMF>ATF2^abo`xqid*ns2D?qPvP0lX%asR=vn~!CB?vnZL_kdGv$_YyWVW zcEzrgQBHk+N-5OIu;?;$1Ge7kI+aBp{B)0cod?KU$dA~*eQo*mQxUpw|IW-igW5&QlNB@i9$g(&6>vSne5l*E=%)0m~_g4Nuc2 z@hn^3Tb&(T+9Ag9aQ}HNw}-x>vy{GHQP{mwB>1%G#EwTN{vP0%pyZRdh`IR1!m`wu zYZ~^?_P&)=`j8@i^6s8TGR%HXc9m0v%3eB__-!d+vy$ovE@U%XKX=~5!e>P{8vkV8 ztbdwScJKO}#;^P3H(XZm=w`d&be(B7Z_A#A-976nL)z|DmZ!udPOH>wwiI7-xISXl zLjgsGV=MyJidXh*-Fj<*%k`3TOrhJGKfTDhv&e6w=Ao$?m&7N3Pug*ImyXHu>kbUZ zdkd5AoV|7IMqZ-FpEl1X89b*zhK=X7NOH!?$7@Ox ze5+y%GMUoy7OH1HGMsbg;qQy{bx$nz;7DJ*KOp1hozth|7@ijTWnZl2Z)uq&T&6En zU)B7q&?zT>ZT-{l_XKy8J$5)(?D2oarJIg*4{D{mJJkP*Z}z@(qpPZpwXOJgGw0H=FT%1u$CtfP z-&c5Lb*SUj*6Hs>PZe-{6?0fOgRhMByX(ZV3oE8N#kxszy8lW%`BbJOW>NWtdmIhT zZ&wsr?Qt%>J}P#j}m8{gwR(*5(@Ys4Md+Mf*0IjdffY?Z0!}fv#Ty{VpI`WnyO+^xg+FE_E!haIjx@Wt2^fNMnz|z z+*k2qiK2Ynqcz(b?@ap5zjBdiXF|jAnESyxk!x=^e=%CL{jO|$$+4Jw>;+rCst5m*=wZD(CH-e8(hNem1=L>HochyJqI1 zzE?l_vp6GXy!dZ;$|G}8W9~#f*tP6V?XGQ%YbLtA&8g4p*pm{U#?B>c@nD+J zM~fAfJ6P)!Zf|p6m0Q{UPbxR_(C$;+hP|%L8+inT*X7o9-QHvRN5r`*<#h12t$sh5 zZ}@b|=Bhe}EO0yIu(zUlm2P3Js^(N#o|ignH}1$Sy(AzXe&%xf zt<7bOVb@un*zOEx5wDz5-R9_&xKKyOl>srlimIq%geZPE1g#~Nj zm#Oz`ZM7z{8(kNkRhlnQ_-T{C)>->s@@;UG%U!l^Qr79@=ko8*yOxUbT!@%zIc?v& zL_u{|n@7_Yvd*u5%k%8=!s)*c30WE}i`M z*rx?c-Qokf)I~3QNHLw#J!rcvW%6-X^UaTPO<59i zSfd!7-&kp#`c^V6f3wg5o%u_@@*a9?7^QnsA}dS$AxGe5OZB4)%5x$$k5`sn-ykoL zGV8{&THmN;x77R(T@F2V<%fyosyC%mtlwJlt)1z5*kkVP+3A~9=05MM-8Jutjc*X2 z$9E3#UcaBaR;ym?&s7DwTcS{svdYo9M z{>`+VX(rZQS-4y1MBkyfNBIU*>=pJnhMX>b8^6dpxYbI)t|MU9>y6X49KJI#X0Nfb zmQ-N2rO9bO*I-L2r-ZV#|1Dk8!uPWY_#JgWv#f2h)aS+jvVUE^Guz=yt>}G*_NvQ2 z-p+};a(YkXBfTl%E&nR^OP?2g)LgAQm1D-Cn5HKpN2fJ*x1JDH38}nsV`qJF!58^m zjvr?4@Vyq$H$jk_eg9`GX8Agk$7WlPh*VGaOL!sjHr3esO1Ab>tE00fxc}Cedf}5s z>S2x(U7fyLUI^zOoP2Oz?|jQ#&l2BcgNq%RJKrg!94LQw{Dqs^JAsMkr*^%2az{CY zy>~_D%qKV3?2`SMJ1czSp7P1Z>yFRknHyyh<8j;PP9^Kj;BCoOmUT|od(YNSdGdN% zUc`Z4YtOKoKGHni^{7ST@`d>1k8i9t_-zdRxx&Cic9M47i@#n&%+^X;f%;taq9fXUT#d``P6nnd5_c8+UwO)e1?|_ZC5mltQI*KcsWlavg4O%m6iKc&F%-TuWEX~Sc$s(b7EUp*3kBI&a-{?C`tus|_~WHd>Wf(an&QH<_OtQ&`RAl+9VSclLRz2rm5Mg>HRhv65#AA+`zGbMKb=a$KjpqaR zIX_u^V)-?!FNJifNE2u%Md;uPu_uxO!@cjr{= zpQ<4NNs@*N+KmR~e_o{PA3LgEFd^fOx7I>_`y>4urrO+e*IDjbX0le3%jQS^|F_*2 zj8cRi#zjn?ThTXJYv&QyIag=v#onLr*uTGT?Pcyaf4-$_SqCqA`}(KIhKb3KYk$X_ zt_kq#vOQlD{6pO2ZRH>CgKaTUSMx-so)P5#YIgme^MYvxe^c0kj&R?b=e1&eX@u$C zgq63McuU+$BKO^HF12Qvcvs_#=3WiAOF;r9KDiP-&8rspg>5<3_gKKUbYkP{%b#79 ztzYk1B5B{OT(HMd;M=aL6%GMgOMMo(?QW0qOtIek!MVgmc2&@oc`VmCg;c_fg2bBm zwYE6T+tdHTa6)H~CZF-XOLMOGG+&6D<$GaDXJ%aO+BI67)n~2i`qs@2+M4AP=^3)_ z@|TRhIN4QdMR6a##$Pv_9RH3hmG5aNV`#S++sUm(?^i14%dIZ|Wp;39x!SvHEPQI= z%U;h8?^t(ej?(}9Mcm8=D;iD9pYZ(J^<`b;^0b4&HP>x&&s+cUs&f|DZ@PXKFO!GB zde5Ei@|z@|$=+VaapOwnw?#=Y>kfn$buFB+@oa*WOh|C|gUod--yXhc@UBfi-JkG6 zbpF?(>Brml#ju5^JeN&w`rYa#QR=rKxc}$VXZg>gcNn)hzCLpPh%ke+&VOT%vkJ@h zu3DKc<$YnhTQ~2C=N#fUkxTSjys*WF8*$_ zzN+^_HKLmB*o&`^UL?+bu&sPz-^_m;YyQSFPG(;wHCt(N7=O~6DwDi1%9~e56%i)=y)mX3?xoaLSIVZcVMOb5FvvI{Ajk_B=&#cLP?7F%%QA&VyfBbao)&02# zx6M1Z@#`ke>F1ova(gB3PPu(|y~+EFv35^+bOH}p@^ycBv1HrEl$Yf)=JZ#rj`L_IkUhJFY8@8*KWyz+zH*k4czz|*VWUv0A zg~bjoSxzQASqXkc=I^4KJ(K6WUv}U;_q1;5{6kwuebj!Cw(?PRq=n+Q*+0am zuD=wdJGaht5zBt*?FK6M^{$C;Qj<6Ppxsro@^h-d+vE1ChZ=Ty9Dg2T;a(#6WMAvd z+YK69kH_7W+ris6li}d0WxPTgnKn+3R{U!wSiENQq2-#E+{Fs)A|=h<$JAHoO$be3 zkeaJ*AQzdUkek@-f3B`!o|gFGjZ;>B`0?r7+|vy?PxNP3IWf)7{%yb7<;^orzP?$D zZcf_H+CF2+9_s#w5ua)1q^;v@ zGQZFH9kF3^nRWcKrDpq=oPRpKp+4#Jln2)n|8r=cIMng^#xf=zX6B&+?DbrSGYMCHRLOe|K9FwzI(4#w6*TSGoi(ia`P;gPWn}Jr$YC+ zeCU>$ng7r5t?;<;(89^OHTXuyq{!9Y0UOi~T7BJcblM8tqWS}jVixYUmDPRBvaDDA zE4uyE(#|}&@0Tieox%FK{EeQYRT&#ri}DM^iih2QVYF9&odO4ckC4^Be~v|O3$oMo z!`IgDY+$kbd$M==ZP_PjMa!p_R9Pj4FBdVcOITndG^gWuSbS<(>bfkZs|oJq8jn7= z-k7TXIdfU9$5EHSR*kg6g#wKK+h1?DN0S zC)87xv#Yj#)<3U(-zAS36vlnxspHR#4STSm@q}7^xP|M#+8G~wrrrD^(DIXU>A^R( zTWZfW^!&Rf@Uu<)wXjBW>`!0e;tMlgil!~t<+A-_g|7bbO%G*5e*T*7gf?+kbUu1}fOFS2&Iq?o`S#)Sf!F;UW5dg>B(f0;}6+}qY* z&~n|lK7wK6|6eKYGc@act@au}6g%4HHB&=~bC*)hpUAJPX62d*S*9%sePwbplFzGT z@3zFE++DI46kVh(lj01w&zCZp?YI7u`wxw@Ieu?L7p7iNPZC~LRdD{swZpOUE7L?J zKfBp6NHWAtG%s#tW_rS==90O8!_COg#g7)ashaQGR>Ix5z1jPv{8{52dCnmh-ZI^H z5#M~~dcfzMLRxys!Ovgj%=+_PurDia`_{Kl!#FPZg@iuLSR?pG_k8HwgSwkehsgT8 zj`*=^1+VMI_zfo&BOV+*q_kR|<4tn>@7X5h6YN92Nej;^e70U_&BUX*C$D@j{w7m!_~{<+`T+1cTe8FEyi<><@C2ptX{kR{!X**+!yQCFWWG&*Xri% z>AM;~NgnufNz8WvL(H_hO&{{ka#mcgvQs+t2Yt^bOFJvw_*8eK8`)Z0AjyT_DP`ZElX@ZVfNZaE(CHG2tF4Xaz@Hy*u#52bAt5LS-Gj3cc^)+kTn10p|0(4NMn{jTPJ_(wA`oO>cChK^jzHV2&-Oc;h;_Zc=!_2Dno?ABPsL$NL!f(w(+wz9%8$)&VepydLv~@o>cXu1!iJpE?pJx=(DeT&PrhrTXJ`QT^Q2Emxly z`L2G|{9mDeRoc!P-^mfK(;2zHZp(>%`_PtSrRQDINoxuseO~>nVT}74*Dks4r|7o# zjz>RC%|1ML&a-&GW-pZ=w(&+1H|d=^%sV!p$Ae)sHR@sGMv1N!Q?;RuXTvcfyyQOU}FbMIKWX z@Al+6#D6ttQJ&c2wARLRGmhS130fkwq>$I?XUO&kEV3uJN-$qv_A$RPNy2Vf{j!M? zYdgytO>AOfslXuJqlkCMMW4`^pbR+R| z{dU#f$i0?6*6Z8lr+nB{R<`iMatpCz%)ieWvMkyr@$t)}bq(2@)vjtD4QIOVYw4NF z*mgBj-cwt~;8M-vVA0=991rsp#Pr_Y$}nbboyL9eve>+HWr-hB9WLKknZHmer6X|} zOK9!^#m$F}ewtLLbC_nan~LcDyX>&IV*Y#HhX*Gz+mzhc@-wL@XX2`V$v>uC=@v-h z+If^w`&Y>cp7`pgK8365!gkesu>b#DHrnRh$t>QFOIP%^?Ae*r#JctYkIAJKfAlpp z|M3)AOuwlx!R~-nMe+xW%C-q-Yi5KU)Hk^4@?xfe^!kdZ$9rDHF7oeb&x&|_G=?vt zOP}T2kH(AzM=tj6yq~l0O|6Xc=SbCSfjc@%5>`53)Lx1|urMu=Dkwj!aooHm|CFx7(5%$6JC`cgXnd>A83AnnGi`q3PUp%)W{*9#jXfiFxXn z|J3YH-ZV``R^vT4?Sr%?-hY_OIP3oNsppU6m7KowXwMcwU)8CJo>?0GXAiR&O%nR5 zw#C9H;7Q-qm3K@xDm84IrSzbJ@8ZjZhX>L^ERU~JW6)|Yncu!?bvW0g>BWxBPO}0w zeT(6H>Ua8MPs)q$4}-hQ#M38l+ONocVy3C*NjBDvYfIP*7F*3exv1%-{XyluM)8T2 zANhM`$*)+L5qJEoN?gy%he}J;d0#AaxNNuiy|J9P-X&$PT~{u)`ITAUwCFRpjyRWI z_0}eXC-HvFAL+u2>t#IE%9j-}+*LTYt3ctK+6mh|2Ttbw3R!pO&N=?tPe1GxWafS0 z^l-j%(Y06o$Vt0|9X-rZ_cIoYcbd!+o^`kBm4D@h+VB_5Y1J;jg)CxgU;P&UCZ+Q! z)N|dJ(%;TIzBKx6*nW=J|ZkkZF6NsFBn{v z`4hkOrc3{vl|7Dbf4Y7rKe_U>`A%G+i@>6D`mtd(Q$s@SzUL)QiBrCs7js_n^o2g3 z$15HBoENTDIv26+p;zLJwRc{AiIY5 z%r^<&=ZZU6)454-iD~%n^013LTwlL`K5qf*{M&LbC#G6xt(mlK{%R)XcL#PGvwpkX zv_fdn<1hIe!jv3S|E1o@pC9LV@<43R+py%XTEW}n?96zqR9?)hbNKj-11s0Xv}Kb`$y<44_pC0voEt5cq3 z)cm&BogVc)@Q=ps75oo+oV2)jHdy>{Hj+ECTqtd2(HzMH~S1%oTs!+b1LEb^{ zMbP?FC-ompH#63}X%iLc|EtejP@_3_?u^+hJGOo?mNk&mJT)=nZ1N{na+L5Y-?hXS;2OV z%g@Dw_c6R#t)r%1X%)lfYbd3Zrd)x=>lypD{PdXLSbhHU>zxy)7I^<`+`QoUWLeF?*Bka2<@y}_y`yArzNE+d zJkPfppEs^e_dD|?>e!w&UH{6L#D)48NlW#7==kx>nPXeH!~$3CiOHEiOnHyWFIjbZ zhsavjZ=W5v%-H$OSyOqpV`fXzFP`6dtp5%Eo}I4~wLaH#>FysPo6D*bKOLDPQ*7&# zE&A$Z>>Hgc*Iv6gq$=>weeC$Db5Z@3d8!}p?6v=uc6P&-O*=Hr1UTig?VEGIwRzaI zK9rHj?iJO@w>WRM#OJQq2fgik-?mBKNsHY0fg@UU%Hv%!Gmcb8%zmYs#D2`oc+Jy= z!aGVQh8xO#Rd?Iz80Awr^O^SZuSe7P`ga$}mMLfLQ+1i&Yb*BhO1^49z)hhrS?+5L z3$ME@E!vRO+IQ{8uIZf%r)Qb$`e^0->2QPB%Kfbw z%-@!l+VbD6Kj*h^LRj6gyd~=t7{vD9o4dia&p>)p;infB5_kA5f4+Y9=2WTcHy1Xh zsVmE}&*kbgv*%Blv1a+rBTBc|T1Ng35`QIh$#Nz0Nu4hn=U%ovxZv5GYh`BD4=g<{ ztE6RcW*PO1N`1NRUwzo-#?0!N(`R)Jq!gVtdxzhcCggSd{LII-+toGh9?BDu(35#x zv(BgeQC=RynHAf0{|mX#i}ugBGLKF8z-zUgQ-y+f*9cgwG)j#F%UTeL}YXe|6=wMK^O^ z?W@^iR=Ubqd+LJOqTWk4bt;RmVNNQ49m=gOu~GAhoizM@XRl+a6D7UtjsJ)yjzESStMs2}M z6?F5>Y_~WwUZB zwii8J8oT%8uE|^*veXkdrmnVMBgd?ga^PoOeh6>qL?`y*UE)_94li_SNi4CLw8%$k zx8M5Pr`x`*IW%>7?!L`;bIlitmJ433Keyh0#>`h@a>~0x?n{aUMIKOOOg-z|@7lWI z>Cc^Ch3>LQ?6ve-UPqewIGcQPRyM4-n=J~mb5uA_0G`U2r&$O<-A@06YcFUJv zJ14g`I_9~Sb+~Ok-@CLdVE5t|)6!+QGcNv&Iy`Hu>^;8R#rnGzWi?Ej_3GQ%2Cv35 z_pfYtzJNJQ_E)y5>UNpUcc-o{6ghdU^7Epj8^Zce@3D{c;FDDRaVk}`USQRPn})9) zmh5fnI=ZjIX@c+8ir&itBI1w#o1E3-JD4GDYc12(>#@B_xt?`{k^c;3$4N$wd*}Cd z?K2R2oS^9%xnshs96dwDRLS2m92aGnPxwz2V|*6>)<0~WaZ+B5ti;^uA7A~t)x5nT zVSQ_Zs#aCswXkx|2ey;0REYDN1+9K?+g2vc`nHs$TheNrMH zKiDVpUyJ$rBe}}YTH=qcxqG$iID2zlI{QFSYmU%M5i?98M+^?LQ?b_Q! z_ZDmJ=1g8NpOO3PZog%#WF*v^Lp>Ip<}QfMdKe}&>Hn&Oek;U(2p;|J_2-z|%1IuM zDoO&5544#+tTkoXAf#<%dS~{@$HJMb&O7^B-x=XYT!a>rPPH<9g?*$Mf#U ziq&>Da^Dte&p)If@Mgxjo0m%hesF|r%2^Y#q{lBm@p%yYO|BesxnxTg25 znGl<&M|!>1J#l;OISdIKe|eqHduFttX#E|oFOsB|Et??R9<~KPv>i5`n2kX#S5RM-QP0jw}Gd)(&UqJTTKIB1SLDmu>G21 z#~<1lut`RiJon_i=4)2Y-KxuZ{JeYi&uh;zVEG0y?x_i z=~{(|tM`%?soJXU&XK%*!OO?=<;`}HV2&eIg$-NIisv_~&1nDnLv{MSGlHTWFJ66+ zi0R&b*Q!5tu^rQ?nE3C3izgK2&bT1$9rWSj_3v6Xvx}ZxFrRzudSP42s&1Dz!4KYM zzS{j^U*_??L?<)(IbyXkJ(1lxZ&X`vD74DNc5ma0(a%4e_RK>nrF!4fq!;tzEdPA@ z&hW1w&{FjIw$MNu#osGimd^U{_1nIZbDai7cP|+Jt-mmxLrpC@KB|pV`pP({f ziTEEq!EAn?dEu1Lg3_;oSKjcE>xz9VY4%t(jgKWqZEoGEi^ci7mRAbz&AB6-nSEBv zWQngwc$?tjBfCz{{q-=Hb%n;6%os4!^1HOf}FU>vYqb0OogP~JE` z_hze8s~YYn9+5xh^&&jb9xGI*EN~G%n`IR zb;uRl!cy?FlO@`JgPh(u#z`k^)pzGG#a}(beeh$+sg-v&ch=X<$u*SP%C0lR=*Pdm z-;9{q?3M~#+j7lu_GUS)XWzGMdjEHSdgJ#k3=&O_=WiwLy`Jh@c;~`@J|<7L#J7hZ zH{4z=mYXtb#p-)a$Ho2Ro_qD5J#NDPP*a(Z46D_q1fy)3fpX4Z7C zOR9&>j8ySDH}ueLQ$TPp^NiX>4&*a<{m*U?NA9yJpAlL(a)^ zjcqF~ySeub;9mu3LQC%YCjeIc-gOM zsrSZU=XU#91?k0#n^n5~1f##*XrLvJS^lW4pbmoDG+-+`|;GN{0JlKSTz7QckI@#VO!m~lrf$@jI* ziR{3aDktZ5f7sqK<^5+Rg*iN&OWfSqcgsEDp7O|&d%@n*Q+{i>3I&C(-7e?7Oucrt z{Ug0K8pqEy98+4BDK+EO$F*%)9QmFvUZtH3Tf)8I+^HiEFQ{Ap&|*I>9}(xAwMmox z{hf}p)^-aVf;D@3YucUHCcJ;%b|g&fLCU;6D}=q?ghq>A+c(q4Z@X3bmTqy$gCgzB zjR6xcAHBBt<}JQdgP(J%KVPsqeU86&`*CA2jZI5ya?*4|3O3n9$;H*OzPS3~!kHIr z>SE2EniBVUS8sf2Ilrl5chrwsWrv7^ii-0eK3vTvR}%F1?v?9z|9@!`i)XIzM!BJ1qLJ*}(0lFw6Xk zqY?#OHy4`k6bg%~6y*;!Zddn?`IID?dxIh4gY%1v z?2jYMDq4JY9(i_|FFx1X=C*9bp4UQUTrQuqG{4wCTI+T+JWzi__x@=sShZgLQ2KDV zuX0lN++Oz_zo3PNy$&_fPh<9n<1^$}wEkPfSln(fKmsOMg1f{83l< z^lc~KYvV_bTkc)=nQd{bQQBQPa^D&$m0J_p`wPDAWH)o*40LTe@}+dk(SA8omx76p zZ*T7slNV_JklNdA9G1WH>Y|U^x2|=#samph-YSlH$}B;qiK#BkdY#)>c7K->k<)9t zbV};O4%N;)okt38MGW`3nAe)=k5%;vNCvVh>d z_o6m@?+?@|PSSp!7gN34&q`P=?uF@x-dTJhVb50Ed^pTr-y$G$H@dgO>wWE_YW+q2 zcduTRI6r;fu^ZpzPrvz^BzpTW%Y=k;W(7yVI=J6%7_RZ0|sC&0$V(o&1Yt##UZPr97 z?D$*nT_bcTar!@{ysBfq^3$X*UCZ7P)>6=7f6#+q+u?AhtG zeLQMzVRzTq^Yq-jW8o>{aw8_}ec7DpZqFGLE}YpQrF-p!moKuXN*2`pE+**W=eXC>#DY&fqxGDX;u4Mw?fYOdj7|3UH-UM^W7VCOdna< zUp%?@_wTM-`XAe8+WJ1ola0B%Xp)6Ute&vqgRqHzWPa#*NFKaWcR#C5DPnWouh`YA zC$HcB+%b=J%Xg()J0{-SI$`C?`qwRrD#xSixmO)vUuyPeQJJI<>#e)zh zu}Oz{tIPjvTmNN~MZ#|3U(0lSud%6Gy%7w^J*1Y->2tS?d+F(-18Lpv@=3bgt9nnX zwe}>Nm^Lv8cwf+aC!xQC>Dr{Il-NHvUWF=~-ajg-c3_>=*`Czz(d)T&?`>gIR`514 zKDwv$W=F>FIiUv&nxFjNk}Eyq_({2Y@@xN|T)8vFE5PvEZ)4t{ z{C3cd^t@h=>8f(igPAs2UvAj)2CdAAdThyzfSz zOB}b>-G4pDb9-txulkhG8JSl5|8W(cF?-1|sa88)qjc}|Z6))1<3f72GB{o>b2FH= z$=YOPEl;eQjkDb!ziF;YG7b}uE%yA}^U~UAij8Z#QhA78>-OU7m-qADx^+wae!$NNr>k31G-p4)yuk0OjSgG9#m)%ZBj;ro{z zuj$dtHCDeCPn5m6*<dh8U5XWWw?bAA%| zccy;!`&eG_%o%3ovntB#qdLW3EwJI~U9x4hYPX%n#>1DbO#{9ZCr+J>aZ1TMHIpcWv*66DmW?k`D*6!;2+x}Mm;S=3MYJn;oGMo=~%dg0r zw0vfr9OtkM}(e@p>35wb9EbjN^FkuA^LwWJ~97tW%K|`&e=zZQVbI zv}ayHk6Nc+)%Eakkj;Hz6zA;7;m500vG=dZkuOt4I{f3Fa4cq+cKTLT&>YuEoJoKB zFF)TmMNwfZ-(B^yudX$$p4Jr?eR%WN6P4!X`<*)2yp7kYCUDG|TbNqTj+RZS8(Q6-gEN2e~wxjKIG`Kv9Ygvd0pVWZT#La{fX!PPFWRe zQniig&7p!1=jX1qUgPmb=vKqhX>tAk`)+3+611&7&B^Gg`S#JiDX+fU_{|7}^|0Jj_WO|XBi_)R zXDU5kG(>Pl&R6>LBE9wJj4R5VyP{vDdu`=h+uxUFoaNmcz@C3~;SPpJp-F*-{%!AV zb866`z(Fd2*d=TO^^+(5@%eHub2E(a%zzoy@Dcv!6|K zn-%qDL+u3K1(jxYDw!#lSIiB+wp)jP%BoE})^;0T@?X1KEp*lMw4|rJqNiRNT>EUA zu-zvxQ?+(dPS)RfbA_CZ%7t!EoE)ds%U(B2VZrRpGS?qmEOf~AQ=cNc_pA6_z8mKr z9r*qGUSq1UnP|O|{h=v}mK$%xbZ9me!Ne-!I$5rwK8a{ z@Ai^6_rI$AePYYPmKV_{!g>gmYFsd{)r6lvDYS*_NlfKA%>tQnl?r z+i9OAS*Cga(z=z4KG((u?za%!s$L+qIciqI=C2;iQ{vY@WT>;hcUd*`_#8f&8u2Ro z0!v%&&|ZhLhSzhKc{;y(_|>}T^!XFoDsP@2*ZVDFezmT#{i<;1uaxdZN2WWMuB@50 zLP&H1XVHF(@7~>Ooy-dE`b?ki{QP(Hjyo|%$L{o|SaY9dvwoaj+aRv<*043h>G{;R zD;RRiGWq?E2#UWy@L|Cb{~GJOr90QEa{R1w|4_etN?g%Q`!AhSHwFEU&0;wjpTjIv z7r97f#estt6s31WJ=~%1>&$R!-T%JB)>~WWzgK%CxFWD_rSbed-;H(|PO08AJ3y;< z;r%!2(rUYm=JhRp=ws)oLZiaa+KI_j1bY9sY~`R;EaAa=YaCC3?p7?VC7j z5*}Dfe03xn|(AR^{e=od74#!k#G9< zK6T~!Uty-QY)>Rht{>7VX)HV?^nmwWrwiv}b|W3-C(r6UcmFxE#Ln!|vUEY^?P?c; zy5}GGeRAdMt*z{#U;OTGld3n3Onv)C=z-zB&{W=r<#B8aEMAp{pL2U6vnY4M_4zuP zl7***dxH~=zw>C;U7z3V`!@7}RHTK>ONGfMW;t9hHc8Gtw1`JJAwsMCZ|&yluGS@s z{@%ZCI$!lF^NaaL8!s5~+J*-H*ZRA0*N^#r50sTyWKecWMfA2h1%?Mo7_y!YMnm& zKvz+JN|;#vueQPtNo8qcskS{ob2Rv8omzB2gfWhFuk^Z*cZ=;by4$>0?3f=|!6wM? zk}qkoV7#|^ew?)1+xJmBq`eYV&VD(x{nR853t7Jy>8?2n?h4^Mbr@G4n=QYSdx2K= zjI)ONi!Qh8?@4UFC?YR-hhd^a(}HL%2|hcm>2dt~9bY{DRla_;PeI?#hH63f0Fy71 zjc2_*`decDxxQ6K;U@EVO3t5RZOnYjy8YPe(1}i*6EYsjZ7AT5-If1r@=DH4yNlm_ z&}fo)6@$Ji*F75bjby186uma&oQ$K4Bkzf5`eS}W*|{C}?k zMKN0kDZ6FN9vU%C#@%yE)-L&AF=c|(#eOM=e&2QLOfLznbYI76_GX{{sftpy{^B_k zr4Q}z_h4P>BtN+F z_^8H&Ri|GD3x1G6B_@?CH><>4>UScE^a$xS)t-k^tirZ+UxCmcBgx>JXI>I=-(h9Ic-vX zOH11U_0Zp2OaBOM)SDl6d*^TVb8PpwK9&FV;lcmdvI|UltZ!=>&rP{)VlE)T7TdLQ zUWEJlIsZ0S9Nfx!F?RZ~qMN&}9vA!9IB)-JHO=5}-S_f-tG^13Ha-7}rQwpuQcsE3 zHveu-&vJICJd&0XUHwz!#_3s$m&k+#-h8XJ%`iA+U%xC%{Lf9UJ6SpwS{u#3AaF?} zm1{bO+6_I{ug?p3*uuM=l~S4(XTm zllIF$4ES`mzvtu9R}ZJDvY*Xh)0rQ5HebZ}b$aJ}h6jh+pNmUN$UCadQ=T?^AG5rh z!$z~KJKZG$ZSrpHE99$9^k35FI^m7pjN7Yjx9e;;#(bKuEXUL}aECM72S>$kPA`LN zcB<&`I|?3Dx&4Y~mcmoM)oY&~-OQ2P@Fu`rYt_}}wGXNiy}s*gx>OTABedYT;o^;( zA3gpT=gBR6@^WcpqmO~@cK5)hhpsMDjWn{-4<+aSJ>=i_P0sRqh;4z>%a9%3N`gKU zo3`JJJUYR1o$jk=p2dwzx7^XS4H9c&x;fYH>$>v2+N%|Bwmg^c{eH`L_v7Buuj2Iu zY!5fQYdQ37w*b$IFG=$`ZP)~tc^CLa_4)8#^VF@nepI>hyPlt!%r3d$nLO2E4$<$5 zzU%F^elYFqKW(|FUz}b#9;tfvAK0u8FUvXWZxq@)J2p%B`t}MX*{;N2*II5~EZ{Ut z&uY`0wd3}sbq!DXq^~?r`5AoGp-@oa-Q8j{i-P2hG*r&h_YL5r_OG)l&L{+Xkwxkk3<_{rYrw-x0w zDprx9>)xg=E8nuF>Am(8{?-#V<@cA}5R0;%%&}zGif>0wuUinycgZ;6W?B6LZ=0F# zAE*4=DBza1y8Fzj9M@-4{P!oX&}3zqm-kWmF7xqK{rq)zy{<(i&iwiB{#!0S7ESx! z#lOFV)lV;G)H?H0ul4`R_c78tX4h(_Sa3!i&Yx!9%YMy-?O8_8oA!Xma@%737+LBc z>i^zcHt8(W%JLY!4f@NM2!w6u+47}o-NY+?N!%F)my;&n5?L-hKlka8`Ry5R11|6K z^*^y7aijM9<#(g6HND}O{OPSe>)na*q7Ow67`ny>Jdrj$u!AqLuI-7_%_mGuNx$^k zl`0=TKm0iG*1b@^=2G~<>#pdlog9+6AL=UB#NV$B`#d+K?rV<~|BM)6 zN!AX(gjp4bIK-k1vsb^^Xnn`_%hf;b2ev#v=^t=V{QuYEOHRcG%BJb}RUC0^JC|D= zHKVWkL3D}3Hn&ysmqae}ES|Siq@iwxY-IOLv*Y@8i=)1Cw;z}EUb*8dhvGhkw#%wN z|BA)G-PoRB8P3pq^ZD{G75fxd%&vIr^kH7~M~&Di+D(!9tOwFVKWHXq+{iwmet2*G z{T=D8CC!&jf)dp-*KHO*yo14|>SN2BC$A3#yGipSDk}J$YVX~ddbmF>>Bamh|F+JXG2v_UONUt(WSCa2o1~y_6qWMMYfjrM zqui~&-+6QR(gc*&1*TL@cDb9k@LQqLgIUEUQ|$EaE;3j!eNtriu?5!71zB-iyscNJ zIH}LDy+6_B;?;YN^Ct40Tex(2gZ1&16aN(5nvww=!*qjoW19-c;%U|!oi0_rH{W8-m&}%+udUe zcDmlEyvvv6ns}tFyFE5?-ENK^uNNhEGgVZorr3PXfBZ=9weO5<0lSO0?KcN&DRg!H z3DckX!sox8^5W&Su}izYPn>o2y7;5tigW7b8|(PA>(33mxpS8L&2LK?4(9thD*s<9 z%(ZP<@2xE^I?*C(+qn-FX!t9aKaja)Q$G3ML#F48mE4o^*v;nYZ#b~;@vUuNGuN%J zPUJkZ*wtr&)YF?w7EiCU7CbF0x+7Su*qWiV&&HJbE9YMqyNex}ORYn-Oq*)1xClw` zzg#W9b52az9lHQ~N5eM5SmUkY^%d`m6{rxLQV9L>DGTUC9tC!i3mJI;%8Ye>l 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/src/internal.c b/src/internal.c index 1d9c1273a3..9a80fd7b06 100644 --- a/src/internal.c +++ b/src/internal.c @@ -14249,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) { @@ -14594,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) { diff --git a/tests/api/test_lms_xmss.c b/tests/api/test_lms_xmss.c index f99b1ed574..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)) @@ -644,219 +650,32 @@ static int rfc9802_xmss_import_negative(void) } #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); -#if !defined(WOLFSSL_XMSS_MIN_HEIGHT) || (WOLFSSL_XMSS_MIN_HEIGHT <= 10) - ExpectIntEQ(wolfSSL_CertManagerVerifyBuffer(cm, leafBuf, (long)leafLen, - WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS); -#endif - - 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 @@ -866,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. */ @@ -910,57 +706,551 @@ int test_rfc9802_xmss_x509_verify(void) { EXPECT_DECLS; #if defined(WOLFSSL_HAVE_XMSS) -#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) -#if (!defined(WOLFSSL_XMSS_MIN_HEIGHT) || (WOLFSSL_XMSS_MIN_HEIGHT <= 16)) - static const char* const xmssFiles[] = { -#if (!defined(WOLFSSL_XMSS_MAX_HEIGHT) || (WOLFSSL_XMSS_MAX_HEIGHT >= 10)) && \ - (!defined(WOLFSSL_XMSS_MIN_HEIGHT) || (WOLFSSL_XMSS_MIN_HEIGHT <= 10)) - "./certs/xmss/bc_xmss_sha2_10_256_root.der", -#endif -#if (!defined(WOLFSSL_XMSS_MAX_HEIGHT) || (WOLFSSL_XMSS_MAX_HEIGHT >= 16)) && \ - (!defined(WOLFSSL_XMSS_MIN_HEIGHT) || (WOLFSSL_XMSS_MIN_HEIGHT <= 16)) - "./certs/xmss/bc_xmss_sha2_16_256_root.der", -#endif - }; -#endif -#if (!defined(WOLFSSL_XMSS_MAX_HEIGHT) || (WOLFSSL_XMSS_MAX_HEIGHT >= 20)) && \ - (!defined(WOLFSSL_XMSS_MIN_HEIGHT) || (WOLFSSL_XMSS_MIN_HEIGHT <= 40)) - static const char* const xmssmtFiles[] = { -#if (!defined(WOLFSSL_XMSS_MAX_HEIGHT) || (WOLFSSL_XMSS_MAX_HEIGHT >= 20)) && \ - (!defined(WOLFSSL_XMSS_MIN_HEIGHT) || (WOLFSSL_XMSS_MIN_HEIGHT <= 20)) - "./certs/xmss/bc_xmssmt_sha2_20_2_256_root.der", - "./certs/xmss/bc_xmssmt_sha2_20_4_256_root.der", -#endif -#if (!defined(WOLFSSL_XMSS_MAX_HEIGHT) || (WOLFSSL_XMSS_MAX_HEIGHT >= 40)) && \ - (!defined(WOLFSSL_XMSS_MIN_HEIGHT) || (WOLFSSL_XMSS_MIN_HEIGHT <= 40)) - "./certs/xmss/bc_xmssmt_sha2_40_8_256_root.der", -#endif - }; -#endif -#if (!defined(WOLFSSL_XMSS_MIN_HEIGHT) || (WOLFSSL_XMSS_MIN_HEIGHT <= 16)) || \ - ((!defined(WOLFSSL_XMSS_MAX_HEIGHT) || (WOLFSSL_XMSS_MAX_HEIGHT >= 20)) && \ - (!defined(WOLFSSL_XMSS_MIN_HEIGHT) || (WOLFSSL_XMSS_MIN_HEIGHT <= 40))) - size_t i; -#endif -#if (!defined(WOLFSSL_XMSS_MIN_HEIGHT) || (WOLFSSL_XMSS_MIN_HEIGHT <= 16)) - for (i = 0; i < sizeof(xmssFiles) / sizeof(xmssFiles[0]); i++) { - ExpectIntEQ(rfc9802_verify_one_cert(xmssFiles[i], - XMSSk, CTC_XMSS), TEST_SUCCESS); - } -#endif -#if (!defined(WOLFSSL_XMSS_MAX_HEIGHT) || (WOLFSSL_XMSS_MAX_HEIGHT >= 20)) && \ - (!defined(WOLFSSL_XMSS_MIN_HEIGHT) || (WOLFSSL_XMSS_MIN_HEIGHT <= 40)) - for (i = 0; i < sizeof(xmssmtFiles) / sizeof(xmssmtFiles[0]); i++) { - ExpectIntEQ(rfc9802_verify_one_cert(xmssmtFiles[i], - XMSSMTk, CTC_XMSSMT), TEST_SUCCESS); - } -#endif - 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/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 00be607506..a80ec115b5 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 @@ -13065,6 +13065,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. */ @@ -27393,7 +27469,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; @@ -27406,6 +27483,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 @@ -27489,6 +27568,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; @@ -28291,8 +28387,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; @@ -28305,6 +28401,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; @@ -28398,6 +28496,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; @@ -28545,7 +28663,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); @@ -28562,6 +28681,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); @@ -28629,6 +28750,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; } @@ -28677,7 +28808,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) { @@ -28864,7 +28995,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. */ @@ -28909,6 +29040,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; @@ -28942,10 +29075,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 */ @@ -28954,7 +29105,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); } @@ -29022,7 +29173,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; @@ -29038,6 +29189,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); @@ -29105,6 +29258,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; } @@ -29127,7 +29290,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) { @@ -29247,7 +29410,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)) { @@ -29281,6 +29444,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; @@ -29314,10 +29479,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 @@ -29325,7 +29508,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 */ @@ -29472,13 +29655,20 @@ 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; void* heap = NULL; + /* The signature buffer must hold the largest signature any supported key + * type can produce. LMS/XMSS signatures are parameter-dependent and can + * exceed MAX_ENCODED_SIG_SZ, so size them from the key at runtime. */ + word32 maxSigSz = MAX_ENCODED_SIG_SZ; CertSignCtx certSignCtx_lcl; CertSignCtx* certSignCtx = &certSignCtx_lcl; + (void)lmsKey; + (void)xmssKey; + XMEMSET(certSignCtx, 0, sizeof(*certSignCtx)); if (requestSz < 0) @@ -29505,19 +29695,64 @@ static int SignCert(int requestSz, int sType, byte* buf, word32 buffSz, return NOT_COMPILED_IN; #endif /* HAVE_ECC */ } +#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) + else if (lmsKey) { + word32 lmsSigSz = 0; + /* The signature algorithm OID is written from sType. Reject a + * mismatch so we never emit a cert whose signatureAlgorithm + * contradicts its HSS/LMS public key. */ + if (sType != CTC_HSS_LMS) { + WOLFSSL_MSG("LMS key requires CTC_HSS_LMS signature type"); + return ALGO_ID_E; + } + heap = lmsKey->heap; + if (wc_LmsKey_GetSigLen(lmsKey, &lmsSigSz) != 0) + return BAD_FUNC_ARG; + if (lmsSigSz > maxSigSz) + maxSigSz = lmsSigSz; + } +#endif +#if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY) + else if (xmssKey) { + word32 xmssSigSz = 0; + /* sType must match the tree variant (XMSS vs XMSS^MT) so the + * signatureAlgorithm OID agrees with the XMSS public key OID that + * MakeAnyCert derived from key->is_xmssmt. */ + if (xmssKey->is_xmssmt ? (sType != CTC_XMSSMT) + : (sType != CTC_XMSS)) { + WOLFSSL_MSG("XMSS signature type does not match key variant"); + return ALGO_ID_E; + } + heap = xmssKey->heap; + if (wc_XmssKey_GetSigLen(xmssKey, &xmssSigSz) != 0) + return BAD_FUNC_ARG; + if (xmssSigSz > maxSigSz) + maxSigSz = xmssSigSz; + } +#endif #ifndef WOLFSSL_NO_MALLOC if (certSignCtx->sig == NULL) { - certSignCtx->sig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, heap, + certSignCtx->sig = (byte*)XMALLOC(maxSigSz, heap, DYNAMIC_TYPE_TMP_BUFFER); if (certSignCtx->sig == NULL) return MEMORY_E; } +#else + /* Without dynamic memory the signature buffer is a fixed + * MAX_ENCODED_SIG_SZ array in CertSignCtx. LMS/XMSS signatures are + * parameter-dependent and can be larger, so reject rather than overflow + * the fixed buffer. */ + if (maxSigSz > MAX_ENCODED_SIG_SZ) { + WOLFSSL_MSG("LMS/XMSS 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); + 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 @@ -29663,7 +29898,7 @@ int wc_MakeSigWithBitStr(byte *sig, int sigSz, int sType, byte* buf, ret = MakeSignature(certSignCtx, buf, (word32)bufSz, certSignCtx->sig, MAX_ENCODED_SIG_SZ, rsaKey, eccKey, ed25519Key, ed448Key, - falconKey, mldsaKey, slhDsaKey, rng, (word32)sType, heap); + 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 @@ -29723,6 +29958,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; @@ -29754,16 +29991,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 @@ -34179,7 +34435,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; @@ -36397,7 +36653,7 @@ int wc_SignCRL_ex(const byte* tbsBuf, int tbsSz, int sType, /* 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); + 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 f4b05445c9..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) diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index 70f823fc80..bf8e15fa53 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -2773,7 +2773,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/settings.h b/wolfssl/wolfcrypt/settings.h index 2226d541f1..e574273d74 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -3379,7 +3379,9 @@ (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 @@ -3389,7 +3391,9 @@ (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 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_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); From 09b288000cf48ad61bc48a24454035cfecda528f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Mon, 8 Jun 2026 20:14:46 +0200 Subject: [PATCH 111/118] Size cert signature buffers from the key and check sig type vs key MAX_ENCODED_SIG_SZ grows to ~50KB once SLH-DSA is enabled, yet it was used to size PKCS#1/signature scratch and output buffers across the library, wasting stack and heap even for classic RSA/ECC operations. - Add MAX_ENCODED_CLASSIC_SIG_SZ for RSA/DSA/ECC DigestInfo buffers that can never hold a PQC signature. - Size the certificate/CSR signing output buffer from the signing key at runtime instead of the worst-case macro. - Add overridable WOLFSSL_MAX_SIG_SZ for the WOLFSSL_NO_MALLOC buffer. - Reject a signature type that does not match the signing key. --- src/internal.c | 34 ++- src/pk_rsa.c | 8 +- tests/api.c | 19 ++ wolfcrypt/src/asn.c | 441 +++++++++++++++++++++++++++++++------- wolfcrypt/src/signature.c | 8 +- wolfssl/wolfcrypt/asn.h | 4 +- wolfssl/wolfcrypt/types.h | 54 +++-- 7 files changed, 459 insertions(+), 109 deletions(-) diff --git a/src/internal.c b/src/internal.c index 9a80fd7b06..e7b5a2edd7 100644 --- a/src/internal.c +++ b/src/internal.c @@ -33825,12 +33825,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)); @@ -33840,7 +33842,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, @@ -35141,9 +35145,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); @@ -36354,8 +36363,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 = @@ -39489,10 +39499,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); @@ -39507,7 +39519,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; } diff --git a/src/pk_rsa.c b/src/pk_rsa.c index 685fdb9fd1..63ab70abd2 100644 --- a/src/pk_rsa.c +++ b/src/pk_rsa.c @@ -3117,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; @@ -3158,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; @@ -3314,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/tests/api.c b/tests/api.c index 9cac424dca..31c9a02a06 100644 --- a/tests/api.c +++ b/tests/api.c @@ -23304,6 +23304,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); @@ -23390,6 +23395,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); @@ -24329,6 +24339,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)); diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index a80ec115b5..96ee114b33 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -17030,7 +17030,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); } @@ -17058,7 +17060,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); } @@ -17747,13 +17749,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; @@ -28380,6 +28384,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 @@ -29658,29 +29926,25 @@ static int SignCert(int requestSz, int sType, byte* buf, word32 buffSz, LmsKey* lmsKey, XmssKey* xmssKey, WC_RNG* rng) { int sigSz = 0; + int ret; void* heap = NULL; - /* The signature buffer must hold the largest signature any supported key - * type can produce. LMS/XMSS signatures are parameter-dependent and can - * exceed MAX_ENCODED_SIG_SZ, so size them from the key at runtime. */ - word32 maxSigSz = MAX_ENCODED_SIG_SZ; + /* The signature buffer is sized from the key at runtime. */ + int maxSigSz; CertSignCtx certSignCtx_lcl; CertSignCtx* certSignCtx = &certSignCtx_lcl; - (void)lmsKey; - (void)xmssKey; - XMEMSET(certSignCtx, 0, sizeof(*certSignCtx)); 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 */ @@ -29690,67 +29954,49 @@ 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 */ } -#if defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY) - else if (lmsKey) { - word32 lmsSigSz = 0; - /* The signature algorithm OID is written from sType. Reject a - * mismatch so we never emit a cert whose signatureAlgorithm - * contradicts its HSS/LMS public key. */ - if (sType != CTC_HSS_LMS) { - WOLFSSL_MSG("LMS key requires CTC_HSS_LMS signature type"); - return ALGO_ID_E; - } - heap = lmsKey->heap; - if (wc_LmsKey_GetSigLen(lmsKey, &lmsSigSz) != 0) - return BAD_FUNC_ARG; - if (lmsSigSz > maxSigSz) - maxSigSz = lmsSigSz; + 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; } -#endif -#if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY) - else if (xmssKey) { - word32 xmssSigSz = 0; - /* sType must match the tree variant (XMSS vs XMSS^MT) so the - * signatureAlgorithm OID agrees with the XMSS public key OID that - * MakeAnyCert derived from key->is_xmssmt. */ - if (xmssKey->is_xmssmt ? (sType != CTC_XMSSMT) - : (sType != CTC_XMSS)) { - WOLFSSL_MSG("XMSS signature type does not match key variant"); - return ALGO_ID_E; - } - heap = xmssKey->heap; - if (wc_XmssKey_GetSigLen(xmssKey, &xmssSigSz) != 0) - return BAD_FUNC_ARG; - if (xmssSigSz > maxSigSz) - maxSigSz = xmssSigSz; - } -#endif + + /* 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(maxSigSz, 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 - * MAX_ENCODED_SIG_SZ array in CertSignCtx. LMS/XMSS signatures are + * 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 (maxSigSz > MAX_ENCODED_SIG_SZ) { - WOLFSSL_MSG("LMS/XMSS signature larger than fixed CertSignCtx 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, - maxSigSz, rsaKey, eccKey, ed25519Key, ed448Key, + (word32)maxSigSz, rsaKey, eccKey, ed25519Key, ed448Key, falconKey, mldsaKey, slhDsaKey, lmsKey, xmssKey, rng, (word32)sType, heap); #ifdef WOLFSSL_ASYNC_CRYPT @@ -29805,6 +30051,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; @@ -29865,13 +30112,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 */ @@ -29881,23 +30128,45 @@ 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, + (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)) { @@ -30050,6 +30319,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; @@ -30076,22 +30346,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 @@ -36611,6 +36899,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; @@ -36622,38 +36911,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, 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/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/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index bf8e15fa53..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 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]; From c76c83258c9a22926f855c8b3eb92e916ed0ae2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Mon, 8 Jun 2026 07:50:03 +0200 Subject: [PATCH 112/118] Ensure a key is set for ARC4 operations Fixes F-5378 --- doc/dox_comments/header_files/arc4.h | 5 +++- tests/api/test_arc4.c | 37 ++++++++++++++++++++++++++++ tests/api/test_arc4.h | 2 ++ tests/api/test_ossl_cipher.c | 4 ++- wolfcrypt/src/arc4.c | 8 ++++++ wolfssl/openssl/rc4.h | 4 +-- wolfssl/wolfcrypt/arc4.h | 1 + 7 files changed, 57 insertions(+), 4 deletions(-) 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/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_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/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/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/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, From c611a22b2f3f96209c068b510f724a7436b9b2f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Mon, 8 Jun 2026 08:04:40 +0200 Subject: [PATCH 113/118] Ensure a key is set for DES3 operations Fixes F-5379 --- doc/dox_comments/header_files/des3.h | 8 ++++ tests/api/test_des3.c | 61 ++++++++++++++++++++++++++++ tests/api/test_des3.h | 12 +++--- wolfcrypt/src/des3.c | 11 +++++ wolfssl/wolfcrypt/des3.h | 1 + 5 files changed, 88 insertions(+), 5 deletions(-) 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/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/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/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 From 9c60d87abc5a2979bfd763d0352b4b817f527beb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Mon, 8 Jun 2026 08:13:57 +0200 Subject: [PATCH 114/118] Fix minor CAVIUM issues Fixes F-4441 and F-4442 --- wolfcrypt/src/port/cavium/cavium_nitrox.c | 28 +++++++++++++++-------- 1 file changed, 18 insertions(+), 10 deletions(-) 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; } From c01152d35ab06139307f793abbc65d77c720016d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Mon, 8 Jun 2026 08:19:13 +0200 Subject: [PATCH 115/118] Minor fix in liboqs GetRandomData Fixes F-4443 --- wolfcrypt/src/port/liboqs/liboqs.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) 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; } } From e1413a177f487926401426c29052de8be3bc2094 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Mon, 8 Jun 2026 09:20:36 +0200 Subject: [PATCH 116/118] Add missing ForceZero() calls Fixes F-5437 and F-5438 --- wolfcrypt/src/asn.c | 35 +++++++++++++---------------------- wolfcrypt/src/wc_mldsa.c | 27 ++++++++++++++++++++++++--- 2 files changed, 37 insertions(+), 25 deletions(-) diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 00be607506..35c07d38b6 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -31973,10 +31973,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; @@ -31984,42 +31981,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; } diff --git a/wolfcrypt/src/wc_mldsa.c b/wolfcrypt/src/wc_mldsa.c index 3e08dad88a..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; From e407dba23b108fd3820a114032c8b33f2d962914 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Mon, 8 Jun 2026 11:07:38 +0200 Subject: [PATCH 117/118] Improve supported_groups handling Fixes F-4891 --- src/tls.c | 17 +++++++- tests/api.c | 1 + tests/api/test_tls_ext.c | 92 ++++++++++++++++++++++++++++++++++++++++ tests/api/test_tls_ext.h | 1 + 4 files changed, 109 insertions(+), 2 deletions(-) diff --git a/src/tls.c b/src/tls.c index 411a97271e..18a8024a24 100644 --- a/src/tls.c +++ b/src/tls.c @@ -5232,8 +5232,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) { @@ -5250,6 +5255,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 */ diff --git a/tests/api.c b/tests/api.c index 9cac424dca..0ec468a2a0 100644 --- a/tests/api.c +++ b/tests/api.c @@ -35141,6 +35141,7 @@ TEST_CASE testCases[] = { 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_wolfSSL_wolfSSL_UseSecureRenegotiation), TEST_DECL(test_wolfSSL_clear_secure_renegotiation), TEST_DECL(test_wolfSSL_SCR_Reconnect), diff --git a/tests/api/test_tls_ext.c b/tests/api/test_tls_ext.c index 49edaf29f5..bcb9d81407 100644 --- a/tests/api/test_tls_ext.c +++ b/tests/api/test_tls_ext.c @@ -1071,3 +1071,95 @@ int test_TLSX_ALPN_server_response_count(void) #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_server_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(); +} diff --git a/tests/api/test_tls_ext.h b/tests/api/test_tls_ext.h index dc617e2d62..5bbd8ffc27 100644 --- a/tests/api/test_tls_ext.h +++ b/tests/api/test_tls_ext.h @@ -37,5 +37,6 @@ 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); #endif /* TESTS_API_TEST_TLS_EMS_H */ From 11270fc46569869fa446914f23763140a1458e62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Mon, 8 Jun 2026 12:25:28 +0200 Subject: [PATCH 118/118] Check for EC_PF_UNCOMPRESSED in TLS 1.2 ClientHello Fixes F-4892 --- src/internal.c | 27 ++++++++++ src/tls.c | 20 ++++++++ tests/api.c | 1 + tests/api/test_tls.c | 103 +++++++++++++++++++++++++++++++++++++++ tests/api/test_tls.h | 5 ++ tests/api/test_tls_ext.c | 79 +++++++++++++++++++++++++++++- tests/api/test_tls_ext.h | 1 + wolfssl/internal.h | 9 +++- 8 files changed, 243 insertions(+), 2 deletions(-) diff --git a/src/internal.c b/src/internal.c index 1d9c1273a3..16869c0bcc 100644 --- a/src/internal.c +++ b/src/internal.c @@ -38861,6 +38861,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 @@ -39073,6 +39081,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 && diff --git a/src/tls.c b/src/tls.c index 18a8024a24..2fa6abd611 100644 --- a/src/tls.c +++ b/src/tls.c @@ -5667,6 +5667,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); diff --git a/tests/api.c b/tests/api.c index 0ec468a2a0..55f8f0f3d0 100644 --- a/tests/api.c +++ b/tests/api.c @@ -35142,6 +35142,7 @@ TEST_CASE testCases[] = { 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), diff --git a/tests/api/test_tls.c b/tests/api/test_tls.c index 1bbe8f2e26..a0635675c0 100644 --- a/tests/api/test_tls.c +++ b/tests/api/test_tls.c @@ -885,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 diff --git a/tests/api/test_tls.h b/tests/api/test_tls.h index cdda231bf5..79d6f18dc8 100644 --- a/tests/api/test_tls.h +++ b/tests/api/test_tls.h @@ -32,6 +32,8 @@ 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); @@ -61,6 +63,9 @@ int test_wolfSSL_get_shared_ciphers(void); 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), \ diff --git a/tests/api/test_tls_ext.c b/tests/api/test_tls_ext.c index bcb9d81407..781042a4ce 100644 --- a/tests/api/test_tls_ext.c +++ b/tests/api/test_tls_ext.c @@ -1108,7 +1108,7 @@ int test_TLSX_SupportedCurve_empty_or_unsupported(void) 0xee, 0xee }; /* An empty named group list is malformed and must be rejected. */ - ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_server_method())); + ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method())); ExpectNotNull(ssl = wolfSSL_new(ctx)); if (ssl != NULL) suites = (Suites*)WOLFSSL_SUITES(ssl); @@ -1163,3 +1163,80 @@ int test_TLSX_SupportedCurve_empty_or_unsupported(void) #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 5bbd8ffc27..00499de3b0 100644 --- a/tests/api/test_tls_ext.h +++ b/tests/api/test_tls_ext.h @@ -38,5 +38,6 @@ 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/wolfssl/internal.h b/wolfssl/internal.h index 80dcb24c70..0480491e71 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -3466,7 +3466,12 @@ WOLFSSL_LOCAL int TLSX_SupportedCurve_Copy(TLSX* src, TLSX** dst, void* heap); WOLFSSL_LOCAL int TLSX_UseSupportedCurve(TLSX** extensions, word16 name, 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, int side); @@ -5197,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 */