Merge remote-tracking branch 'upstream/master' into harden-chain-depth-and-parser-bounds

# Conflicts:
#	src/ssl.c
This commit is contained in:
Colton Willey
2026-06-10 11:26:12 -07:00
214 changed files with 25005 additions and 6985 deletions
+2
View File
@@ -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/**'
+15 -1
View File
@@ -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
+2 -2
View File
@@ -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:
+1 -1
View File
@@ -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 &
+30 -3
View File
@@ -15,12 +15,20 @@ concurrency:
# Build the STM32 software simulator (https://github.com/wolfSSL/simulators,
# STM32Sim/ subdirectory) and run the wolfCrypt test suite on emulated
# STM32H753 (Cortex-M7) and STM32U585 (Cortex-M33) hardware. Replaces the
# previous Renode-based STM32H753 workflow and adds U5/PKA coverage.
# STM32H753 (Cortex-M7), STM32U585 (Cortex-M33), and STM32MP135 (Cortex-A7)
# hardware. Replaces the previous Renode-based STM32H753 workflow and adds
# U5/PKA + MP135 (SHA3/SHAKE on HASH1) coverage.
#
# Dockerfile.wolfcrypt reads wolfSSL from /opt/wolfssl at runtime via a
# bind mount, so unlike se050-sim.yml / stsafe-a120-sim.yml no Dockerfile
# patching is required - we just mount the PR checkout.
#
# The simulators repo is pinned via SIMULATORS_REF so the MP135 SHAKE-
# enabling sed patch below has a known anchor in user_settings.h. Bump
# the pin when simulators changes are needed.
env:
SIMULATORS_REF: 840da2f4a28a9e3027c127da38d758ded902d926
jobs:
stm32_sim:
@@ -36,6 +44,8 @@ jobs:
script: run-wolfcrypt-h7.sh
- chip_label: U585
script: run-wolfcrypt-u5.sh
- chip_label: MP135
script: run-wolfcrypt-mp135.sh
steps:
- name: Checkout wolfSSL (PR source)
uses: actions/checkout@v4
@@ -43,7 +53,24 @@ jobs:
path: wolfssl
- name: Clone STM32 simulator
run: git clone --depth 1 https://github.com/wolfSSL/simulators simulators
run: |
git clone https://github.com/wolfSSL/simulators simulators
cd simulators && git checkout "$SIMULATORS_REF"
# The MP135 firmware in the simulators repo currently disables SHAKE
# in user_settings.h with a comment pointing at the wolfSSL build
# break that this PR resolves. Once the simulators repo refreshes
# that file, this patch step becomes a no-op (the grep below will
# still pass) - drop it then.
- name: Enable SHAKE in MP135 firmware user_settings.h
if: matrix.chip_label == 'MP135'
working-directory: simulators/STM32Sim/firmware/wolfcrypt-test-mp135
run: |
sed -i 's|^#define WOLFSSL_SHA3$|#define WOLFSSL_SHA3\n#define WOLFSSL_SHAKE128\n#define WOLFSSL_SHAKE256|' user_settings.h
# Fail fast if the anchor line drifted - better than silently
# building with SHAKE off and "passing" without exercising it.
grep -q '^#define WOLFSSL_SHAKE128$' user_settings.h
grep -q '^#define WOLFSSL_SHAKE256$' user_settings.h
- uses: docker/setup-buildx-action@v3
+5 -1
View File
@@ -183,6 +183,7 @@ CONFIG_WOLFSSL_KEEP_PEER_CERT
CONFIG_WOLFSSL_MAX_FRAGMENT_LEN
CONFIG_WOLFSSL_MLKEM
CONFIG_WOLFSSL_NO_ASN_STRICT
CONFIG_WOLFSSL_OPENSSL_EXTRA_X509_SMALL
CONFIG_WOLFSSL_PSK
CONFIG_WOLFSSL_RSA_PSS
CONFIG_WOLFSSL_SESSION_EXPORT
@@ -661,6 +662,7 @@ WC_HASH_CUSTOM_MAX_BLOCK_SIZE
WC_HASH_CUSTOM_MAX_DIGEST_SIZE
WC_HASH_CUSTOM_MIN_DIGEST_SIZE
WC_LINUXKM_NO_USE_HEAP_WRAPPERS
WC_INIT_ERROR_WHEN_CONTENDED
WC_MLKEM_KERNEL_ASM
WC_NO_ASYNC_SLEEP
WC_NO_RNG_SIMPLE
@@ -844,7 +846,6 @@ WOLFSSL_NO_KCAPI_SHA224
WOLFSSL_NO_KTRI_ORACLE_WARNING
WOLFSSL_NO_LMS_SHAKE256_256
WOLFSSL_NO_OCSP_DATE_CHECK
WOLFSSL_NO_OCSP_ISSUER_CHAIN_CHECK
WOLFSSL_NO_OCSP_OPTIONAL_CERTS
WOLFSSL_NO_RSA_KEY_CHECK
WOLFSSL_NO_SERVER_GROUPS_EXT
@@ -968,6 +969,8 @@ WOLFSSL_XIL_MSG_NO_SLEEP
WOLFSSL_ZEPHYR
WOLF_ALLOW_BUILTIN
WOLF_CRYPTO_CB_CMD
WOLF_CRYPTO_CB_NO_SHA512_FALLBACK
WOLF_CRYPTO_CB_ONLY_SHA512
WOLF_CRYPTO_DEV
WOLF_NO_TRAILING_ENUM_COMMAS
WindowsCE
@@ -979,6 +982,7 @@ _ABI64
_ABIO64
_ARCH_PPC64
_ARCH_PWR8
_CALL_ELF
_COMPILER_VERSION
_INTPTR_T_DECLARED
_LINUX_REFCOUNT_H
+3
View File
@@ -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
+19
View File
@@ -2,6 +2,17 @@
## Enhancements
* **Behavioral change (RSA-PSS trailerField enforcement)**: `DecodeRsaPssParams`
(and its public wrapper `wc_DecodeRsaPssParams`) now enforces RFC 8017 A.2.3,
which mandates `trailerField == trailerFieldBC(1)`. In the default build
(i.e., without `WOLFSSL_NO_ASN_STRICT`), any certificate or CMS/PKCS#7
structure whose RSA-PSS parameters contain a `trailerField` value other than 1
is now rejected with `ASN_PARSE_E`. Previously, any positive integer value was
silently accepted. This affects all call paths that decode RSA-PSS algorithm
parameters, including X.509 certificate parsing and PKCS#7 signature
verification. Users who need to interoperate with non-conformant peers can
define `WOLFSSL_NO_ASN_STRICT` to restore the previous permissive behavior.
* **BREAKING (FIPS 205 SLH-DSA)**: `wc_SlhDsaKey_SignHash`,
`wc_SlhDsaKey_SignHashDeterministic`, `wc_SlhDsaKey_SignHashWithRandom`, and
`wc_SlhDsaKey_VerifyHash` now take the **caller-pre-hashed message digest**
@@ -46,6 +57,14 @@
per-record nonce. Scoped to TLS 1.3, non-DTLS, non-QUIC; requires
`WOLF_CRYPTO_CB` and `WOLF_CRYPTO_CB_AES_SETKEY`.
* **BREAKING (RFC 6960 4.2.2.2)**: OCSP responder authorization is now
strictly enforced. Removes the non-compliant `CheckOcspResponderChain()`
fallback, which authorized any OCSP responder cert issued by an ancestor
of the target's issuer; [RFC 6960 4.2.2.2](https://datatracker.ietf.org/doc/html/rfc6960#section-4.2.2.2)
requires direct issuance by the CA identified in the request. Also
removes the now-unused `WOLFSSL_NO_OCSP_ISSUER_CHAIN_CHECK` macro and
the `vp` parameter from `CheckOcspResponder()`.
# wolfSSL Release 5.9.1 (Apr. 8, 2026)
Release 5.9.1 has been developed according to wolfSSL's development and QA
+23 -12
View File
@@ -1,14 +1,20 @@
#!/bin/sh
runCMD() { # usage: runCMD "<command>" "<retVal>"
runCMD() { # usage: runCMD "<command>" "<retVal>[ <retVal> ...]"
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."
+19 -8
View File
@@ -491,6 +491,7 @@ static int wolfkdriv_attach(device_t dev)
attach_out:
if (error) {
device_printf(dev, "error: attach_out: %d\n", error);
wolfkdriv_unregister(softc);
(void)wolfkmod_cleanup();
}
@@ -503,16 +504,14 @@ static int wolfkdriv_detach(device_t dev)
struct wolfkdriv_softc * softc = NULL;
int ret = 0;
/* unregister wolfcrypt algs */
softc = device_get_softc(dev);
wolfkdriv_unregister(softc);
ret = wolfkmod_cleanup();
if (ret == 0) {
/* unregister wolfcrypt algs */
softc = device_get_softc(dev);
wolfkdriv_unregister(softc);
}
#if defined(WOLFSSL_BSDKM_VERBOSE_DEBUG)
device_printf(dev, "info: exiting detach\n");
device_printf(dev, "info: exiting detach: %d\n", ret);
#else
(void)ret;
#endif /* WOLFSSL_BSDKM_VERBOSE_DEBUG */
return (0);
@@ -802,6 +801,7 @@ static int wolfkdriv_cbc_work(device_t dev, wolfkdriv_session_t * session,
cbc_work_out:
/* cleanup. */
wc_ForceZero(&aes, sizeof(aes));
wc_ForceZero(iv, sizeof(iv));
wc_ForceZero(block, sizeof(block));
@@ -812,6 +812,11 @@ cbc_work_out:
error);
#endif /* WOLFSSL_BSDKM_VERBOSE_DEBUG */
if (error < 0) {
/* convert wolfcrypt errors to EINVAL. */
error = EINVAL;
}
return (error);
}
@@ -979,6 +984,7 @@ static int wolfkdriv_gcm_work(device_t dev, wolfkdriv_session_t * session,
gcm_work_out:
/* cleanup. */
wc_ForceZero(&aes, sizeof(aes));
wc_ForceZero(iv, sizeof(iv));
wc_ForceZero(auth_tag, sizeof(auth_tag));
@@ -989,6 +995,11 @@ gcm_work_out:
error);
#endif /* WOLFSSL_BSDKM_VERBOSE_DEBUG */
if (error < 0) {
/* convert wolfcrypt errors to EINVAL. */
error = EINVAL;
}
return (error);
}
+1 -1
View File
@@ -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 */
+10
View File
@@ -139,6 +139,11 @@ int wolfkmod_vecreg_save(int flags_unused)
wolfkmod_print_curthread("wolfkmod_vecreg_save");
#endif
if (fpu_states == NULL) {
printf("error: wolfkmod_vecreg_save: fpu_states null\n");
return (EINVAL);
}
if (is_fpu_kern_thread(0)) {
/* kernel fpu threads are special, do nothing. They own a
* persistent, dedicated fpu context. */
@@ -189,6 +194,11 @@ void wolfkmod_vecreg_restore(void)
wolfkmod_print_curthread("wolfkmod_vecreg_restore");
#endif
if (fpu_states == NULL) {
printf("error: wolfkmod_vecreg_restore: fpu_states null\n");
return;
}
if (is_fpu_kern_thread(0)) {
/* kernel fpu threads are special, do nothing. They own a
* persistent, dedicated fpu context. */
-1
View File
@@ -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
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+5 -6
View File
@@ -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
+4
View File
@@ -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 \
Binary file not shown.
+273
View File
@@ -0,0 +1,273 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 10 (0xa)
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=US, ST=Washington, L=Seattle, O=wolfSSL, OU=Engineering, CN=wolfSSL intermediate CA 1, emailAddress=info@wolfssl.com
Validity
Not Before: May 27 16:15:23 2026 GMT
Not After : Feb 20 16:15:23 2029 GMT
Subject: C=US, ST=Washington, L=Seattle, O=wolfSSL, OU=Engineering, CN=wolfSSL OCSP Responder Int1, emailAddress=info@wolfssl.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:98:82:f0:e7:da:58:cf:85:0b:a4:de:34:41:3f:
79:5a:ff:75:78:95:c6:89:5c:b7:2e:c4:6d:05:73:
a5:b1:45:58:72:3e:2c:e2:c0:17:87:fe:b4:64:82:
00:fd:56:7d:8a:73:8d:6f:88:77:bb:98:56:a8:b6:
28:36:a8:0c:9f:d6:7a:25:1d:ad:10:b8:d0:19:7c:
80:70:9c:80:26:95:53:42:1c:90:4e:27:ed:f5:6e:
87:6f:2e:eb:92:95:e0:6f:53:fe:be:17:a9:7f:e6:
b7:09:4b:63:9c:08:97:c8:b3:36:75:38:6d:3e:ff:
d8:e1:22:75:57:1a:5f:60:30:4d:1b:bc:2f:99:7f:
02:ef:df:24:25:88:57:91:7b:2c:6f:f7:98:90:29:
9f:12:66:a9:3e:73:c4:81:73:e7:9c:eb:22:f5:6c:
d5:23:e0:7b:ba:a6:ca:16:a3:33:f9:2e:52:a3:a8:
c9:f1:dd:85:1f:c1:94:0b:1e:8f:b7:48:be:20:d0:
da:bd:3b:85:8e:92:c1:f0:7c:ec:2e:c5:27:a0:4e:
22:c5:c2:4d:1b:66:e7:ac:57:8c:34:2b:a5:55:e9:
34:9c:7f:33:29:d0:4e:cb:1a:1a:02:17:b2:45:a3:
49:05:5d:00:79:85:50:91:c0:3d:30:cb:84:0a:9a:
2d:6d
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
X509v3 Subject Key Identifier:
90:3C:B9:FB:15:20:AB:F6:6F:D3:F1:C9:71:B0:D0:1D:97:C6:A5:C5
X509v3 Authority Key Identifier:
keyid:83:C6:3A:89:2C:81:F4:02:D7:9D:4C:E2:2A:C0:71:82:64:44:DA:0E
DirName:/C=US/ST=Washington/L=Seattle/O=wolfSSL/OU=Engineering/CN=wolfSSL root CA/emailAddress=info@wolfssl.com
serial:01
X509v3 Extended Key Usage:
OCSP Signing
Signature Algorithm: sha256WithRSAEncryption
Signature Value:
3c:42:b5:c3:a3:1a:d7:2d:c6:6a:3d:b2:5c:18:49:85:26:65:
85:af:c2:2e:46:dc:a1:1c:8d:22:86:fc:a9:73:02:79:60:3e:
e7:f8:cc:ff:c9:b1:38:e0:96:4f:31:b8:e5:b5:0c:b0:1d:1c:
c2:27:29:c7:3f:70:86:5a:61:2e:11:c7:81:75:8a:72:f8:75:
0c:84:be:65:44:98:ce:29:87:02:30:ed:42:47:fc:75:d9:88:
73:64:ad:6b:cd:32:96:55:ea:b5:fb:8e:21:ce:02:59:dc:3e:
9f:33:40:66:c4:be:f0:71:88:ce:f5:98:79:2d:dd:58:2b:28:
bf:09:89:88:05:3e:36:de:e6:b1:9a:fc:4a:80:1b:00:fd:c9:
2a:46:ce:8c:64:81:b8:25:c9:7d:d2:31:05:2c:49:57:e9:84:
c0:a4:dc:f6:20:7e:fb:c1:d7:c5:bc:ea:07:bf:e6:10:a0:53:
25:4f:7e:c5:77:a8:b4:c6:98:2c:72:76:49:ea:e5:45:bb:c4:
e5:fc:4b:9c:08:64:b4:2f:bf:97:8e:84:84:d7:30:82:7f:32:
25:73:00:d5:58:44:2b:4a:2c:08:79:86:50:0f:e9:e7:94:d1:
d4:0e:4f:a9:e0:ab:ba:8b:e8:1a:be:90:92:64:39:10:35:90:
09:7f:ed:69
-----BEGIN CERTIFICATE-----
MIIEzTCCA7WgAwIBAgIBCjANBgkqhkiG9w0BAQsFADCBoTELMAkGA1UEBhMCVVMx
EzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxEDAOBgNVBAoM
B3dvbGZTU0wxFDASBgNVBAsMC0VuZ2luZWVyaW5nMSIwIAYDVQQDDBl3b2xmU1NM
IGludGVybWVkaWF0ZSBDQSAxMR8wHQYJKoZIhvcNAQkBFhBpbmZvQHdvbGZzc2wu
Y29tMB4XDTI2MDUyNzE2MTUyM1oXDTI5MDIyMDE2MTUyM1owgaMxCzAJBgNVBAYT
AlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMRAwDgYDVQQHDAdTZWF0dGxlMRAwDgYD
VQQKDAd3b2xmU1NMMRQwEgYDVQQLDAtFbmdpbmVlcmluZzEkMCIGA1UEAwwbd29s
ZlNTTCBPQ1NQIFJlc3BvbmRlciBJbnQxMR8wHQYJKoZIhvcNAQkBFhBpbmZvQHdv
bGZzc2wuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmILw59pY
z4ULpN40QT95Wv91eJXGiVy3LsRtBXOlsUVYcj4s4sAXh/60ZIIA/VZ9inONb4h3
u5hWqLYoNqgMn9Z6JR2tELjQGXyAcJyAJpVTQhyQTift9W6Hby7rkpXgb1P+vhep
f+a3CUtjnAiXyLM2dThtPv/Y4SJ1VxpfYDBNG7wvmX8C798kJYhXkXssb/eYkCmf
EmapPnPEgXPnnOsi9WzVI+B7uqbKFqMz+S5So6jJ8d2FH8GUCx6Pt0i+INDavTuF
jpLB8HzsLsUnoE4ixcJNG2bnrFeMNCulVek0nH8zKdBOyxoaAheyRaNJBV0AeYVQ
kcA9MMuECpotbQIDAQABo4IBCjCCAQYwCQYDVR0TBAIwADAdBgNVHQ4EFgQUkDy5
+xUgq/Zv0/HJcbDQHZfGpcUwgcQGA1UdIwSBvDCBuYAUg8Y6iSyB9ALXnUziKsBx
gmRE2g6hgZ2kgZowgZcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9u
MRAwDgYDVQQHDAdTZWF0dGxlMRAwDgYDVQQKDAd3b2xmU1NMMRQwEgYDVQQLDAtF
bmdpbmVlcmluZzEYMBYGA1UEAwwPd29sZlNTTCByb290IENBMR8wHQYJKoZIhvcN
AQkBFhBpbmZvQHdvbGZzc2wuY29tggEBMBMGA1UdJQQMMAoGCCsGAQUFBwMJMA0G
CSqGSIb3DQEBCwUAA4IBAQA8QrXDoxrXLcZqPbJcGEmFJmWFr8IuRtyhHI0ihvyp
cwJ5YD7n+Mz/ybE44JZPMbjltQywHRzCJynHP3CGWmEuEceBdYpy+HUMhL5lRJjO
KYcCMO1CR/x12YhzZK1rzTKWVeq1+44hzgJZ3D6fM0BmxL7wcYjO9Zh5Ld1YKyi/
CYmIBT423uaxmvxKgBsA/ckqRs6MZIG4Jcl90jEFLElX6YTApNz2IH77wdfFvOoH
v+YQoFMlT37Fd6i0xpgscnZJ6uVFu8Tl/EucCGS0L7+XjoSE1zCCfzIlcwDVWEQr
SiwIeYZQD+nnlNHUDk+p4Ku6i+gavpCSZDkQNZAJf+1p
-----END CERTIFICATE-----
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=US, ST=Washington, L=Seattle, O=wolfSSL, OU=Engineering, CN=wolfSSL root CA, emailAddress=info@wolfssl.com
Validity
Not Before: Nov 13 20:41:34 2025 GMT
Not After : Aug 9 20:41:34 2028 GMT
Subject: C=US, ST=Washington, L=Seattle, O=wolfSSL, OU=Engineering, CN=wolfSSL intermediate CA 1, emailAddress=info@wolfssl.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:de:b4:c8:5c:77:e0:2d:b1:f5:b9:ad:16:47:35:
a0:35:65:65:c6:e1:40:ab:1e:b4:b9:13:b7:cb:8c:
bb:77:a5:76:da:6d:87:87:f6:4a:4d:13:e4:26:3e:
27:87:ee:5b:c7:6a:3f:45:30:61:55:5c:f6:35:d1:
65:fa:98:11:a3:a7:55:d5:be:91:82:4b:fc:be:90:
d6:50:53:63:9a:2c:22:e1:35:11:dc:78:02:97:8a:
e4:46:92:9c:53:08:76:de:1f:53:b6:b8:ca:77:3e:
79:6e:bc:d0:e3:0d:30:5b:4c:f6:94:0d:30:29:64:
9f:04:e5:db:fb:89:60:67:bb:af:26:83:51:77:24:
2f:2b:0b:a1:94:81:10:98:e8:eb:26:a8:1e:7c:e4:
c4:6c:67:06:95:55:4a:dd:52:f4:f2:60:6d:01:2b:
19:91:35:6d:a4:08:47:06:71:24:00:d9:de:c6:56:
f3:8b:53:2c:e2:9a:96:a5:f3:62:e5:c4:e3:23:f2:
d2:fc:21:ea:0f:62:76:8d:d5:99:48:ce:dc:58:c4:
bb:7f:da:94:2c:80:74:83:c5:e0:b0:15:7e:41:fd:
0e:f2:f4:f0:78:76:7b:ad:26:0d:aa:48:96:17:2f:
21:e3:95:2b:26:37:f9:aa:80:2f:fe:de:f6:5e:bc:
97:7f
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints:
CA:TRUE
X509v3 Subject Key Identifier:
83:C6:3A:89:2C:81:F4:02:D7:9D:4C:E2:2A:C0:71:82:64:44:DA:0E
X509v3 Authority Key Identifier:
keyid:73:B0:1C:A4:2F:82:CB:CF:47:A5:38:D7:B0:04:82:3A:7E:72:15:21
DirName:/C=US/ST=Washington/L=Seattle/O=wolfSSL/OU=Engineering/CN=wolfSSL root CA/emailAddress=info@wolfssl.com
serial:63
X509v3 Key Usage:
Certificate Sign, CRL Sign
Authority Information Access:
OCSP - URI:http://127.0.0.1:22220
Signature Algorithm: sha256WithRSAEncryption
Signature Value:
77:ec:89:37:d4:35:2e:24:fd:d2:de:d9:98:87:be:52:ae:b5:
d4:f6:13:34:12:2c:f0:78:98:07:9f:f7:e4:76:df:6e:eb:97:
c7:03:a3:e6:15:6e:e2:94:16:6b:ed:59:a9:4a:10:a0:cc:c2:
61:78:c7:fb:1c:04:4a:20:c1:fc:94:c6:99:b0:3a:8c:2f:2b:
7d:15:30:53:c7:9b:73:54:6f:4d:16:a6:ab:2d:8a:51:70:1f:
1b:8e:60:0b:56:8b:f2:94:01:fd:81:5f:73:cb:ed:5e:cc:4a:
71:c1:a9:1a:d7:c7:2b:5a:66:02:77:da:10:e8:45:42:a0:7c:
ef:78:ff:dd:08:f6:84:2f:41:f5:18:c9:a2:48:d1:5d:b6:a4:
4d:32:af:83:5d:b9:64:ec:40:e9:62:38:ef:1b:d1:8e:c9:e8:
fd:b3:e8:e1:a1:da:16:1e:26:3c:82:36:cb:8d:80:67:33:ca:
30:bf:93:03:c8:9c:be:a2:6f:aa:7c:76:24:3d:06:99:ab:a7:
fe:12:f3:db:fd:a0:8a:b5:0d:c1:9c:90:b7:ca:7e:6d:fb:ff:
2a:c3:fe:7c:9f:41:e8:c2:7f:4f:fa:4b:49:c4:a0:d0:bc:fd:
38:34:22:ff:d5:83:79:70:7f:6c:30:8d:ad:93:fb:b8:77:01:
34:af:cc:0e
-----BEGIN CERTIFICATE-----
MIIE8DCCA9igAwIBAgIBATANBgkqhkiG9w0BAQsFADCBlzELMAkGA1UEBhMCVVMx
EzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxEDAOBgNVBAoM
B3dvbGZTU0wxFDASBgNVBAsMC0VuZ2luZWVyaW5nMRgwFgYDVQQDDA93b2xmU1NM
IHJvb3QgQ0ExHzAdBgkqhkiG9w0BCQEWEGluZm9Ad29sZnNzbC5jb20wHhcNMjUx
MTEzMjA0MTM0WhcNMjgwODA5MjA0MTM0WjCBoTELMAkGA1UEBhMCVVMxEzARBgNV
BAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxEDAOBgNVBAoMB3dvbGZT
U0wxFDASBgNVBAsMC0VuZ2luZWVyaW5nMSIwIAYDVQQDDBl3b2xmU1NMIGludGVy
bWVkaWF0ZSBDQSAxMR8wHQYJKoZIhvcNAQkBFhBpbmZvQHdvbGZzc2wuY29tMIIB
IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3rTIXHfgLbH1ua0WRzWgNWVl
xuFAqx60uRO3y4y7d6V22m2Hh/ZKTRPkJj4nh+5bx2o/RTBhVVz2NdFl+pgRo6dV
1b6Rgkv8vpDWUFNjmiwi4TUR3HgCl4rkRpKcUwh23h9TtrjKdz55brzQ4w0wW0z2
lA0wKWSfBOXb+4lgZ7uvJoNRdyQvKwuhlIEQmOjrJqgefOTEbGcGlVVK3VL08mBt
ASsZkTVtpAhHBnEkANnexlbzi1Ms4pqWpfNi5cTjI/LS/CHqD2J2jdWZSM7cWMS7
f9qULIB0g8XgsBV+Qf0O8vTweHZ7rSYNqkiWFy8h45UrJjf5qoAv/t72XryXfwID
AQABo4IBOTCCATUwDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQUg8Y6iSyB9ALXnUzi
KsBxgmRE2g4wgcQGA1UdIwSBvDCBuYAUc7AcpC+Cy89HpTjXsASCOn5yFSGhgZ2k
gZowgZcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMRAwDgYDVQQH
DAdTZWF0dGxlMRAwDgYDVQQKDAd3b2xmU1NMMRQwEgYDVQQLDAtFbmdpbmVlcmlu
ZzEYMBYGA1UEAwwPd29sZlNTTCByb290IENBMR8wHQYJKoZIhvcNAQkBFhBpbmZv
QHdvbGZzc2wuY29tggFjMAsGA1UdDwQEAwIBBjAyBggrBgEFBQcBAQQmMCQwIgYI
KwYBBQUHMAGGFmh0dHA6Ly8xMjcuMC4wLjE6MjIyMjAwDQYJKoZIhvcNAQELBQAD
ggEBAHfsiTfUNS4k/dLe2ZiHvlKutdT2EzQSLPB4mAef9+R2327rl8cDo+YVbuKU
FmvtWalKEKDMwmF4x/scBEogwfyUxpmwOowvK30VMFPHm3NUb00WpqstilFwHxuO
YAtWi/KUAf2BX3PL7V7MSnHBqRrXxytaZgJ32hDoRUKgfO94/90I9oQvQfUYyaJI
0V22pE0yr4NduWTsQOliOO8b0Y7J6P2z6OGh2hYeJjyCNsuNgGczyjC/kwPInL6i
b6p8diQ9Bpmrp/4S89v9oIq1DcGckLfKfm37/yrD/nyfQejCf0/6S0nEoNC8/Tg0
Iv/Vg3lwf2wwja2T+7h3ATSvzA4=
-----END CERTIFICATE-----
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 99 (0x63)
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=US, ST=Washington, L=Seattle, O=wolfSSL, OU=Engineering, CN=wolfSSL root CA, emailAddress=info@wolfssl.com
Validity
Not Before: Nov 13 20:41:34 2025 GMT
Not After : Aug 9 20:41:34 2028 GMT
Subject: C=US, ST=Washington, L=Seattle, O=wolfSSL, OU=Engineering, CN=wolfSSL root CA, emailAddress=info@wolfssl.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:ab:2c:b4:2f:1d:06:09:ef:4e:29:86:84:7e:cc:
bf:a6:79:7c:f0:c0:c1:64:25:8c:75:b7:10:05:ca:
48:27:0c:0e:32:1c:b0:fe:99:85:39:b6:b9:a2:f7:
27:ff:6d:3c:8c:16:73:29:21:7f:8b:a6:54:71:90:
ad:cc:05:b9:9f:15:c7:0a:3f:5f:69:f4:0a:5f:8c:
71:b5:2c:bf:66:e2:03:9a:32:f4:d2:ec:2a:89:4b:
f9:35:88:14:33:47:4e:2e:05:79:01:ed:64:36:76:
b9:f8:85:cd:01:88:ac:c5:b2:b1:59:b8:cd:5a:f4:
09:09:38:9b:da:5a:cf:ce:78:99:1f:49:3d:41:d6:
06:7c:52:99:c8:97:d1:b3:80:3a:a2:4f:36:c4:c5:
96:30:77:31:38:c8:70:cc:e1:67:06:b3:2b:2f:93:
b5:69:cf:83:7e:88:53:9b:0f:46:21:4c:d6:05:36:
44:99:60:68:47:e5:32:01:12:d4:10:73:ae:9a:34:
94:fa:6e:b8:58:4f:7b:5b:8a:92:97:ad:fd:97:b9:
75:ca:c2:d4:45:7d:17:6b:cd:2f:f3:63:7a:0e:30:
b5:0b:a9:d9:a6:7c:74:60:9d:cc:09:03:43:f1:0f:
90:d3:b7:fe:6c:9f:d9:cd:78:4b:15:ae:8c:5b:f9:
99:81
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints:
CA:TRUE
X509v3 Subject Key Identifier:
73:B0:1C:A4:2F:82:CB:CF:47:A5:38:D7:B0:04:82:3A:7E:72:15:21
X509v3 Authority Key Identifier:
keyid:73:B0:1C:A4:2F:82:CB:CF:47:A5:38:D7:B0:04:82:3A:7E:72:15:21
DirName:/C=US/ST=Washington/L=Seattle/O=wolfSSL/OU=Engineering/CN=wolfSSL root CA/emailAddress=info@wolfssl.com
serial:63
X509v3 Key Usage:
Certificate Sign, CRL Sign
Authority Information Access:
OCSP - URI:http://127.0.0.1:22220
Signature Algorithm: sha256WithRSAEncryption
Signature Value:
58:41:01:e5:1b:ce:bc:51:0c:23:b2:66:df:39:d9:1e:b1:bd:
9a:db:fa:da:16:83:26:6e:7e:2e:f9:5d:46:9a:52:a0:09:6f:
f2:c0:96:ba:49:ad:29:54:06:e9:21:d6:36:5e:d5:43:07:2c:
5d:4e:b7:bf:7c:e5:91:75:ea:0d:56:7c:a3:fd:82:d8:2e:70:
fa:fc:ab:36:36:d5:ba:63:d5:42:da:21:b4:50:9a:86:8a:df:
21:26:03:e8:ca:6f:c7:51:50:6c:cc:40:da:4e:8f:06:15:c0:
9a:0d:7a:80:2c:95:aa:5a:ad:e2:66:b0:32:d6:74:87:ea:7a:
b2:46:d5:2c:cf:fa:18:8a:2f:e0:3a:ae:17:6a:f2:ce:75:8d:
e4:4d:74:8f:e7:c6:21:29:65:5d:41:07:fb:29:d9:be:ea:b2:
e3:80:07:8c:14:8d:a3:7d:d1:51:af:26:9d:cd:01:d5:80:af:
68:12:41:2b:eb:94:cc:45:d1:c7:66:f3:f9:15:72:be:94:e3:
21:6d:f1:08:78:b6:5a:ee:73:09:4b:f4:1a:5e:02:2a:25:f0:
3d:d2:03:f2:22:15:4b:3d:aa:35:ea:90:ca:44:4e:61:77:db:
b4:94:46:77:c6:8c:33:09:b6:84:3c:4e:ac:ad:9d:e0:2f:22:
5a:be:25:19
-----BEGIN CERTIFICATE-----
MIIE5jCCA86gAwIBAgIBYzANBgkqhkiG9w0BAQsFADCBlzELMAkGA1UEBhMCVVMx
EzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxEDAOBgNVBAoM
B3dvbGZTU0wxFDASBgNVBAsMC0VuZ2luZWVyaW5nMRgwFgYDVQQDDA93b2xmU1NM
IHJvb3QgQ0ExHzAdBgkqhkiG9w0BCQEWEGluZm9Ad29sZnNzbC5jb20wHhcNMjUx
MTEzMjA0MTM0WhcNMjgwODA5MjA0MTM0WjCBlzELMAkGA1UEBhMCVVMxEzARBgNV
BAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxEDAOBgNVBAoMB3dvbGZT
U0wxFDASBgNVBAsMC0VuZ2luZWVyaW5nMRgwFgYDVQQDDA93b2xmU1NMIHJvb3Qg
Q0ExHzAdBgkqhkiG9w0BCQEWEGluZm9Ad29sZnNzbC5jb20wggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQCrLLQvHQYJ704phoR+zL+meXzwwMFkJYx1txAF
ykgnDA4yHLD+mYU5trmi9yf/bTyMFnMpIX+LplRxkK3MBbmfFccKP19p9ApfjHG1
LL9m4gOaMvTS7CqJS/k1iBQzR04uBXkB7WQ2drn4hc0BiKzFsrFZuM1a9AkJOJva
Ws/OeJkfST1B1gZ8UpnIl9GzgDqiTzbExZYwdzE4yHDM4WcGsysvk7Vpz4N+iFOb
D0YhTNYFNkSZYGhH5TIBEtQQc66aNJT6brhYT3tbipKXrf2XuXXKwtRFfRdrzS/z
Y3oOMLULqdmmfHRgncwJA0PxD5DTt/5sn9nNeEsVroxb+ZmBAgMBAAGjggE5MIIB
NTAMBgNVHRMEBTADAQH/MB0GA1UdDgQWBBRzsBykL4LLz0elONewBII6fnIVITCB
xAYDVR0jBIG8MIG5gBRzsBykL4LLz0elONewBII6fnIVIaGBnaSBmjCBlzELMAkG
A1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUx
EDAOBgNVBAoMB3dvbGZTU0wxFDASBgNVBAsMC0VuZ2luZWVyaW5nMRgwFgYDVQQD
DA93b2xmU1NMIHJvb3QgQ0ExHzAdBgkqhkiG9w0BCQEWEGluZm9Ad29sZnNzbC5j
b22CAWMwCwYDVR0PBAQDAgEGMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcwAYYW
aHR0cDovLzEyNy4wLjAuMToyMjIyMDANBgkqhkiG9w0BAQsFAAOCAQEAWEEB5RvO
vFEMI7Jm3znZHrG9mtv62haDJm5+LvldRppSoAlv8sCWukmtKVQG6SHWNl7VQwcs
XU63v3zlkXXqDVZ8o/2C2C5w+vyrNjbVumPVQtohtFCahorfISYD6Mpvx1FQbMxA
2k6PBhXAmg16gCyVqlqt4mawMtZ0h+p6skbVLM/6GIov4DquF2ryznWN5E10j+fG
ISllXUEH+ynZvuqy44AHjBSNo33RUa8mnc0B1YCvaBJBK+uUzEXRx2bz+RVyvpTj
IW3xCHi2Wu5zCUv0Gl4CKiXwPdID8iIVSz2qNeqQykROYXfbtJRGd8aMMwm2hDxO
rK2d4C8iWr4lGQ==
-----END CERTIFICATE-----
Binary file not shown.
+28
View File
@@ -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-----
+12 -3
View File
@@ -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
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
-12
View File
@@ -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
+1 -1
View File
@@ -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"])
+4 -1
View File
@@ -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
+8
View File
@@ -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
@@ -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 <wolfssl/wolfcrypt/dilithium.h>).
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).
+643
View File
@@ -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);
+932
View File
@@ -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);
+472
View File
@@ -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);
+530
View File
@@ -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-<hash>_<height>_<n>" (single-tree) or
"XMSSMT-<hash>_<total_height>/<layers>_<n>" (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);
+5
View File
@@ -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 */
+7 -5
View File
@@ -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
+2 -2
View File
@@ -363,8 +363,8 @@ fi
# purposes!
openssl ocsp -port "$port2" -nmin 1 \
-index certs/ocsp/index-intermediate1-ca-issued-certs.txt \
-rsigner certs/ocsp/ocsp-responder-cert.pem \
-rkey certs/ocsp/ocsp-responder-key.pem \
-rsigner certs/ocsp/ocsp-responder-int1-cert.pem \
-rkey certs/ocsp/ocsp-responder-int1-key.pem \
-CA certs/ocsp/intermediate1-ca-cert.pem \
"$@" &
+4 -4
View File
@@ -335,8 +335,8 @@ openssl ocsp -port "$port1" -nmin 1 \
# purposes!
openssl ocsp -port "$port2" -nmin 1 \
-index certs/ocsp/index-intermediate2-ca-issued-certs.txt \
-rsigner certs/ocsp/ocsp-responder-cert.pem \
-rkey certs/ocsp/ocsp-responder-key.pem \
-rsigner certs/ocsp/intermediate2-ca-cert.pem \
-rkey certs/ocsp/intermediate2-ca-key.pem \
-CA certs/ocsp/intermediate2-ca-cert.pem \
"$@" \
&
@@ -346,8 +346,8 @@ openssl ocsp -port "$port2" -nmin 1 \
# purposes!
openssl ocsp -port "$port3" -nmin 1 \
-index certs/ocsp/index-intermediate3-ca-issued-certs.txt \
-rsigner certs/ocsp/ocsp-responder-cert.pem \
-rkey certs/ocsp/ocsp-responder-key.pem \
-rsigner certs/ocsp/intermediate3-ca-cert.pem \
-rkey certs/ocsp/intermediate3-ca-key.pem \
-CA certs/ocsp/intermediate3-ca-cert.pem \
"$@" \
&
+4 -4
View File
@@ -353,8 +353,8 @@ openssl ocsp -port "$port1" -nmin 1 \
# purposes!
openssl ocsp -port "$port2" -nmin 1 \
-index certs/ocsp/index-intermediate2-ca-issued-certs.txt \
-rsigner certs/ocsp/ocsp-responder-cert.pem \
-rkey certs/ocsp/ocsp-responder-key.pem \
-rsigner certs/ocsp/intermediate2-ca-cert.pem \
-rkey certs/ocsp/intermediate2-ca-key.pem \
-CA certs/ocsp/intermediate2-ca-cert.pem \
"$@" \
&
@@ -364,8 +364,8 @@ openssl ocsp -port "$port2" -nmin 1 \
# purposes!
openssl ocsp -port "$port3" -nmin 1 \
-index certs/ocsp/index-intermediate3-ca-issued-certs.txt \
-rsigner certs/ocsp/ocsp-responder-cert.pem \
-rkey certs/ocsp/ocsp-responder-key.pem \
-rsigner certs/ocsp/intermediate3-ca-cert.pem \
-rkey certs/ocsp/intermediate3-ca-key.pem \
-CA certs/ocsp/intermediate3-ca-cert.pem \
"$@" \
&
+2 -2
View File
@@ -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) {
+8
View File
@@ -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;
+15 -4
View File
@@ -2369,7 +2369,6 @@ static Dtls13Epoch* Dtls13NewEpochSlot(WOLFSSL* ssl)
w64wrapper oldestNumber;
int i;
/* FIXME: add max function */
oldestNumber = w64From32((word32)-1, (word32)-1);
oldest = NULL;
@@ -2380,8 +2379,10 @@ static Dtls13Epoch* Dtls13NewEpochSlot(WOLFSSL* ssl)
if (!w64Equal(e->epochNumber, ssl->dtls13Epoch) &&
!w64Equal(e->epochNumber, ssl->dtls13PeerEpoch) &&
w64LT(e->epochNumber, oldestNumber))
w64LT(e->epochNumber, oldestNumber)) {
oldest = e;
oldestNumber = e->epochNumber;
}
}
if (oldest == NULL)
@@ -2720,17 +2721,27 @@ static int Dtls13RtxIsTrackedByRn(const Dtls13RtxRecord* r, w64wrapper epoch,
static int Dtls13KeyUpdateAckReceived(WOLFSSL* ssl)
{
int ret;
/* Validate on a local copy so ssl->dtls13Epoch is left untouched when a
* check fails. */
w64wrapper newEpoch = ssl->dtls13Epoch;
ret = DeriveTls13Keys(ssl, update_traffic_key, ENCRYPT_SIDE_ONLY, 1);
if (ret != 0)
return ret;
w64Increment(&ssl->dtls13Epoch);
w64Increment(&newEpoch);
/* Epoch wrapped up */
if (w64IsZero(ssl->dtls13Epoch))
if (w64IsZero(newEpoch))
return BAD_STATE_E;
/* RFC 9147 Section 4.2.1: the epoch must not exceed 2^48-1. */
if (w64GT(newEpoch,
w64From32(DTLS13_EPOCH_MAX_HI32, DTLS13_EPOCH_MAX_LO32)))
return BAD_STATE_E;
ssl->dtls13Epoch = newEpoch;
return Dtls13SetEpochKeys(ssl, ssl->dtls13Epoch, ENCRYPT_SIDE_ONLY);
}
+2
View File
@@ -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
+406 -91
View File
@@ -535,6 +535,12 @@ void wolfssl_priv_der_unblind_free(DerBuffer* key)
#define SSC_TLS13_EES "EARLY_EXPORTER_SECRET"
/* Label string for exporter secret. */
#define SSC_TLS13_ES "EXPORTER_SECRET"
#ifdef HAVE_ECH
/* Label string for ECH KEM shared secret. */
#define SSC_TLS13_ECH_S "ECH_SECRET"
/* Label string for ECHConfig used to construct ECH. */
#define SSC_TLS13_ECH_C "ECH_CONFIG"
#endif
/*
* This function builds up string for key-logging then call user's
@@ -594,6 +600,18 @@ void wolfssl_priv_der_unblind_free(DerBuffer* key)
label = SSC_TLS13_ES;
break;
#ifdef HAVE_ECH
case ECH_SECRET:
labelSz = sizeof(SSC_TLS13_ECH_S);
label = SSC_TLS13_ECH_S;
break;
case ECH_CONFIG:
labelSz = sizeof(SSC_TLS13_ECH_C);
label = SSC_TLS13_ECH_C;
break;
#endif
default:
return BAD_FUNC_ARG;
}
@@ -3282,6 +3300,7 @@ static void FreeCiphersSide(Ciphers *cipher, void* heap)
cipher->aria = NULL;
#endif
#ifdef HAVE_CAMELLIA
wc_CamelliaFree(cipher->cam);
XFREE(cipher->cam, heap, DYNAMIC_TYPE_CIPHER);
cipher->cam = NULL;
#endif
@@ -7329,6 +7348,9 @@ int SetSSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup)
#endif
#else
if (ctx->privateKey != NULL) {
if (ssl->buffers.key != NULL) {
FreeDer(&ssl->buffers.key);
}
ret = AllocCopyDer(&ssl->buffers.key, ctx->privateKey->buffer,
ctx->privateKey->length, ctx->privateKey->type,
ctx->privateKey->heap);
@@ -14227,8 +14249,10 @@ int CopyDecodedToX509(WOLFSSL_X509* x509, DecodedCert* dCert)
#endif
}
if (dCert->signature != NULL && dCert->sigLength != 0 &&
dCert->sigLength <= MAX_ENCODED_SIG_SZ) {
/* Store a copy of the signature for later retrieval. The buffer is sized
* to the exact parsed length (itself bounded by the cert DER), so no fixed
* ceiling is applied -- a ceiling would drop large LMS/XMSS signatures. */
if (dCert->signature != NULL && dCert->sigLength != 0) {
x509->sig.buffer = (byte*)XMALLOC(
dCert->sigLength, x509->heap, DYNAMIC_TYPE_SIGNATURE);
if (x509->sig.buffer == NULL) {
@@ -14572,9 +14596,9 @@ int CopyDecodedAcertToX509(WOLFSSL_X509_ACERT* x509, DecodedAcert* dAcert)
CopyDateToASN1_TIME(dAcert->afterDate, dAcert->afterDateLen,
&x509->notAfter);
/* Copy the signature. */
if (dAcert->signature != NULL && dAcert->sigLength != 0 &&
dAcert->sigLength <= MAX_ENCODED_SIG_SZ) {
/* Copy the signature. Sized to the exact parsed length (bounded by the
* cert DER); no fixed ceiling, so large LMS/XMSS signatures are kept. */
if (dAcert->signature != NULL && dAcert->sigLength != 0) {
x509->sig.buffer = (byte*)XMALLOC(
dAcert->sigLength, x509->heap, DYNAMIC_TYPE_SIGNATURE);
if (x509->sig.buffer == NULL) {
@@ -18797,7 +18821,7 @@ int DoHandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx,
if (ssl->options.handShakeState == HANDSHAKE_DONE && type == client_hello &&
ssl->options.side == WOLFSSL_SERVER_END) {
WOLFSSL_MSG("Renegotiation request rejected");
SendAlert(ssl, alert_fatal, no_renegotiation);
SendAlert(ssl, alert_warning, no_renegotiation);
WOLFSSL_ERROR_VERBOSE(SECURE_RENEGOTIATION_E);
return SECURE_RENEGOTIATION_E;
}
@@ -22468,6 +22492,9 @@ static int DoAlert(WOLFSSL* ssl, byte* input, word32* inOutIdx, int* type)
byte level;
byte code;
word32 dataSz = (word32)ssl->curSize;
#ifdef WOLFSSL_TLS13_IGNORE_PT_ALERT_ON_ENC
int ignorePtAlert;
#endif
#if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA)
if (ssl->hsInfoOn)
@@ -22496,9 +22523,19 @@ static int DoAlert(WOLFSSL* ssl, byte* input, word32* inOutIdx, int* type)
code = input[(*inOutIdx)++];
*type = code;
#ifdef WOLFSSL_TLS13_IGNORE_PT_ALERT_ON_ENC
/* Don't process alert when TLS 1.3 and encrypting but plaintext alert. */
if (!IsAtLeastTLSv1_3(ssl->version) || !IsEncryptionOn(ssl, 0) ||
ssl->keys.decryptedCur)
/* A plaintext alert received in TLS 1.3 once we are decrypting is only
* tolerated while still in the handshake and before the peer has sent an
* encrypted message. The peer sequence number is reset to zero each time
* decryption keys are installed and incremented for each record decrypted,
* so a non-zero value means the peer has sent an encrypted message and a
* plaintext alert is treated as an error. */
ignorePtAlert = IsAtLeastTLSv1_3(ssl->version) && IsEncryptionOn(ssl, 0) &&
!ssl->keys.decryptedCur && !ssl->options.handShakeDone &&
ssl->keys.peer_sequence_number_hi == 0 &&
ssl->keys.peer_sequence_number_lo == 0;
/* Don't record an ignored plaintext alert in the alert history. */
if (!ignorePtAlert)
#endif
{
ssl->alert_history.last_rx.code = code;
@@ -22529,16 +22566,21 @@ static int DoAlert(WOLFSSL* ssl, byte* input, word32* inOutIdx, int* type)
!ssl->keys.decryptedCur)
{
#ifdef WOLFSSL_TLS13_IGNORE_PT_ALERT_ON_ENC
/* Ignore alert if TLS 1.3 and encrypting but was plaintext alert. */
*type = invalid_alert;
level = alert_none;
#else
/* Unexpected message when encryption is on and alert not encrypted. */
SendAlert(ssl, alert_fatal, unexpected_message);
WOLFSSL_ERROR_VERBOSE(PARSE_ERROR);
return PARSE_ERROR;
if (ignorePtAlert) {
/* Ignore plaintext alert: TLS 1.3, decrypting, and the peer has
* not yet sent an encrypted handshake message. */
*type = invalid_alert;
level = alert_none;
}
else
#endif
{
/* Unexpected message when encryption is on and alert not
* encrypted. */
SendAlert(ssl, alert_fatal, unexpected_message);
WOLFSSL_ERROR_VERBOSE(PARSE_ERROR);
return PARSE_ERROR;
}
}
else {
if (*type == close_notify) {
@@ -25848,6 +25890,153 @@ int SendCertificate(WOLFSSL* ssl)
#if !defined(NO_TLS)
/* Returns the certificate_types this server advertises in its
* CertificateRequest. The list is broader than the negotiated cipher suite's
* own signature algorithm so a client may authenticate with a certificate of
* a different type (e.g. an RSA client on an ECDHE-ECDSA suite). */
WC_MAYBE_UNUSED static int GetServerCertReqCertTypes(const WOLFSSL* ssl,
byte* certTypes)
{
int n = 0;
(void)ssl;
(void)certTypes;
#ifdef HAVE_ECC
if ((ssl->options.cipherSuite0 == ECC_BYTE ||
ssl->options.cipherSuite0 == CHACHA_BYTE) &&
ssl->specs.sig_algo == ecc_dsa_sa_algo) {
certTypes[n++] = ecdsa_sign;
#ifndef NO_RSA
certTypes[n++] = rsa_sign;
#endif
}
else
#if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) && \
(defined(WOLFSSL_SM4_CBC) || defined(WOLFSSL_SM4_GCM) || \
defined(WOLFSSL_SM4_CCM))
if (ssl->options.cipherSuite0 == SM_BYTE && (0
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_SM4_CBC_SM3
|| ssl->options.cipherSuite == TLS_ECDHE_ECDSA_WITH_SM4_CBC_SM3
#endif
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_SM4_GCM_SM3
|| ssl->options.cipherSuite == TLS_ECDHE_ECDSA_WITH_SM4_GCM_SM3
#endif
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_SM4_CCM_SM3
|| ssl->options.cipherSuite == TLS_ECDHE_ECDSA_WITH_SM4_CCM_SM3
#endif
)) {
certTypes[n++] = ecdsa_sign;
}
else
#endif
#endif /* HAVE_ECC */
{
#ifndef NO_RSA
certTypes[n++] = rsa_sign;
#endif
#ifdef HAVE_ECC
certTypes[n++] = ecdsa_sign;
#endif
}
return n;
}
/* Returns the set of sig families covered by the given hash/sig algorithm
* list, as a bitmask of SIG_* values. Uses DecodeSigAlg so the NEW_SA_MAJOR
* encoding (ED25519/ED448/RSA-PSS-PSS/brainpool) is classified correctly. */
WC_MAYBE_UNUSED static int HashSigAlgoCoverage(const byte* hashSigAlgo,
word16 hashSigAlgoSz)
{
int coverage = 0;
word16 j;
byte hashAlgo;
byte sigAlgo;
for (j = 0; (j + 1) < hashSigAlgoSz; j += HELLO_EXT_SIGALGO_SZ) {
DecodeSigAlg(&hashSigAlgo[j], &hashAlgo, &sigAlgo);
(void)hashAlgo;
switch (sigAlgo) {
case rsa_sa_algo:
#ifdef WC_RSA_PSS
case rsa_pss_sa_algo:
case rsa_pss_pss_algo:
#endif
coverage |= SIG_RSA;
break;
#ifdef HAVE_ECC
case ecc_dsa_sa_algo:
#ifdef HAVE_ECC_BRAINPOOL
case ecc_brainpool_sa_algo:
#endif
#if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3)
case sm2_sa_algo:
#endif
coverage |= SIG_ECDSA;
break;
#endif
default:
break;
}
}
return coverage;
}
/* Builds the signature_algorithms this server advertises in its
* CertificateRequest. Respects a user-configured suites->hashSigAlgo (e.g.
* via wolfSSL_set1_sigalgs_list) and only broadens the list when one of the
* advertised certificate_types has no matching signature algorithm in the
* configured list. The result is written to the caller's buffer; no SSL
* state is modified. */
WC_MAYBE_UNUSED static void GetServerCertReqHashSigAlgo(const WOLFSSL* ssl,
byte* hashSigAlgo, word16* hashSigAlgoSz)
{
const Suites* suites = WOLFSSL_SUITES(ssl);
byte certTypes[MAX_CERT_REQ_CERT_TYPE_CNT];
int typeTotal;
int need = 0;
int have;
int j;
word16 localSz = 0;
typeTotal = GetServerCertReqCertTypes(ssl, certTypes);
for (j = 0; j < typeTotal; j++) {
if (certTypes[j] == rsa_sign)
need |= SIG_RSA;
else if (certTypes[j] == ecdsa_sign)
need |= SIG_ECDSA;
}
have = HashSigAlgoCoverage(suites->hashSigAlgo, suites->hashSigAlgoSz);
if ((need & ~have) != 0) {
/* The configured list is missing signature algorithms for at least
* one of the advertised certificate_types. Build a broader list
* locally that covers every advertised type. */
InitSuitesHashSigAlgo(hashSigAlgo, need | have, 1, 0,
ssl->buffers.keySz, &localSz);
*hashSigAlgoSz = localSz;
return;
}
XMEMCPY(hashSigAlgo, suites->hashSigAlgo, suites->hashSigAlgoSz);
*hashSigAlgoSz = suites->hashSigAlgoSz;
}
/* Returns 1 if algo (2 bytes) is in the server's CertificateRequest
* signature_algorithms list, 0 otherwise. Used to validate the client's
* CertificateVerify against what we actually advertised. */
WC_MAYBE_UNUSED static int InServerCertReqHashSigAlgo(const WOLFSSL* ssl,
const byte* algo)
{
byte list[WOLFSSL_MAX_SIGALGO];
word16 listSz = 0;
word16 j;
GetServerCertReqHashSigAlgo(ssl, list, &listSz);
for (j = 0; (j + 1) < listSz; j += HELLO_EXT_SIGALGO_SZ) {
if (XMEMCMP(&list[j], algo, HELLO_EXT_SIGALGO_SZ) == 0)
return 1;
}
return 0;
}
/* handle generation of certificate_request (13) */
int SendCertificateRequest(WOLFSSL* ssl)
{
@@ -25859,16 +26048,24 @@ int SendCertificateRequest(WOLFSSL* ssl)
#ifndef WOLFSSL_NO_CA_NAMES
WOLF_STACK_OF(WOLFSSL_X509_NAME)* names;
#endif
const Suites* suites = WOLFSSL_SUITES(ssl);
int typeTotal = 1; /* only 1 for now */
int reqSz = ENUM_LEN + typeTotal + REQ_HEADER_SZ; /* add auth later */
byte certTypes[MAX_CERT_REQ_CERT_TYPE_CNT];
int typeTotal;
int t;
byte localHashSigAlgo[WOLFSSL_MAX_SIGALGO];
word16 localHashSigAlgoSz = 0;
int reqSz;
WOLFSSL_START(WC_FUNC_CERTIFICATE_REQUEST_SEND);
WOLFSSL_ENTER("SendCertificateRequest");
typeTotal = GetServerCertReqCertTypes(ssl, certTypes);
if (IsAtLeastTLSv1_2(ssl))
reqSz += LENGTH_SZ + suites->hashSigAlgoSz;
GetServerCertReqHashSigAlgo(ssl, localHashSigAlgo, &localHashSigAlgoSz);
reqSz = ENUM_LEN + typeTotal + REQ_HEADER_SZ; /* add auth later */
if (IsAtLeastTLSv1_2(ssl))
reqSz += LENGTH_SZ + localHashSigAlgoSz;
#ifndef WOLFSSL_NO_CA_NAMES
/* Certificate Authorities */
@@ -25921,43 +26118,16 @@ int SendCertificateRequest(WOLFSSL* ssl)
/* write to output */
output[i++] = (byte)typeTotal; /* # of types */
#ifdef HAVE_ECC
if ((ssl->options.cipherSuite0 == ECC_BYTE ||
ssl->options.cipherSuite0 == CHACHA_BYTE) &&
ssl->specs.sig_algo == ecc_dsa_sa_algo) {
output[i++] = ecdsa_sign;
}
else
#if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) && \
(defined(WOLFSSL_SM4_CBC) || defined(WOLFSSL_SM4_GCM) || \
defined(WOLFSSL_SM4_CCM))
if (ssl->options.cipherSuite0 == SM_BYTE && (0
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_SM4_CBC_SM3
|| ssl->options.cipherSuite == TLS_ECDHE_ECDSA_WITH_SM4_CBC_SM3
#endif
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_SM4_GCM_SM3
|| ssl->options.cipherSuite == TLS_ECDHE_ECDSA_WITH_SM4_GCM_SM3
#endif
#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_SM4_CCM_SM3
|| ssl->options.cipherSuite == TLS_ECDHE_ECDSA_WITH_SM4_CCM_SM3
#endif
)) {
output[i++] = ecdsa_sign;
}
else
#endif
#endif /* HAVE_ECC */
{
output[i++] = rsa_sign;
}
for (t = 0; t < typeTotal; t++)
output[i++] = certTypes[t];
/* supported hash/sig */
if (IsAtLeastTLSv1_2(ssl)) {
c16toa(suites->hashSigAlgoSz, &output[i]);
c16toa(localHashSigAlgoSz, &output[i]);
i += OPAQUE16_LEN;
XMEMCPY(&output[i], suites->hashSigAlgo, suites->hashSigAlgoSz);
i += suites->hashSigAlgoSz;
XMEMCPY(&output[i], localHashSigAlgo, localHashSigAlgoSz);
i += localHashSigAlgoSz;
}
/* Certificate Authorities */
@@ -32335,6 +32505,14 @@ static void MakePSKPreMasterSecret(Arrays* arrays, byte use_psk_key)
if ((len > size) || ((*inOutIdx - begin) + len > size))
return BUFFER_ERROR;
/* Signature algorithm list is a sequence of 2-byte pairs; an odd
* length is malformed and must be rejected (matches TLS 1.3
* signature_algorithms extension parsing). */
if ((len % HELLO_EXT_SIGALGO_SZ) != 0) {
WOLFSSL_ERROR_VERBOSE(BUFFER_ERROR);
return BUFFER_ERROR;
}
if (PickHashSigAlgo(ssl, input + *inOutIdx, len, 0) != 0 &&
ssl->buffers.certificate &&
ssl->buffers.certificate->buffer) {
@@ -33648,12 +33826,14 @@ static int DoServerKeyExchange(WOLFSSL* ssl, const byte* input,
}
#endif
if (IsAtLeastTLSv1_2(ssl)) {
/* DigestInfo encoding for RSA, never a PQC
* signature -- size to the classic tier. */
WC_DECLARE_VAR(encodedSig, byte,
MAX_ENCODED_SIG_SZ, 0);
MAX_ENCODED_CLASSIC_SIG_SZ, 0);
word32 encSigSz;
WC_ALLOC_VAR_EX(encodedSig, byte,
MAX_ENCODED_SIG_SZ, ssl->heap,
MAX_ENCODED_CLASSIC_SIG_SZ, ssl->heap,
DYNAMIC_TYPE_SIGNATURE,
ERROR_OUT(MEMORY_E,exit_dske));
@@ -33663,7 +33843,9 @@ static int DoServerKeyExchange(WOLFSSL* ssl, const byte* input,
TypeHash(ssl->options.peerHashAlgo));
if (encSigSz != args->sigSz || !args->output ||
XMEMCMP(args->output, encodedSig,
min(encSigSz, MAX_ENCODED_SIG_SZ)) != 0) {
min(encSigSz,
MAX_ENCODED_CLASSIC_SIG_SZ))
!= 0) {
ret = VERIFY_SIGN_ERROR;
}
WC_FREE_VAR_EX(encodedSig, ssl->heap,
@@ -34964,9 +35146,14 @@ int SendCertificateVerify(WOLFSSL* ssl)
args->verify = &args->output[RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ];
args->extraSz = 0; /* tls 1.2 hash/sig */
/* build encoded signature buffer */
ssl->buffers.sig.length = MAX_ENCODED_SIG_SZ;
ssl->buffers.sig.buffer = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ,
/* Build encoded signature buffer. This is TLS 1.2 and earlier
* (TLS 1.3 uses SendTls13CertificateVerify), so the signature is
* always classic (RSA/ECC/EdDSA), never PQC -- size to the classic
* tier rather than the (potentially huge) PQC worst case. This
* comfortably holds an ECC/EdDSA signature written directly, or the
* PKCS#1 DigestInfo that is the input to RsaSign. */
ssl->buffers.sig.length = MAX_ENCODED_CLASSIC_SIG_SZ;
ssl->buffers.sig.buffer = (byte*)XMALLOC(MAX_ENCODED_CLASSIC_SIG_SZ,
ssl->heap, DYNAMIC_TYPE_SIGNATURE);
if (ssl->buffers.sig.buffer == NULL) {
ERROR_OUT(MEMORY_E, exit_scv);
@@ -36177,8 +36364,9 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
static int ReEncodeSig(WOLFSSL* ssl)
{ /* For TLS 1.2 re-encode signature */
if (IsAtLeastTLSv1_2(ssl)) {
byte* encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, ssl->heap,
DYNAMIC_TYPE_DIGEST);
/* DigestInfo encoding for RSA, never a PQC signature. */
byte* encodedSig = (byte*)XMALLOC(MAX_ENCODED_CLASSIC_SIG_SZ,
ssl->heap, DYNAMIC_TYPE_DIGEST);
if (encodedSig == NULL)
return MEMORY_E;
ssl->buffers.digest.length =
@@ -38135,6 +38323,32 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
ssl->options.resuming = 0;
return ret;
}
#if defined(HAVE_SESSION_TICKET) && \
(defined(HAVE_SNI) || defined(HAVE_ALPN))
/* Do not resume session if sniHash/alpnHash do not match. */
if (!ssl->options.useTicket) {
byte curHash[TICKET_BINDING_HASH_SZ];
#ifdef HAVE_SNI
if (TicketSniHash(ssl, curHash) != 0 ||
XMEMCMP(curHash, session->sniHash,
TICKET_BINDING_HASH_SZ) != 0) {
WOLFSSL_MSG("Resumed session SNI mismatch, full handshake");
ssl->options.resuming = 0;
return ret;
}
#endif
#ifdef HAVE_ALPN
if (ssl->options.resuming &&
(TicketAlpnHash(ssl, curHash) != 0 ||
XMEMCMP(curHash, session->alpnHash,
TICKET_BINDING_HASH_SZ) != 0)) {
WOLFSSL_MSG("Resumed session ALPN mismatch, full handshake");
ssl->options.resuming = 0;
return ret;
}
#endif
}
#endif /* HAVE_SESSION_TICKET && (HAVE_SNI || HAVE_ALPN) */
#if !defined(WOLFSSL_NO_TICKET_EXPIRE) && !defined(NO_ASN_TIME)
/* check if the ticket is valid */
if (LowResTimer() > session->bornOn + ssl->timeout) {
@@ -38660,6 +38874,14 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
*inOutIdx = i;
#if defined(HAVE_TLS_EXTENSIONS) && defined(HAVE_SUPPORTED_CURVES)
/* Reset per-ClientHello extension state before (re)parsing so a stale
* value from an earlier handshake on this object (e.g. secure
* renegotiation, where Options is not zeroed) cannot trigger a spurious
* RFC 8422 abort below. */
ssl->options.peerNoUncompPF = 0;
#endif
/* tls extensions */
if ((i - begin) < helloSz) {
#ifdef HAVE_TLS_EXTENSIONS
@@ -38716,8 +38938,22 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
#endif
#if defined(HAVE_SESSION_TICKET) && \
(defined(HAVE_SNI) || defined(HAVE_ALPN))
if((ret=VerifyTicketBinding(ssl)))
goto out;
/* Only verify here for TLS 1.2 ticket-based resumption.
* For stateful (session-ID) resumption ssl->session is
* not loaded until HandleTlsResumption runs below, which
* performs its own binding check against the cached
* session. On mismatch decline the resumption (RFC 6066
* Section 3) but proceed with a full handshake; leave
* useTicket set so the server still issues a fresh
* ticket to the client. */
if (ssl->options.useTicket &&
VerifyTicketBinding(ssl) != 0) {
WOLFSSL_MSG("Ticket binding mismatch, "
"declining resumption and falling back "
"to full handshake");
ssl->options.resuming = 0;
ssl->options.peerAuthGood = 0;
}
#endif
i += totalExtSz;
@@ -38858,6 +39094,25 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
if (ret == 0)
ret = MatchSuite(ssl, ssl->clSuites);
#if defined(HAVE_TLS_EXTENSIONS) && defined(HAVE_SUPPORTED_CURVES)
/* RFC 8422 Section 5.1.2: abort only when an ECC suite was actually
* negotiated and the client's ec_point_formats omitted the uncompressed
* (0) format (peerNoUncompPF, set in TLSX_PointFormat_Parse). Checked
* after MatchSuite so it keys off the chosen suite, not advertised
* groups. */
if (ret == 0 && ssl->options.peerNoUncompPF &&
(ssl->specs.kea == ecc_diffie_hellman_kea ||
ssl->specs.kea == ecc_static_diffie_hellman_kea ||
ssl->specs.kea == ecdhe_psk_kea)) {
WOLFSSL_MSG("Client ec_point_formats extension missing "
"uncompressed format for negotiated ECC suite");
SendAlert(ssl, alert_fatal, illegal_parameter);
ret = INVALID_PARAMETER;
WOLFSSL_ERROR_VERBOSE(ret);
goto out;
}
#endif
#if defined(HAVE_TLS_EXTENSIONS) && defined(HAVE_ENCRYPT_THEN_MAC) && \
!defined(WOLFSSL_AEAD_ONLY)
if (ret == 0 && ssl->options.encThenMac &&
@@ -38980,9 +39235,9 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
ERROR_OUT(BUFFER_ERROR, exit_dcv);
}
/* Check if hashSigAlgo in CertificateVerify is supported
* in our ssl->suites or ssl->ctx->suites. */
if (!SupportedHashSigAlgo(ssl, &input[args->idx])) {
/* Check the algorithm in CertificateVerify against the
* list we actually advertised in our CertificateRequest. */
if (!InServerCertReqHashSigAlgo(ssl, &input[args->idx])) {
WOLFSSL_MSG("Signature algorithm was not in "
"CertificateRequest");
ERROR_OUT(INVALID_PARAMETER, exit_dcv);
@@ -39272,10 +39527,12 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
else
#endif
{
/* DigestInfo encoding for RSA */
#ifndef WOLFSSL_SMALL_STACK
byte encodedSig[MAX_ENCODED_SIG_SZ];
byte encodedSig[MAX_ENCODED_CLASSIC_SIG_SZ];
#else
byte* encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ,
byte* encodedSig =
(byte*)XMALLOC(MAX_ENCODED_CLASSIC_SIG_SZ,
ssl->heap, DYNAMIC_TYPE_SIGNATURE);
if (encodedSig == NULL) {
ERROR_OUT(MEMORY_E, exit_dcv);
@@ -39290,7 +39547,7 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
if (args->sendSz != args->sigSz || !args->output ||
XMEMCMP(args->output, encodedSig,
min(args->sigSz, MAX_ENCODED_SIG_SZ)) != 0) {
min(args->sigSz, MAX_ENCODED_CLASSIC_SIG_SZ)) != 0) {
ret = VERIFY_CERT_ERROR;
}
@@ -39499,7 +39756,7 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
#ifdef HAVE_SNI
/* Hash server-selected SNI; zeros dst when none. */
static int TicketSniHash(WOLFSSL* ssl, byte* dst)
int TicketSniHash(WOLFSSL* ssl, byte* dst)
{
char* name = NULL;
word16 nameLen;
@@ -39519,16 +39776,23 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
#ifdef HAVE_ALPN
/* Hash negotiated ALPN; zeros dst when none. */
static int TicketAlpnHash(WOLFSSL* ssl, byte* dst)
int TicketAlpnHash(WOLFSSL* ssl, byte* dst)
{
char* proto = NULL;
word16 protoLen = 0;
TLSX* extension;
ALPN* alpn;
if (TLSX_ALPN_GetRequest(ssl->extensions, (void**)&proto,
&protoLen) == WOLFSSL_SUCCESS &&
proto != NULL && protoLen > 0) {
return wc_Hash(TICKET_BINDING_HASH_TYPE, (const byte*)proto,
protoLen, dst, TICKET_BINDING_HASH_SZ);
extension = TLSX_Find(ssl->extensions, TLSX_APPLICATION_LAYER_PROTOCOL);
if (extension != NULL) {
alpn = (ALPN*)extension->data;
if (alpn != NULL && alpn->negotiated == 1 &&
alpn->protocol_name != NULL) {
word32 protoLen = (word32)XSTRLEN(alpn->protocol_name);
if (protoLen > 0) {
return wc_Hash(TICKET_BINDING_HASH_TYPE,
(const byte*)alpn->protocol_name,
protoLen, dst, TICKET_BINDING_HASH_SZ);
}
}
}
XMEMSET(dst, 0, TICKET_BINDING_HASH_SZ);
@@ -39537,15 +39801,30 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
#endif
#if defined(HAVE_SNI) || defined(HAVE_ALPN)
/* Server-side: verify the SNI/ALPN bindings carried on a resumed
* session match what was negotiated for the current connection.
* Must be called after extension parsing and ALPN_Select.
* Returns 0 on match, WOLFSSL_FATAL_ERROR on mismatch. */
/* Server-side TLS 1.2 ticket-resumption binding check. Confirms the
* SNI/ALPN bound to the resumed session matches what was negotiated
* for the current connection. Must be called after extension
* parsing and ALPN_Select so the negotiated values are available,
* and only once DoClientTicketFinalize has populated
* ssl->session->sniHash/alpnHash from the decrypted ticket.
*
* Other resumption paths handle the same check themselves and do
* not use this function:
* - TLS 1.2 session-ID (stateful): HandleTlsResumption compares
* against the cached session at lookup time.
* - TLS 1.3 PSK: DoPreSharedKeys compares against each candidate
* ticket's bound hashes before committing, allowing the server
* to skip mismatching PSKs and pick the next one.
*
* Returns 0 on match, WOLFSSL_FATAL_ERROR on mismatch. The caller
* is responsible for the policy on mismatch -- RFC 6066 Section 3
* mandates declining the resumption and proceeding with a full
* handshake rather than aborting. */
int VerifyTicketBinding(WOLFSSL* ssl)
{
byte curHash[TICKET_BINDING_HASH_SZ];
if (!ssl->options.resuming || !ssl->options.useTicket)
if (!ssl->options.resuming)
return 0;
#ifdef HAVE_SNI
@@ -40054,8 +40333,9 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
ssl->sessionCtxSz) != 0))
return WOLFSSL_FATAL_ERROR;
#endif
/* SNI/ALPN binding is verified after ALPN_Select via
* VerifyTicketBinding(). */
/* SNI/ALPN binding is checked by the per-PSK loop in
* DoPreSharedKeys, not here, so that mismatching PSKs can be
* skipped in favor of the next candidate. */
return 0;
}
#endif /* WOLFSSL_SLT13 */
@@ -40151,8 +40431,13 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
}
}
#endif
/* Carry the ticket bindings on the session for the deferred
* VerifyTicketBinding() check. */
/* Carry the ticket bindings on the session. TLS 1.2 uses these
* for the deferred VerifyTicketBinding() check in DoClientHello
* (SNI/ALPN aren't known when DoClientTicket runs during
* extension parsing). TLS 1.3 checks bindings per-PSK before
* reaching this point, but still copies them so a subsequent
* SetupSession on a resumed session preserves them in the cache
* for future resumptions. */
#ifdef HAVE_SNI
XMEMCPY(ssl->session->sniHash, it->sniHash, TICKET_BINDING_HASH_SZ);
#endif
@@ -40518,8 +40803,9 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
goto cleanup;
}
/* SNI/ALPN binding is verified after ALPN_Select via
* VerifyTicketBinding(). */
/* SNI/ALPN binding is verified later in DoClientHello via
* VerifyTicketBinding(), once extension parsing and ALPN_Select
* have run and the negotiated values are available. */
DoClientTicketFinalize(ssl, it, NULL);
cleanup:
@@ -42643,6 +42929,27 @@ int wolfssl_local_GetRecordSize(WOLFSSL *ssl, int payloadSz, int isEncrypted)
return BAD_FUNC_ARG;
if (isEncrypted) {
/* AEAD overhead is constant per cache key (cipher, version, CID, DTLS
* 1.3 epoch); use the cached value when available. DTLS 1.3 pads
* records up to Dtls13MinimumRecordLength() (RFC 9147 5.5), so:
* - on read: only return the cached overhead when the resulting
* record would not be padded;
* - on populate: only store the overhead when BuildMessage returned
* a record strictly above the minimum, which guarantees no
* padding was applied. */
#ifdef WOLFSSL_DTLS13
int isDtls13 = ssl->options.dtls && ssl->options.tls1_3;
#endif
if (ssl->specs.cipher_type == aead && ssl->recordSzOverhead != 0
#ifdef WOLFSSL_DTLS13
&& (!isDtls13 || payloadSz + (int)ssl->recordSzOverhead
>= Dtls13MinimumRecordLength(ssl))
#endif
) {
return payloadSz + (int)ssl->recordSzOverhead;
}
recordSz = BuildMessage(ssl, NULL, 0, NULL, payloadSz, application_data,
0, 1, 0, CUR_ORDER);
/* use a safe upper bound in case of error */
@@ -42653,6 +42960,14 @@ int wolfssl_local_GetRecordSize(WOLFSSL *ssl, int payloadSz, int isEncrypted)
recordSz += DTLS_RECORD_EXTRA;
}
}
else if (ssl->specs.cipher_type == aead && recordSz > payloadSz
#ifdef WOLFSSL_DTLS13
&& (!isDtls13 || recordSz > Dtls13MinimumRecordLength(ssl))
#endif
) {
/* Populate cache only on success; never from the fallback. */
ssl->recordSzOverhead = (word32)(recordSz - payloadSz);
}
}
else {
recordSz = payloadSz + RECORD_HEADER_SZ;
+6
View File
@@ -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) {
+6 -87
View File
@@ -21,15 +21,6 @@
#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
/* Name change compatibility layer no longer needs to be included here */
/*
* WOLFSSL_NO_OCSP_ISSUER_CHAIN_CHECK:
* Disable looking for an authorized responder in the verification path of
* the issuer. This will make the authorized responder only look at the
* OCSP response signer and direct issuer.
*/
/*
* OCSP responder missing features:
* - Support for multiple requests and responses in a single OCSP exchange
@@ -590,80 +581,13 @@ int CheckOcspRequest(WOLFSSL_OCSP* ocsp, OcspRequest* ocspRequest,
return ret;
}
#ifndef WOLFSSL_NO_OCSP_ISSUER_CHAIN_CHECK
static int CheckOcspResponderChain(OcspEntry* single, byte* issuerNameHash,
byte* issuerKeyHash, void* vp, Signer* pendingCAs) {
/* Attempt to build a chain up to cert's issuer */
WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)vp;
Signer* ca = NULL;
Signer* prev = NULL;
int passed = 0;
/*
* Relation between certs:
* CA
* / \
* intermediate(s) cert in OCSP response
* | with OCSP key usage ext
* issuer of cert
* in OCSP request
*/
if (issuerKeyHash == NULL)
return 0;
/* Select CertID issuer by key hash so a same-DN / different-key trust
* anchor cannot hijack the starting point. */
ca = GetCAByKeyHash(cm, single->issuerKeyHash);
if (ca != NULL && XMEMCMP(ca->subjectNameHash, single->issuerHash,
OCSP_DIGEST_SIZE) != 0) {
ca = NULL;
}
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
if (ca == NULL && pendingCAs != NULL) {
ca = findSignerByKeyHash(pendingCAs, single->issuerKeyHash);
if (ca != NULL && XMEMCMP(ca->subjectNameHash, single->issuerHash,
OCSP_DIGEST_SIZE) != 0) {
ca = NULL;
}
}
#else
(void)pendingCAs;
#endif
for (; ca != NULL && ca != prev;
prev = ca) {
Signer* parent = GetCAByName(cm, ca->issuerNameHash);
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
if (parent == NULL && pendingCAs != NULL) {
parent = findSignerByName(pendingCAs, ca->issuerNameHash);
}
#endif
if (parent == NULL || parent == ca)
break;
if (XMEMCMP(parent->subjectNameHash, issuerNameHash,
OCSP_DIGEST_SIZE) == 0 &&
XMEMCMP(parent->subjectKeyHash, issuerKeyHash,
KEYID_SIZE) == 0) {
WOLFSSL_MSG("\tOCSP Response signed by authorized "
"responder delegated by issuer "
"(found in chain)");
passed = 1;
break;
}
ca = parent;
}
return passed;
}
#endif
/* Enforce https://www.rfc-editor.org/rfc/rfc6960#section-4.2.2.2. Both halves
* of CertID (issuerNameHash and issuerKeyHash) must match; name-only matching
* would authorize a same-DN / different-key CA. issuerKeyHash may be NULL when
* unavailable, which disables the delegated branch. */
int CheckOcspResponder(OcspResponse *bs, byte* subjectNameHash,
byte* subjectKeyHash, byte extExtKeyUsage, byte* issuerNameHash,
byte* issuerKeyHash, void* vp)
byte* issuerKeyHash)
{
int ret = 0;
OcspEntry* single;
@@ -671,8 +595,6 @@ int CheckOcspResponder(OcspResponse *bs, byte* subjectNameHash,
/* Both evaluate to enum values so can't use a pre-processor check */
WOLFSSL_ASSERT_EQ(OCSP_DIGEST_SIZE, SIGNER_DIGEST_SIZE);
(void)vp;
WOLFSSL_ENTER("CheckOcspResponder");
/* In the future if this API is used more then it could be beneficial to
@@ -702,12 +624,6 @@ int CheckOcspResponder(OcspResponse *bs, byte* subjectNameHash,
"delegated by issuer");
passed = 1;
}
#ifndef WOLFSSL_NO_OCSP_ISSUER_CHAIN_CHECK
else if (vp != NULL) {
passed = CheckOcspResponderChain(single, issuerNameHash,
issuerKeyHash, vp, bs->pendingCAs);
}
#endif
}
if (!passed) {
@@ -1112,8 +1028,7 @@ static int OcspVerifySigner(WOLFSSL_OCSP_BASICRESP *resp, DecodedCert *cert,
if ((flags & WOLFSSL_OCSP_NOCHECKS) == 0) {
ret = CheckOcspResponder(resp, c->subjectHash, c->subjectKeyHash,
c->extExtKeyUsage, c->issuerHash,
(c->ca != NULL) ? c->ca->subjectKeyHash : NULL,
st->cm);
(c->ca != NULL) ? c->ca->subjectKeyHash : NULL);
}
else {
ret = 0;
@@ -1273,6 +1188,10 @@ OcspResponse* wolfSSL_d2i_OCSP_RESPONSE(OcspResponse** response,
if (data == NULL || *data == NULL || len <= 0)
return NULL;
if (*data == NULL)
return NULL;
if (len <= 0)
return NULL;
if (response != NULL)
resp = *response;
+1 -2
View File
@@ -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;
}
+6 -1
View File
@@ -449,6 +449,8 @@ static WOLFSSL_EC_GROUP* wolfssl_ec_group_d2i(WOLFSSL_EC_GROUP** group,
if (in_pp == NULL || *in_pp == NULL)
return NULL;
if (inSz <= 0)
return NULL;
in = *in_pp;
@@ -4998,7 +5000,10 @@ WOLFSSL_ECDSA_SIG* wolfSSL_d2i_ECDSA_SIG(WOLFSSL_ECDSA_SIG** sig,
WOLFSSL_ECDSA_SIG *s = NULL;
/* Validate parameter. */
if (pp == NULL) {
if (pp == NULL || *pp == NULL) {
err = 1;
}
if ((!err) && (len <= 0)) {
err = 1;
}
if (!err) {
+12 -4
View File
@@ -454,6 +454,10 @@ WOLFSSL_RSA *wolfSSL_d2i_RSAPublicKey(WOLFSSL_RSA **out,
WOLFSSL_ERROR_MSG("Bad argument");
err = 1;
}
if ((!err) && (derSz <= 0)) {
WOLFSSL_ERROR_MSG("Bad argument");
err = 1;
}
/* Create a new RSA key to return. */
if ((!err) && ((rsa = wolfSSL_RSA_new()) == NULL)) {
WOLFSSL_ERROR_MSG("RSA_new failed");
@@ -503,6 +507,10 @@ WOLFSSL_RSA *wolfSSL_d2i_RSAPrivateKey(WOLFSSL_RSA **out,
WOLFSSL_ERROR_MSG("Bad argument");
err = 1;
}
if ((!err) && (derSz <= 0)) {
WOLFSSL_ERROR_MSG("Bad argument");
err = 1;
}
/* Create a new RSA key to return. */
if ((!err) && ((rsa = wolfSSL_RSA_new()) == NULL)) {
WOLFSSL_ERROR_MSG("RSA_new failed");
@@ -3109,7 +3117,7 @@ int wolfSSL_RSA_sign_mgf(int hashAlg, const unsigned char* hash,
#else
WC_RNG _tmpRng[1];
WC_RNG* tmpRng = _tmpRng;
byte encodedSig[MAX_ENCODED_SIG_SZ];
byte encodedSig[MAX_ENCODED_CLASSIC_SIG_SZ];
#endif
unsigned int encSz = 0;
@@ -3150,7 +3158,7 @@ int wolfSSL_RSA_sign_mgf(int hashAlg, const unsigned char* hash,
#ifdef WOLFSSL_SMALL_STACK
if (ret == 1) {
/* Allocate encoded signature buffer if doing PKCS#1 padding. */
encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, NULL,
encodedSig = (byte*)XMALLOC(MAX_ENCODED_CLASSIC_SIG_SZ, NULL,
DYNAMIC_TYPE_SIGNATURE);
if (encodedSig == NULL) {
ret = 0;
@@ -3306,10 +3314,10 @@ int wolfSSL_RSA_verify_mgf(int hashAlg, const unsigned char* hash,
#ifdef WOLFSSL_SMALL_STACK
unsigned char* encodedSig = NULL;
#else
unsigned char encodedSig[MAX_ENCODED_SIG_SZ];
unsigned char encodedSig[MAX_ENCODED_CLASSIC_SIG_SZ];
#endif
unsigned char* sigDec = NULL;
unsigned int len = MAX_ENCODED_SIG_SZ;
unsigned int len = MAX_ENCODED_CLASSIC_SIG_SZ;
int verLen = 0;
#if (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5, 1)) && !defined(HAVE_SELFTEST)
enum wc_HashType hType = WC_HASH_TYPE_NONE;
+37 -4096
View File
File diff suppressed because it is too large Load Diff
+772 -15
View File
@@ -42,6 +42,7 @@ int wolfSSL_CTX_mutual_auth(WOLFSSL_CTX* ctx, int req)
{
if (ctx == NULL)
return BAD_FUNC_ARG;
/* Mutual authentication is a server-side only setting. */
if (ctx->method->side != WOLFSSL_SERVER_END)
return SIDE_ERROR;
@@ -63,6 +64,7 @@ int wolfSSL_mutual_auth(WOLFSSL* ssl, int req)
{
if (ssl == NULL)
return BAD_FUNC_ARG;
/* Mutual authentication is a server-side only setting. */
if (ssl->options.side != WOLFSSL_SERVER_END)
return SIDE_ERROR;
@@ -81,7 +83,8 @@ WOLFSSL_CERT_MANAGER* wolfSSL_CTX_GetCertManager(WOLFSSL_CTX* ctx)
{
WOLFSSL_CERT_MANAGER* cm = NULL;
if (ctx)
/* The certificate manager is owned by the context. */
if (ctx != NULL)
cm = ctx->cm;
return cm;
@@ -98,6 +101,7 @@ void wolfSSL_CTX_set_verify_depth(WOLFSSL_CTX *ctx, int depth)
{
WOLFSSL_ENTER("wolfSSL_CTX_set_verify_depth");
/* Reject out-of-range depths; valid range is 0 to MAX_CHAIN_DEPTH. */
if ((ctx == NULL) || (depth < 0) || (depth > MAX_CHAIN_DEPTH)) {
WOLFSSL_MSG("Bad depth argument, too large or less than 0");
}
@@ -121,6 +125,8 @@ long wolfSSL_CTX_get_verify_depth(WOLFSSL_CTX* ctx)
ret = BAD_FUNC_ARG;
}
else {
/* A configurable depth is only tracked with the OpenSSL extra APIs;
* otherwise the fixed maximum chain depth applies. */
#ifndef OPENSSL_EXTRA
ret = MAX_CHAIN_DEPTH;
#else
@@ -145,6 +151,8 @@ long wolfSSL_get_verify_depth(WOLFSSL* ssl)
ret = BAD_FUNC_ARG;
}
else {
/* A configurable depth is only tracked with the OpenSSL extra APIs;
* otherwise the fixed maximum chain depth applies. */
#ifndef OPENSSL_EXTRA
ret = MAX_CHAIN_DEPTH;
#else
@@ -168,7 +176,7 @@ long wolfSSL_get_verify_depth(WOLFSSL* ssl)
static int isArrayUnique(const char* buf, size_t len)
{
size_t i;
/* check the array is unique */
/* Check the array is unique. */
for (i = 0; i < len - 1; ++i) {
size_t j;
for (j = i + 1; j < len; ++j) {
@@ -260,6 +268,7 @@ int wolfSSL_CTX_set_client_cert_type(WOLFSSL_CTX* ctx, const char* buf, int len)
ret = BAD_FUNC_ARG;
}
else {
/* A side value of 1 records these as the client certificate types. */
ret = set_cert_type(&ctx->rpkConfig, 1, buf, len);
}
@@ -284,6 +293,7 @@ int wolfSSL_CTX_set_server_cert_type(WOLFSSL_CTX* ctx, const char* buf, int len)
ret = BAD_FUNC_ARG;
}
else {
/* A side value of 0 records these as the server certificate types. */
ret = set_cert_type(&ctx->rpkConfig, 0, buf, len);
}
@@ -308,6 +318,7 @@ int wolfSSL_set_client_cert_type(WOLFSSL* ssl, const char* buf, int len)
ret = BAD_FUNC_ARG;
}
else {
/* A side value of 1 records these as the client certificate types. */
ret = set_cert_type(&ssl->options.rpkConfig, 1, buf, len);
}
@@ -332,6 +343,7 @@ int wolfSSL_set_server_cert_type(WOLFSSL* ssl, const char* buf, int len)
ret = BAD_FUNC_ARG;
}
else {
/* A side value of 0 records these as the server certificate types. */
ret = set_cert_type(&ssl->options.rpkConfig, 0, buf, len);
}
@@ -627,7 +639,7 @@ int wolfSSL_verify_client_post_handshake(WOLFSSL* ssl)
ret = wolfSSL_request_certificate(ssl);
if (ret != 1) {
/* Special logging for wrong protocol version. */
if ((ssl != NULL) && !IsAtLeastTLSv1_3(ssl->version)) {
if ((ssl != NULL) && (!IsAtLeastTLSv1_3(ssl->version))) {
WOLFSSL_ERROR(UNSUPPORTED_PROTO_VERSION);
}
else {
@@ -851,7 +863,7 @@ int wolfSSL_UnloadCertsKeys(WOLFSSL* ssl)
ret = BAD_FUNC_ARG;
}
else {
if (ssl->buffers.weOwnCert && !ssl->keepCert) {
if (ssl->buffers.weOwnCert && (!ssl->keepCert)) {
WOLFSSL_MSG("Unloading cert");
FreeDer(&ssl->buffers.certificate);
#ifdef KEEP_OUR_CERT
@@ -869,7 +881,7 @@ int wolfSSL_UnloadCertsKeys(WOLFSSL* ssl)
if (ssl->buffers.weOwnKey) {
WOLFSSL_MSG("Unloading key");
if (ssl->buffers.key != NULL && ssl->buffers.key->buffer != NULL)
if ((ssl->buffers.key != NULL) && (ssl->buffers.key->buffer != NULL))
ForceZero(ssl->buffers.key->buffer, ssl->buffers.key->length);
FreeDer(&ssl->buffers.key);
#ifdef WOLFSSL_BLIND_PRIVATE_KEY
@@ -881,8 +893,8 @@ int wolfSSL_UnloadCertsKeys(WOLFSSL* ssl)
#ifdef WOLFSSL_DUAL_ALG_CERTS
if (ssl->buffers.weOwnAltKey) {
WOLFSSL_MSG("Unloading alt key");
if (ssl->buffers.altKey != NULL &&
ssl->buffers.altKey->buffer != NULL) {
if ((ssl->buffers.altKey != NULL) &&
(ssl->buffers.altKey->buffer != NULL)) {
ForceZero(ssl->buffers.altKey->buffer,
ssl->buffers.altKey->length);
}
@@ -1028,11 +1040,13 @@ static int add_to_ca_names_list(WOLFSSL_STACK* ca_names, WOLFSSL_X509* x509)
int ret = 1;
WOLFSSL_X509_NAME *nameCopy = NULL;
/* The list owns its names, so push a copy of the subject name. */
nameCopy = wolfSSL_X509_NAME_dup(wolfSSL_X509_get_subject_name(x509));
if (nameCopy == NULL) {
WOLFSSL_MSG("wolfSSL_X509_NAME_dup error");
ret = 0;
}
/* On push failure the copy is not owned by the list - free it here. */
else if (wolfSSL_sk_X509_NAME_push(ca_names, nameCopy) <= 0) {
WOLFSSL_MSG("wolfSSL_sk_X509_NAME_push error");
wolfSSL_X509_NAME_free(nameCopy);
@@ -1435,7 +1449,7 @@ WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_load_client_CA_file(const char* fname)
}
/* Read each certificate in the chain out of the file. */
while (!err && wolfSSL_PEM_read_bio_X509(bio, &cert, NULL, NULL) != NULL) {
while ((!err) && (wolfSSL_PEM_read_bio_X509(bio, &cert, NULL, NULL) != NULL)) {
WOLFSSL_X509_NAME *nameCopy;
/* Need a persistent copy of the subject name. */
@@ -1730,15 +1744,15 @@ WOLFSSL_X509* wolfSSL_get_certificate(WOLFSSL* ssl)
* a new X509. This maintains pointer compatibility with
* applications (like nginx OCSP stapling) that use the X509 pointer
* from SSL_CTX_use_certificate as a lookup key. */
if (ssl->ctx != NULL && ssl->ctx->ourCert != NULL) {
if ((ssl->ctx != NULL) && (ssl->ctx->ourCert != NULL)) {
/* Compare cert buffers to make sure they are the same */
if (ssl->buffers.certificate == NULL ||
ssl->buffers.certificate->buffer == NULL ||
(ssl->buffers.certificate->length ==
ssl->ctx->certificate->length &&
XMEMCMP(ssl->buffers.certificate->buffer,
if ((ssl->buffers.certificate == NULL) ||
(ssl->buffers.certificate->buffer == NULL) ||
((ssl->buffers.certificate->length ==
ssl->ctx->certificate->length) &&
(XMEMCMP(ssl->buffers.certificate->buffer,
ssl->ctx->certificate->buffer,
ssl->buffers.certificate->length) == 0)) {
ssl->buffers.certificate->length) == 0))) {
return ssl->ctx->ourCert;
}
}
@@ -1769,4 +1783,747 @@ WOLFSSL_X509* wolfSSL_get_certificate(WOLFSSL* ssl)
#endif /* !NO_CERTS */
#ifndef WOLFCRYPT_ONLY
#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)
/* Get the index at which the object is stored in an X509 store context's
* external data.
*
* @return Index of the SSL/TLS object (0).
*/
int wolfSSL_get_ex_data_X509_STORE_CTX_idx(void)
{
WOLFSSL_ENTER("wolfSSL_get_ex_data_X509_STORE_CTX_idx");
/* store SSL at index 0 */
return 0;
}
#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) || \
defined(OPENSSL_ALL)
/* Get the result of peer certificate verification.
*
* @param [in] ssl SSL/TLS object.
* @return Verification result code on success.
* @return WOLFSSL_X509_V_ERR_APPLICATION_VERIFICATION when ssl is NULL.
*/
long wolfSSL_get_verify_result(const WOLFSSL *ssl)
{
long ret;
if (ssl == NULL) {
/* Return a non-zero error so the OpenSSL-idiomatic
* "!= X509_V_OK" check does not mistake a NULL ssl for a
* successful verification (X509_V_OK is 0). */
ret = WOLFSSL_X509_V_ERR_APPLICATION_VERIFICATION;
}
else {
/* Result of verifying the peer's certificate chain. */
ret = (long)ssl->peerVerifyRet;
}
return ret;
}
#endif
#if defined(OPENSSL_EXTRA) && defined(KEEP_PEER_CERT) && \
defined(HAVE_EX_DATA) && !defined(NO_FILESYSTEM)
/* Compare the peer's certificate against a PEM certificate file.
*
* @param [in] ssl SSL/TLS object.
* @param [in] fname Path to a PEM certificate file.
* @return 0 when the certificates match.
* @return WOLFSSL_FATAL_ERROR when arguments are NULL or they do not match.
* @return WOLFSSL_BAD_FILE when the file cannot be read.
*/
int wolfSSL_cmp_peer_cert_to_file(WOLFSSL* ssl, const char *fname)
{
int ret;
WOLFSSL_ENTER("wolfSSL_cmp_peer_cert_to_file");
if ((ssl == NULL) || (fname == NULL)) {
ret = WOLFSSL_FATAL_ERROR;
}
else {
#ifdef WOLFSSL_SMALL_STACK
byte staticBuffer[1]; /* force heap usage */
#else
byte staticBuffer[FILE_BUFFER_SIZE];
#endif
byte* myBuf = staticBuffer;
XFILE file;
long sz = 0;
void* heap = ssl->ctx->heap;
WOLFSSL_X509* peer_cert = &ssl->peerCert;
DerBuffer* fileDer = NULL;
/* Open the file and determine its size. From here, ret == 0
* indicates processing is still on track. */
file = XFOPEN(fname, "rb");
ret = wolfssl_file_len(file, &sz);
/* Use a heap buffer when the file is bigger than the stack buffer. */
if ((ret == 0) && (sz > (long)sizeof(staticBuffer))) {
WOLFSSL_MSG("Getting dynamic buffer");
myBuf = (byte*)XMALLOC((size_t)sz, heap, DYNAMIC_TYPE_FILE);
if (myBuf == NULL) {
ret = WOLFSSL_FATAL_ERROR;
}
}
/* Read the whole file into the buffer. */
if ((ret == 0) && (XFREAD(myBuf, 1, (size_t)sz, file) != (size_t)sz)) {
ret = WOLFSSL_FATAL_ERROR;
}
/* Convert the PEM file contents to DER. */
if ((ret == 0) && (PemToDer(myBuf, sz, CERT_TYPE, &fileDer, heap, NULL,
NULL) != 0)) {
ret = WOLFSSL_FATAL_ERROR;
}
/* Peer certificate matches when the DER lengths and bytes are equal. */
if ((ret == 0) && ((fileDer->length == 0) ||
(fileDer->length != peer_cert->derCert->length) ||
(XMEMCMP(peer_cert->derCert->buffer, fileDer->buffer,
fileDer->length) != 0))) {
ret = WOLFSSL_FATAL_ERROR;
}
/* Dispose of the DER, any heap buffer and close the file. */
FreeDer(&fileDer);
if (myBuf != staticBuffer) {
XFREE(myBuf, heap, DYNAMIC_TYPE_FILE);
}
if (file != XBADFILE) {
XFCLOSE(file);
}
}
return ret;
}
#endif
#ifdef WOLFSSL_ALT_CERT_CHAINS
/* Determine whether the peer was verified using an alternate cert chain.
*
* @param [in] ssl SSL/TLS object.
* @return 1 when an alternate certificate chain was used.
* @return 0 otherwise, or when ssl is NULL.
*/
int wolfSSL_is_peer_alt_cert_chain(const WOLFSSL* ssl)
{
return (ssl != NULL) && ssl->options.usingAltCertChain;
}
#endif /* WOLFSSL_ALT_CERT_CHAINS */
#ifdef SESSION_CERTS
#ifdef WOLFSSL_ALT_CERT_CHAINS
/* Get the peer's alternate certificate chain.
*
* @param [in] ssl SSL/TLS object.
* @return Alternate certificate chain on success.
* @return NULL when ssl is NULL.
*/
WOLFSSL_X509_CHAIN* wolfSSL_get_peer_alt_chain(WOLFSSL* ssl)
{
WOLFSSL_X509_CHAIN* chain = NULL;
WOLFSSL_ENTER("wolfSSL_get_peer_alt_chain");
if (ssl != NULL) {
/* The alternate chain is held within the session. */
chain = &ssl->session->altChain;
}
return chain;
}
#endif /* WOLFSSL_ALT_CERT_CHAINS */
/* Get the peer's certificate chain.
*
* @param [in] ssl SSL/TLS object.
* @return Certificate chain on success.
* @return NULL when ssl is NULL.
*/
WOLFSSL_X509_CHAIN* wolfSSL_get_peer_chain(WOLFSSL* ssl)
{
WOLFSSL_X509_CHAIN* chain = NULL;
WOLFSSL_ENTER("wolfSSL_get_peer_chain");
if (ssl != NULL) {
/* The peer chain is held within the session. */
chain = &ssl->session->chain;
}
return chain;
}
/* Get the number of certificates in a certificate chain.
*
* @param [in] chain Certificate chain object.
* @return Number of certificates on success.
* @return 0 when chain is NULL.
*/
int wolfSSL_get_chain_count(WOLFSSL_X509_CHAIN* chain)
{
int count = 0;
WOLFSSL_ENTER("wolfSSL_get_chain_count");
if (chain != NULL) {
/* Number of certificates captured in the chain. */
count = chain->count;
}
return count;
}
/* Get the length, in bytes, of the DER certificate at an index in a chain.
*
* @param [in] chain Certificate chain object.
* @param [in] idx Index of the certificate in the chain.
* @return Length of the DER certificate in bytes on success.
* @return 0 when chain is NULL or idx is out of range.
*/
int wolfSSL_get_chain_length(WOLFSSL_X509_CHAIN* chain, int idx)
{
int length = 0;
WOLFSSL_ENTER("wolfSSL_get_chain_length");
if ((chain != NULL) && (idx >= 0) && (idx < chain->count)) {
/* DER length of the certificate stored at the given index. */
length = chain->certs[idx].length;
}
return length;
}
/* Get the DER certificate at an index in a certificate chain.
*
* @param [in] chain Certificate chain object.
* @param [in] idx Index of the certificate in the chain.
* @return Buffer holding the DER certificate on success.
* @return 0 when chain is NULL or idx is out of range.
*/
byte* wolfSSL_get_chain_cert(WOLFSSL_X509_CHAIN* chain, int idx)
{
byte* cert = NULL;
WOLFSSL_ENTER("wolfSSL_get_chain_cert");
if ((chain != NULL) && (idx >= 0) && (idx < chain->count)) {
/* DER buffer of the certificate stored at the given index. */
cert = chain->certs[idx].buffer;
}
return cert;
}
/* Decode DER certificate data into a WOLFSSL_X509 object. Defined in
* src/ssl.c. */
static int DecodeToX509(WOLFSSL_X509* x509, const byte* in, int len);
/* Get the certificate at an index in a chain as a new X509 object.
*
* The returned object must be freed by the caller with wolfSSL_X509_free().
*
* @param [in] chain Certificate chain object.
* @param [in] idx Index of the certificate in the chain.
* @return Newly allocated X509 certificate object on success.
* @return NULL when chain is NULL, idx is out of range or on error.
*/
WOLFSSL_X509* wolfSSL_get_chain_X509(WOLFSSL_X509_CHAIN* chain, int idx)
{
WOLFSSL_X509* x509 = NULL;
WOLFSSL_ENTER("wolfSSL_get_chain_X509");
if ((chain != NULL) && (idx >= 0) && (idx < chain->count)) {
x509 = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), NULL,
DYNAMIC_TYPE_X509);
if (x509 == NULL) {
WOLFSSL_MSG("Failed alloc X509");
}
else {
/* Pre-init with dynamicMemory=1 so DecodeToX509 skips its own
* InitX509 (and we still own the buffer for X509_free). */
InitX509(x509, 1, NULL);
if (DecodeToX509(x509, chain->certs[idx].buffer,
chain->certs[idx].length) != 0) {
WOLFSSL_MSG("Failed to decode cert");
wolfSSL_X509_free(x509);
x509 = NULL;
}
}
}
return x509;
}
/* Get the certificate at an index in a chain as PEM.
*
* When buf is NULL, the length required is returned in outLen.
*
* @param [in] chain Certificate chain object.
* @param [in] idx Index of the certificate in the chain.
* @param [out] buf Buffer to hold PEM. May be NULL to get the length.
* @param [in] inLen Length of buffer in bytes.
* @param [out] outLen Length of PEM data in bytes.
* @return WOLFSSL_SUCCESS on success.
* @return LENGTH_ONLY_E when buf is NULL and outLen has been set.
* @return BAD_FUNC_ARG when a required argument is NULL or idx is invalid.
* @return WOLFSSL_FAILURE on error.
*/
int wolfSSL_get_chain_cert_pem(WOLFSSL_X509_CHAIN* chain, int idx,
unsigned char* buf, int inLen, int* outLen)
{
#ifdef WOLFSSL_DER_TO_PEM
int ret = WOLFSSL_SUCCESS;
WOLFSSL_ENTER("wolfSSL_get_chain_cert_pem");
if ((chain == NULL) || (outLen == NULL) || (idx < 0) ||
(idx >= wolfSSL_get_chain_count(chain))) {
ret = BAD_FUNC_ARG;
}
/* Delegate to wc_DerToPem when DER-to-PEM is available. */
if (ret == WOLFSSL_SUCCESS) {
if (buf == NULL) {
inLen = 0;
}
else if (inLen < 0) {
ret = BAD_FUNC_ARG;
}
}
if (ret == WOLFSSL_SUCCESS) {
int n = wc_DerToPem(chain->certs[idx].buffer,
(word32)chain->certs[idx].length, buf, (word32)inLen, CERT_TYPE);
if (n < 0) {
if (buf == NULL) {
ret = WOLFSSL_FAILURE;
}
else {
ret = n;
}
}
else {
*outLen = n;
if (buf == NULL) {
ret = WC_NO_ERR_TRACE(LENGTH_ONLY_E);
}
}
}
return ret;
#elif defined(WOLFSSL_PEM_TO_DER)
int ret = WOLFSSL_SUCCESS;
const char* header = NULL;
const char* footer = NULL;
int headerLen;
int footerLen;
int i;
int err;
WOLFSSL_ENTER("wolfSSL_get_chain_cert_pem");
if ((chain == NULL) || (outLen == NULL) || (idx < 0) ||
(idx >= wolfSSL_get_chain_count(chain))) {
ret = BAD_FUNC_ARG;
}
if (ret == WOLFSSL_SUCCESS) {
if ((err = wc_PemGetHeaderFooter(CERT_TYPE, &header, &footer)) != 0) {
ret = err;
}
}
if (ret == WOLFSSL_SUCCESS) {
headerLen = (int)XSTRLEN(header);
footerLen = (int)XSTRLEN(footer);
/* Null output buffer returns size needed in outLen. */
if (buf == NULL) {
word32 szNeeded = 0;
if (Base64_Encode(chain->certs[idx].buffer,
(word32)chain->certs[idx].length, NULL,
&szNeeded) != WC_NO_ERR_TRACE(LENGTH_ONLY_E)) {
ret = WOLFSSL_FAILURE;
}
else {
*outLen = (int)szNeeded + headerLen + footerLen;
ret = WC_NO_ERR_TRACE(LENGTH_ONLY_E);
}
}
/* buf == NULL, ret will not be WOLFSSL_SUCCESS. */
}
/* Don't even try when inLen is too short. */
if ((ret == WOLFSSL_SUCCESS) &&
(inLen < headerLen + footerLen + chain->certs[idx].length)) {
ret = BAD_FUNC_ARG;
}
if (ret == WOLFSSL_SUCCESS) {
/* Write the PEM header. */
XMEMCPY(buf, header, (size_t)headerLen);
i = headerLen;
/* Space left for Base64 data after header and before footer. */
*outLen = inLen - headerLen - footerLen;
if ((err = Base64_Encode(chain->certs[idx].buffer,
(word32)chain->certs[idx].length, buf + i,
(word32*)outLen)) < 0) {
ret = err;
}
}
if (ret == WOLFSSL_SUCCESS) {
i += *outLen;
/* Write the PEM footer. */
XMEMCPY(buf + i, footer, (size_t)footerLen);
*outLen += headerLen + footerLen;
}
return ret;
#else
(void)chain;
(void)idx;
(void)buf;
(void)inLen;
(void)outLen;
return WOLFSSL_FAILURE;
#endif /* WOLFSSL_PEM_TO_DER || WOLFSSL_DER_TO_PEM */
}
#endif /* SESSION_CERTS */
#if defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO) || defined(WOLFSSL_HAPROXY) \
|| defined(WOLFSSL_NGINX) || defined(WOLFSSL_QT)
#ifndef NO_WOLFSSL_STUB
/* Clear the extra certificate chain set on the context.
*
* Not implemented - stub for OpenSSL compatibility.
*
* @param [in] ctx SSL/TLS context object.
* @return Result of the SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS control command.
*/
long wolfSSL_CTX_clear_extra_chain_certs(WOLFSSL_CTX* ctx)
{
return wolfSSL_CTX_ctrl(ctx, SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS, 0L, NULL);
}
#endif
/* Get the verify callback set on the object.
*
* @param [in] ssl SSL/TLS object.
* @return Verify callback on success.
* @return NULL when ssl is NULL or no callback is set.
*/
VerifyCallback wolfSSL_get_verify_callback(WOLFSSL* ssl)
{
VerifyCallback cb = NULL;
WOLFSSL_ENTER("wolfSSL_get_verify_callback");
if (ssl != NULL) {
/* Verify callback configured on the object. */
cb = ssl->verifyCallback;
}
return cb;
}
#endif
#if defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)
/* Get the verify callback set on the context.
*
* @param [in] ctx SSL/TLS context object.
* @return Verify callback on success.
* @return NULL when ctx is NULL or no callback is set.
*/
VerifyCallback wolfSSL_CTX_get_verify_callback(WOLFSSL_CTX* ctx)
{
VerifyCallback cb = NULL;
WOLFSSL_ENTER("wolfSSL_CTX_get_verify_callback");
if (ctx != NULL) {
/* Verify callback configured on the context. */
cb = ctx->verifyCallback;
}
return cb;
}
#endif
#if defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) || defined(HAVE_STUNNEL) || \
defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(WOLFSSL_NGINX)
/* Get the verification mode set on the object.
*
* TODO: Doesn't currently track SSL_VERIFY_CLIENT_ONCE.
*
* @param [in] ssl SSL/TLS object.
* @return Bitmask of WOLFSSL_VERIFY_* flags on success.
* @return WOLFSSL_FAILURE when ssl is NULL.
*/
int wolfSSL_get_verify_mode(const WOLFSSL* ssl)
{
int mode = 0;
WOLFSSL_ENTER("wolfSSL_get_verify_mode");
if (ssl == NULL) {
mode = WOLFSSL_FAILURE;
}
else if (ssl->options.verifyNone) {
/* VERIFY_NONE is exclusive of the other verify flags. */
mode = WOLFSSL_VERIFY_NONE;
}
else {
/* Build the mode as a bitmask of the enabled verify flags. */
if (ssl->options.verifyPeer) {
mode |= WOLFSSL_VERIFY_PEER;
}
if (ssl->options.failNoCert) {
mode |= WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT;
}
if (ssl->options.failNoCertxPSK) {
mode |= WOLFSSL_VERIFY_FAIL_EXCEPT_PSK;
}
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH)
if (ssl->options.verifyPostHandshake) {
mode |= WOLFSSL_VERIFY_POST_HANDSHAKE;
}
#endif
}
WOLFSSL_LEAVE("wolfSSL_get_verify_mode", mode);
return mode;
}
/* Get the verification mode set on the context.
*
* @param [in] ctx SSL/TLS context object.
* @return Bitmask of WOLFSSL_VERIFY_* flags on success.
* @return WOLFSSL_FAILURE when ctx is NULL.
*/
int wolfSSL_CTX_get_verify_mode(const WOLFSSL_CTX* ctx)
{
int mode = 0;
WOLFSSL_ENTER("wolfSSL_CTX_get_verify_mode");
if (ctx == NULL) {
mode = WOLFSSL_FAILURE;
}
else if (ctx->verifyNone) {
/* VERIFY_NONE is exclusive of the other verify flags. */
mode = WOLFSSL_VERIFY_NONE;
}
else {
/* Build the mode as a bitmask of the enabled verify flags. */
if (ctx->verifyPeer) {
mode |= WOLFSSL_VERIFY_PEER;
}
if (ctx->failNoCert) {
mode |= WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT;
}
if (ctx->failNoCertxPSK) {
mode |= WOLFSSL_VERIFY_FAIL_EXCEPT_PSK;
}
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH)
if (ctx->verifyPostHandshake) {
mode |= WOLFSSL_VERIFY_POST_HANDSHAKE;
}
#endif
}
WOLFSSL_LEAVE("wolfSSL_CTX_get_verify_mode", mode);
return mode;
}
#endif
#if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) || \
defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL)
/* Create a stack of X509 certificates from a DER encoded certificate chain.
*
* The chain buffer holds each certificate as: 3 byte length | X509 DER data.
*
* @param [in] der DER encoded certificate chain.
* @param [in] derLen Length of certificate chain buffer in bytes.
* @param [in] heap Dynamic memory hint.
* @param [out] chain Stack of X509 certificates. Holds as much of the
* chain as was created on failure.
* @return WOLFSSL_SUCCESS on success.
* @return WOLFSSL_FAILURE on allocation or decode error.
*/
static int wolfssl_certchain_to_x509_stack(byte* der, word32 derLen,
void* heap, WOLF_STACK_OF(X509)** chain)
{
int ret = WOLFSSL_SUCCESS;
word32 idx;
word32 length;
WOLFSSL_STACK* node;
WOLFSSL_STACK* last = NULL;
/* Create a new stack of WOLFSSL_X509 object from chain buffer. */
for (idx = 0; idx < derLen; ) {
/* Need 3 bytes for the length of the DER encoded certificate. */
if ((derLen - idx) < 3) {
ret = WOLFSSL_FAILURE;
break;
}
/* Format: 3 byte length | X509 DER data. */
ato24(der + idx, &length);
idx += 3;
/* Ensure the DER encoded certificate is contained in the buffer. */
if (length > (derLen - idx)) {
ret = WOLFSSL_FAILURE;
break;
}
node = wolfSSL_sk_X509_new_null();
if (node == NULL) {
ret = WOLFSSL_FAILURE;
break;
}
node->next = NULL;
/* Create a new X509 from DER encoded data. */
node->data.x509 = wolfSSL_X509_d2i_ex(NULL, der + idx, (int)length,
heap);
if (node->data.x509 == NULL) {
XFREE(node, NULL, DYNAMIC_TYPE_OPENSSL);
/* Return as much of the chain as we created. */
ret = WOLFSSL_FAILURE;
break;
}
idx += length;
/* Add object to the end of the stack. */
if (last == NULL) {
node->num = 1;
*chain = node;
}
else {
(*chain)->num++;
last->next = node;
}
last = node;
}
return ret;
}
/* Get the extra certificate chain set on the context as a stack of X509.
*
* Builds the stack from the context's certificate chain buffer when needed.
*
* @param [in] ctx SSL/TLS context object.
* @param [out] chain Stack of X509 certificates.
* @return WOLFSSL_SUCCESS on success.
* @return WOLFSSL_FAILURE when ctx or chain is NULL, or on allocation error.
*/
int wolfSSL_CTX_get_extra_chain_certs(WOLFSSL_CTX* ctx,
WOLF_STACK_OF(X509)** chain)
{
int ret = WOLFSSL_SUCCESS;
if ((ctx == NULL) || (chain == NULL)) {
ret = WOLFSSL_FAILURE;
}
else if (ctx->x509Chain != NULL) {
*chain = ctx->x509Chain;
}
else {
/* If there are no chains then success! */
*chain = NULL;
if ((ctx->certChain != NULL) && (ctx->certChain->length != 0)) {
/* Build a stack of X509 from the DER certificate chain buffer. */
ret = wolfssl_certchain_to_x509_stack(ctx->certChain->buffer,
ctx->certChain->length, ctx->heap, chain);
/* Cache the chain - holds as much as was created on failure. */
ctx->x509Chain = *chain;
}
}
return ret;
}
/* Get the certificate chain set on the context.
*
* @param [in] ctx SSL/TLS context object.
* @param [out] sk Stack of X509 certificates.
* @return WOLFSSL_SUCCESS on success.
* @return WOLFSSL_FAILURE when ctx or sk is NULL.
*/
int wolfSSL_CTX_get0_chain_certs(WOLFSSL_CTX *ctx,
WOLF_STACK_OF(WOLFSSL_X509) **sk)
{
int ret;
WOLFSSL_ENTER("wolfSSL_CTX_get0_chain_certs");
if ((ctx == NULL) || (sk == NULL)) {
WOLFSSL_MSG("Bad parameter");
ret = WOLFSSL_FAILURE;
}
else {
/* This function should return ctx->x509Chain if it is populated,
* otherwise it should be populated from ctx->certChain. This matches
* the behavior of wolfSSL_CTX_get_extra_chain_certs, so it is used
* directly. */
ret = wolfSSL_CTX_get_extra_chain_certs(ctx, sk);
}
return ret;
}
#ifdef KEEP_OUR_CERT
/* Get our certificate chain set on the object.
*
* @param [in] ssl SSL/TLS object.
* @param [out] sk Stack of X509 certificates.
* @return WOLFSSL_SUCCESS on success.
* @return WOLFSSL_FAILURE when ssl or sk is NULL.
*/
int wolfSSL_get0_chain_certs(WOLFSSL *ssl, WOLF_STACK_OF(WOLFSSL_X509) **sk)
{
int ret = WOLFSSL_SUCCESS;
WOLFSSL_ENTER("wolfSSL_get0_chain_certs");
if ((ssl == NULL) || (sk == NULL)) {
WOLFSSL_MSG("Bad parameter");
ret = WOLFSSL_FAILURE;
}
else {
/* Return our own certificate chain held on the object. */
*sk = ssl->ourCertChain;
}
return ret;
}
#endif
#endif
#endif /* !WOLFCRYPT_ONLY */
#endif /* !WOLFSSL_SSL_API_CERT_INCLUDED */
+1462
View File
File diff suppressed because it is too large Load Diff
+2727
View File
File diff suppressed because it is too large Load Diff
+1241 -5
View File
File diff suppressed because it is too large Load Diff
+21 -13
View File
@@ -913,7 +913,7 @@ WOLFSSL_ASN1_BIT_STRING* wolfSSL_d2i_ASN1_BIT_STRING(
WOLFSSL_ENTER("wolfSSL_d2i_ASN1_BIT_STRING");
if (src == NULL || *src == NULL || len == 0)
if (src == NULL || *src == NULL || len <= 0)
return NULL;
if (GetASNTag(*src, &idx, &tag, (word32)len) < 0)
@@ -2984,7 +2984,7 @@ static WOLFSSL_ASN1_STRING* d2i_ASN1_STRING(WOLFSSL_ASN1_STRING** out,
WOLFSSL_ENTER("d2i_ASN1_STRING");
if (src == NULL || *src == NULL || len == 0)
if (src == NULL || *src == NULL || len <= 0)
return NULL;
if (GetASNTag(*src, &idx, &tag, (word32)len) < 0)
@@ -3159,6 +3159,11 @@ int wolfSSL_ASN1_STRING_set(WOLFSSL_ASN1_STRING* asn1, const void* data, int sz)
}
if (ret == 1) {
/* Cast to size_t BEFORE adding 1 to prevent signed overflow
* when sz == INT_MAX. By this point sz >= 0 (negative sz is
* handled above as OpenSSL -1/strlen compat). */
size_t allocSz = (size_t)sz + 1;
/* Dispose of any existing dynamic data. */
if (asn1->isDynamic) {
XFREE(asn1->data, NULL, DYNAMIC_TYPE_OPENSSL);
@@ -3166,9 +3171,9 @@ int wolfSSL_ASN1_STRING_set(WOLFSSL_ASN1_STRING* asn1, const void* data, int sz)
}
/* Check string will fit - including NUL. */
if (sz + 1 > CTC_NAME_SIZE) {
if (allocSz > CTC_NAME_SIZE) {
/* Allocate new buffer. */
asn1->data = (char*)XMALLOC((size_t)(sz + 1), NULL,
asn1->data = (char*)XMALLOC(allocSz, NULL,
DYNAMIC_TYPE_OPENSSL);
if (asn1->data == NULL) {
ret = 0;
@@ -3760,8 +3765,6 @@ int wolfSSL_ASN1_GENERALIZEDTIME_print(WOLFSSL_BIO* bio,
* ASN1_TIME APIs
******************************************************************************/
#ifndef NO_ASN_TIME
#ifdef OPENSSL_EXTRA
/* Allocate a new ASN.1 TIME object.
*
@@ -3811,6 +3814,7 @@ WOLFSSL_ASN1_TIME *wolfSSL_ASN1_TIME_set(WOLFSSL_ASN1_TIME *a, time_t t)
}
#endif /* !NO_WOLFSSL_STUB */
#ifndef NO_ASN_TIME
/* Convert time to Unix time (GMT).
*
* @param [in] sec Second in minute. 0-59.
@@ -4005,6 +4009,7 @@ WOLFSSL_ASN1_TIME* wolfSSL_ASN1_TIME_adj(WOLFSSL_ASN1_TIME* a, time_t t,
return ret;
}
#endif /* !USER_TIME && !TIME_OVERRIDES */
#endif /* !NO_ASN_TIME */
/* Get the length of the ASN.1 TIME data.
*
@@ -4048,6 +4053,7 @@ unsigned char* wolfSSL_ASN1_TIME_get_data(const WOLFSSL_ASN1_TIME *t)
return data;
}
#ifndef NO_ASN_TIME
/* Check format of string in ASN.1 TIME object.
*
* @param [in] a ASN.1 TIME object.
@@ -4069,6 +4075,7 @@ int wolfSSL_ASN1_TIME_check(const WOLFSSL_ASN1_TIME* a)
return ret;
}
#endif /* !NO_ASN_TIME */
/* Set the time as a string into ASN.1 TIME object.
*
@@ -4112,6 +4119,7 @@ int wolfSSL_ASN1_TIME_set_string(WOLFSSL_ASN1_TIME *t, const char *str)
return ret;
}
#ifndef NO_ASN_TIME
int wolfSSL_ASN1_TIME_set_string_X509(WOLFSSL_ASN1_TIME *t, const char *str)
{
int ret = WOLFSSL_SUCCESS;
@@ -4126,6 +4134,7 @@ int wolfSSL_ASN1_TIME_set_string_X509(WOLFSSL_ASN1_TIME *t, const char *str)
ret = wolfSSL_ASN1_TIME_check(t);
return ret;
}
#endif /* !NO_ASN_TIME */
/* Convert ASN.1 TIME object to ASN.1 GENERALIZED TIME object.
*
@@ -4199,7 +4208,7 @@ WOLFSSL_ASN1_TIME* wolfSSL_ASN1_TIME_to_generalizedtime(WOLFSSL_ASN1_TIME *t,
return ret;
}
#if !defined(USER_TIME) && !defined(TIME_OVERRIDES)
#if !defined(NO_ASN_TIME) && !defined(USER_TIME) && !defined(TIME_OVERRIDES)
WOLFSSL_ASN1_TIME* wolfSSL_ASN1_UTCTIME_set(WOLFSSL_ASN1_TIME *s, time_t t)
{
WOLFSSL_ASN1_TIME* ret = s;
@@ -4228,7 +4237,8 @@ WOLFSSL_ASN1_TIME* wolfSSL_ASN1_UTCTIME_set(WOLFSSL_ASN1_TIME *s, time_t t)
#endif /* !USER_TIME && !TIME_OVERRIDES */
#endif /* OPENSSL_EXTRA */
#if defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(OPENSSL_EXTRA)
#if !defined(NO_ASN_TIME) && \
(defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(OPENSSL_EXTRA))
/* Get string from ASN.1 TIME object.
*
* Not an OpenSSL compatibility API.
@@ -4607,9 +4617,9 @@ int wolfSSL_ASN1_TIME_print(WOLFSSL_BIO* bio, const WOLFSSL_ASN1_TIME* asnTime)
}
#endif /* !NO_BIO */
#endif /* WOLFSSL_MYSQL_COMPATIBLE || OPENSSL_EXTRA */
#endif /* !NO_ASN_TIME && (WOLFSSL_MYSQL_COMPATIBLE || OPENSSL_EXTRA) */
#ifdef OPENSSL_EXTRA
#if !defined(NO_ASN_TIME) && defined(OPENSSL_EXTRA)
#ifndef NO_BIO
/* Print the ASN.1 UTC TIME object as a string to BIO.
@@ -4647,9 +4657,7 @@ int wolfSSL_ASN1_UTCTIME_print(WOLFSSL_BIO* bio, const WOLFSSL_ASN1_UTCTIME* a)
}
#endif /* !NO_BIO */
#endif /* OPENSSL_EXTRA */
#endif /* !NO_ASN_TIME */
#endif /* !NO_ASN_TIME && OPENSSL_EXTRA */
/*******************************************************************************
* ASN1_TYPE APIs
+6 -3
View File
@@ -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.
+4
View File
@@ -2430,6 +2430,10 @@ int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, long sz,
if ((ret == 0) && (type == CHAIN_CERT_TYPE)) {
ret = BAD_FUNC_ARG;
}
/* Reject negative size - would wrap to huge word32. */
if ((ret == 0) && (sz < 0)) {
ret = BAD_FUNC_ARG;
}
#ifdef WOLFSSL_SMALL_STACK
if (ret == 0) {
+50
View File
@@ -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();
+524 -281
View File
File diff suppressed because it is too large Load Diff
+168 -49
View File
@@ -57,7 +57,6 @@
* WOLFSSL_PSK_ONE_ID: Single PSK identity per connect default: off
* WOLFSSL_PSK_MULTI_ID_PER_CS: Multiple PSK IDs per cipher suite default: off
* WOLFSSL_PRIORITIZE_PSK: Prioritize PSK over ciphersuite order default: off
* WOLFSSL_PSK_ID_PROTECTION: Enable PSK identity protection default: off
*
* TLS 1.3 Session Tickets:
* WOLFSSL_TICKET_HAVE_ID: Session tickets include ID default: off
@@ -4781,7 +4780,7 @@ int SendTls13ClientHello(WOLFSSL* ssl)
/* find length of outer and inner */
#if defined(HAVE_ECH)
if (ssl->echConfigs != NULL && !ssl->options.disableECH) {
if (!ssl->options.disableECH) {
TLSX* echX = TLSX_Find(ssl->extensions, TLSX_ECH);
if (echX == NULL)
return WOLFSSL_FATAL_ERROR;
@@ -4790,8 +4789,17 @@ int SendTls13ClientHello(WOLFSSL* ssl)
if (args->ech == NULL)
return WOLFSSL_FATAL_ERROR;
/* only prepare if we have a chance at acceptance */
if (ssl->options.echAccepted || args->ech->innerCount == 0) {
/* if ECH was rejected by the HRR then the server MUST stop
* decrypting ECH, so send a GREASE ECH for the follow-up CH */
if (ssl->echConfigs != NULL && !ssl->options.echAccepted &&
ssl->options.serverState ==
SERVER_HELLO_RETRY_REQUEST_COMPLETE) {
args->ech->state = ECH_WRITE_GREASE;
}
/* only prepare if we have a chance at acceptance (real ECH only) */
if (ssl->echConfigs != NULL &&
(ssl->options.echAccepted || args->ech->innerCount == 0)) {
word32 encodedLen;
byte downgrade;
@@ -4845,8 +4853,8 @@ int SendTls13ClientHello(WOLFSSL* ssl)
/* innerClientHelloLen and padding are based on the
* encoded (sealed) inner */
args->ech->paddingLen += 31 -
((encodedLen + args->ech->paddingLen - 1) % 32);
args->ech->paddingLen +=
ECH_PADDING_TO_32(encodedLen + args->ech->paddingLen);
args->ech->innerClientHelloLen = encodedLen +
args->ech->paddingLen + args->ech->hpke->Nt;
@@ -5097,16 +5105,16 @@ int SendTls13ClientHello(WOLFSSL* ssl)
return ret;
}
#endif
ret = TLSX_FinalizeEch(args->ech,
ret = TLSX_FinalizeEch(ssl, args->ech,
args->output + RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ,
(word32)(args->sendSz - (RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ)));
if (ret != 0)
return ret;
/* innerCount gates HRR re-prep and the server's copyRandom logic. */
args->ech->innerCount = 1;
}
/* Mark CH1 done for any ECH extension (real or GREASE) */
if (args->ech != NULL)
args->ech->innerCount = 1;
#endif
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
@@ -5854,7 +5862,7 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
if (args->extMsgType == hello_retry_request &&
((WOLFSSL_ECH*)args->echX->data)->confBuf == NULL) {
/* server rejected ECH, fallback to outer */
/* server rejected ECH, fall back to outer */
Free_HS_Hashes(ssl->hsHashesEch, ssl->heap);
ssl->hsHashesEch = NULL;
}
@@ -5879,7 +5887,8 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
if (ret != 0)
return ret;
/* use the inner random for client random */
if (args->extMsgType != hello_retry_request) {
if (args->extMsgType != hello_retry_request &&
ssl->options.echAccepted) {
XMEMCPY(ssl->arrays->clientRandom,
ssl->arrays->clientRandomInner, RAN_LEN);
}
@@ -6100,11 +6109,24 @@ static int DoTls13CertificateRequest(WOLFSSL* ssl, const byte* input,
return BUFFER_ERROR;
/* INVALID_PARAMETER does not map to illegal_parameter in the central
* alert path, so emit the alert explicitly before returning. */
if (ssl->options.connectState < FINISHED_DONE && len > 0) {
if (ssl->options.connectState < FINISHED_DONE) {
/* RFC 8446 Section 4.3.2: in the handshake the context is zero
* length. */
if (len > 0) {
SendAlert(ssl, alert_fatal, illegal_parameter);
WOLFSSL_ERROR_VERBOSE(INVALID_PARAMETER);
return INVALID_PARAMETER;
}
}
#ifdef WOLFSSL_POST_HANDSHAKE_AUTH
else if (len == 0) {
/* RFC 8446 Section 4.3.2: a post-handshake CertificateRequest context
* MUST be non-empty and unique for the connection. */
SendAlert(ssl, alert_fatal, illegal_parameter);
WOLFSSL_ERROR_VERBOSE(INVALID_PARAMETER);
return INVALID_PARAMETER;
}
#endif
#ifdef WOLFSSL_POST_HANDSHAKE_AUTH
/* Remember the request context bytes; the CertReqCtx allocation and
@@ -6113,6 +6135,18 @@ static int DoTls13CertificateRequest(WOLFSSL* ssl, const byte* input,
*/
reqCtxLen = len;
reqCtxData = input + *inOutIdx;
/* Reject a context that duplicates one still pending on the connection. */
if (ssl->options.connectState >= FINISHED_DONE) {
CertReqCtx* dup;
for (dup = ssl->certReqCtx; dup != NULL; dup = dup->next) {
if (dup->len == reqCtxLen &&
XMEMCMP(&dup->ctx, reqCtxData, reqCtxLen) == 0) {
SendAlert(ssl, alert_fatal, illegal_parameter);
WOLFSSL_ERROR_VERBOSE(INVALID_PARAMETER);
return INVALID_PARAMETER;
}
}
}
#endif
*inOutIdx += len;
@@ -6134,6 +6168,14 @@ static int DoTls13CertificateRequest(WOLFSSL* ssl, const byte* input,
}
*inOutIdx += len;
/* RFC 8446 Section 4.3.2: the signature_algorithms extension MUST be
* present in a CertificateRequest. */
if (peerSuites.hashSigAlgoSz == 0) {
SendAlert(ssl, alert_fatal, missing_extension);
WOLFSSL_ERROR_VERBOSE(INVALID_PARAMETER);
return INVALID_PARAMETER;
}
#ifdef WOLFSSL_CERT_SETUP_CB
if ((ret = CertSetupCbWrapper(ssl)) != 0)
return ret;
@@ -6446,6 +6488,37 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 inputSz,
}
#endif
ret = DoClientTicketCheck(ssl, current, ssl->timeout, suite);
#if defined(HAVE_SNI) || defined(HAVE_ALPN)
if (ret == 0) {
/* Decline this PSK if the SNI/ALPN bound to the ticket
* does not match the current connection. RFC 6066 Sect.
* 3 mandates this for SNI; wolfSSL applies the same
* policy to ALPN as defense in depth. Skipping the PSK
* (rather than aborting) lets the server try the next
* candidate or fall back to a full handshake naturally
* without unwinding committed PSK state. ALPN_Select
* has already run earlier in DoTls13ClientHello so the
* negotiated ALPN is available to TicketAlpnHash. */
byte curHash[TICKET_BINDING_HASH_SZ];
#ifdef HAVE_SNI
if (TicketSniHash(ssl, curHash) != 0 ||
XMEMCMP(curHash, current->it->sniHash,
TICKET_BINDING_HASH_SZ) != 0) {
WOLFSSL_MSG("Ticket SNI mismatch, skipping PSK");
ret = WOLFSSL_FATAL_ERROR;
}
#endif
#ifdef HAVE_ALPN
if (ret == 0 &&
(TicketAlpnHash(ssl, curHash) != 0 ||
XMEMCMP(curHash, current->it->alpnHash,
TICKET_BINDING_HASH_SZ) != 0)) {
WOLFSSL_MSG("Ticket ALPN mismatch, skipping PSK");
ret = WOLFSSL_FATAL_ERROR;
}
#endif
}
#endif
if (ret == 0)
DoClientTicketFinalize(ssl, current->it, current->sess);
if (current->sess_free_cb != NULL) {
@@ -6544,20 +6617,8 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 inputSz,
}
if (current == NULL) {
#ifdef WOLFSSL_PSK_ID_PROTECTION
#ifndef NO_CERTS
if (ssl->buffers.certChainCnt != 0) {
ret = 0;
goto cleanup;
}
#endif
WOLFSSL_ERROR_VERBOSE(BAD_BINDER);
ret = BAD_BINDER;
goto cleanup;
#else
ret = 0;
goto cleanup;
#endif
}
*first = (current == ext->data);
@@ -6609,11 +6670,11 @@ static int CheckPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz,
return ret;
}
/* Extensions pushed on stack/list and PSK must be last. */
if (ssl->extensions != ext) {
WOLFSSL_ERROR_VERBOSE(PSK_KEY_ERROR);
return PSK_KEY_ERROR;
}
/* Wire-order check that PSK was the last extension in ClientHello is
* performed in DoTls13ClientHello immediately after TLSX_Parse, since
* post-parse code (e.g. ALPN_Select via TLSX_SetALPN) may legitimately
* prepend new entries to ssl->extensions before this point and would
* otherwise trip a head-of-list check here. */
/* Assume we are going to resume with a pre-shared key. */
ssl->options.resuming = 1;
@@ -6664,6 +6725,20 @@ static int CheckPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz,
}
#endif
if (!*usingPSK) {
#ifndef NO_CERTS
if (ssl->buffers.certificate == NULL
#ifdef WOLFSSL_CERT_SETUP_CB
&& ssl->ctx->certSetupCb == NULL
#endif
)
#endif
{
WOLFSSL_ERROR_VERBOSE(BAD_BINDER);
return BAD_BINDER;
}
}
if (*usingPSK) {
/* While verifying the selected PSK, we updated the
* handshake hash up to the binder bytes in the PSK extensions.
@@ -6834,14 +6909,16 @@ static int CheckPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz,
TLSX_Remove(&ssl->extensions, TLSX_CERT_WITH_EXTERN_PSK, ssl->heap);
ssl->options.certWithExternPsk = 0;
#endif
#ifdef WOLFSSL_PSK_ID_PROTECTION
#ifndef NO_CERTS
if (ssl->buffers.certChainCnt != 0)
if (ssl->buffers.certificate != NULL
#ifdef WOLFSSL_CERT_SETUP_CB
|| ssl->ctx->certSetupCb != NULL
#endif
)
return 0;
#endif
WOLFSSL_ERROR_VERBOSE(BAD_BINDER);
return BAD_BINDER;
#endif
}
WOLFSSL_LEAVE("CheckPreSharedKeys", ret);
@@ -7452,7 +7529,8 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
/* From here on we are a TLS 1.3 ClientHello. */
/* Client random */
/* Client random
* ECH Accepted -> This will fill with the innerClientRandom */
XMEMCPY(ssl->arrays->clientRandom, input + args->idx, RAN_LEN);
args->idx += RAN_LEN;
@@ -7579,6 +7657,25 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
goto exit_dch;
}
#if (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)) && \
defined(HAVE_TLS_EXTENSIONS)
/* RFC 8446 Section 4.2.11: the pre_shared_key extension MUST be the
* last extension in the ClientHello. wolfSSL stores extensions in
* reverse wire order (TLSX_Push prepends), so a well-formed
* ClientHello with PSK leaves PSK at the head of ssl->extensions
* here, before any post-parse code (e.g. ALPN_Select) modifies the
* list. */
{
TLSX* pskExt = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY);
if (pskExt != NULL && ssl->extensions != pskExt) {
WOLFSSL_MSG("pre_shared_key extension was not last in "
"ClientHello");
WOLFSSL_ERROR_VERBOSE(PSK_KEY_ERROR);
ERROR_OUT(PSK_KEY_ERROR, exit_dch);
}
}
#endif
#if defined(HAVE_ECH)
if (!ssl->options.echProcessingInner && echX != NULL &&
((WOLFSSL_ECH*)echX->data)->state == ECH_WRITE_NONE) {
@@ -7688,6 +7785,15 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
}
#endif
#ifdef HAVE_ALPN
/* Select the ALPN protocol before PSK selection so that the
* selected value is available to the per-PSK SNI/ALPN binding check
* inside CheckPreSharedKeys/DoPreSharedKeys. ALPN_Select itself
* only inspects ssl->extensions and the app callback; it does not
* depend on any state set during PSK validation. */
if ((ret = ALPN_Select(ssl)) != 0)
goto exit_dch;
#endif
#if (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)) && \
defined(HAVE_TLS_EXTENSIONS)
ret = CheckPreSharedKeys(ssl, input + args->begin, helloSz, ssl->clSuites,
@@ -7729,16 +7835,6 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
#endif
}
#ifdef HAVE_ALPN
/* With PSK and all other things validated, it's time to
* select the ALPN protocol, if so requested */
if ((ret = ALPN_Select(ssl)) != 0)
goto exit_dch;
#endif
#if defined(HAVE_SESSION_TICKET) && (defined(HAVE_SNI) || defined(HAVE_ALPN))
if ((ret = VerifyTicketBinding(ssl)) != 0)
goto exit_dch;
#endif
} /* case TLS_ASYNC_BEGIN */
FALL_THROUGH;
@@ -12176,8 +12272,16 @@ int SendTls13KeyUpdate(WOLFSSL* ssl)
WOLFSSL_ENTER("SendTls13KeyUpdate");
#ifdef WOLFSSL_DTLS13
if (ssl->options.dtls)
if (ssl->options.dtls) {
/* RFC 9147 Section 4.2.1: do not send a KeyUpdate that would advance
* the sending epoch beyond 2^48-1. */
if (w64GTE(ssl->dtls13Epoch,
w64From32(DTLS13_EPOCH_MAX_HI32, DTLS13_EPOCH_MAX_LO32))) {
WOLFSSL_MSG("DTLS 1.3 sending epoch at maximum; refusing KeyUpdate");
return BAD_STATE_E;
}
i = Dtls13GetRlHeaderLength(ssl, 1) + DTLS_HANDSHAKE_HEADER_SZ;
}
#endif /* WOLFSSL_DTLS13 */
outputSz = OPAQUE8_LEN + MAX_MSG_EXTRA;
@@ -12311,7 +12415,17 @@ static int DoTls13KeyUpdate(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
#ifdef WOLFSSL_DTLS13
if (ssl->options.dtls) {
w64Increment(&ssl->dtls13PeerEpoch);
/* Increment on a local copy so ssl->dtls13PeerEpoch is left
* untouched when the check fails. */
w64wrapper newEpoch = ssl->dtls13PeerEpoch;
w64Increment(&newEpoch);
/* RFC 9147 Section 8: the 2^48-1 cap is sender-only; receivers MUST
* NOT enforce it. Guard only the wrap-to-zero (Section 4.2.1). */
if (w64IsZero(newEpoch))
return BAD_STATE_E;
ssl->dtls13PeerEpoch = newEpoch;
ret = Dtls13SetEpochKeys(ssl, ssl->dtls13PeerEpoch, DECRYPT_SIDE_ONLY);
if (ret != 0)
@@ -13690,8 +13804,7 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx,
* Only on first inner ClientHello (before HRR), not CH2. */
if (copyRandom) {
XMEMCPY(ssl->arrays->clientRandomInner,
((WOLFSSL_ECH*)echX->data)->innerClientHello +
HANDSHAKE_HEADER_SZ + VERSION_SZ, RAN_LEN);
ssl->arrays->clientRandom, RAN_LEN);
}
*inOutIdx += size;
}
@@ -14667,7 +14780,7 @@ int wolfSSL_UseKeyShare(WOLFSSL* ssl, word16 group)
(void)group;
#else
/* Check if the group is supported. */
if (!TLSX_IsGroupSupported(group)) {
if (!TLSX_IsGroupSupported(group, ssl->options.side)) {
WOLFSSL_MSG("Group not supported.");
return BAD_FUNC_ARG;
}
@@ -16103,6 +16216,12 @@ int tls13ShowSecrets(WOLFSSL* ssl, int id, const unsigned char* secret,
str = "SERVER_TRAFFIC_SECRET_0"; break;
case EXPORTER_SECRET:
str = "EXPORTER_SECRET"; break;
#ifdef HAVE_ECH
case ECH_SECRET:
str = "ECH_SECRET"; break;
case ECH_CONFIG:
str = "ECH_CONFIG"; break;
#endif
default:
#ifdef WOLFSSL_SSLKEYLOGFILE_OUTPUT
XFCLOSE(fp);
+10 -5
View File
@@ -4213,7 +4213,7 @@ static WOLFSSL_X509* d2i_X509orX509REQ(WOLFSSL_X509** x509,
WOLFSSL_ENTER("wolfSSL_X509_d2i");
if (in != NULL && len != 0
if (in != NULL && len > 0
#ifndef WOLFSSL_CERT_REQ
&& req == 0
#else
@@ -4523,6 +4523,10 @@ const byte* wolfSSL_X509_get_der(WOLFSSL_X509* x509, int* outSz)
if (x509 == NULL || x509->derCert == NULL || outSz == NULL)
return NULL;
if (x509->derCert->length > (word32)INT_MAX) {
return NULL;
}
*outSz = (int)x509->derCert->length;
return x509->derCert->buffer;
}
@@ -6114,8 +6118,9 @@ WOLFSSL_X509* wolfSSL_X509_d2i_fp(WOLFSSL_X509** x509, XFILE file)
#endif /* OPENSSL_EXTRA && !NO_FILESYSTEM && !NO_STDIO_FILESYSTEM */
#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) || \
defined(KEEP_PEER_CERT) || defined(SESSION_CERTS)
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) || \
defined(WOLFSSL_WPAS_SMALL) || defined(KEEP_PEER_CERT) || \
defined(SESSION_CERTS)
#ifndef NO_FILESYSTEM
WOLFSSL_ABI
@@ -8835,7 +8840,7 @@ int wolfSSL_i2d_X509(WOLFSSL_X509* x509, unsigned char** out)
}
der = wolfSSL_X509_get_der(x509, &derSz);
if (der == NULL) {
if (der == NULL || derSz <= 0) {
WOLFSSL_LEAVE("wolfSSL_i2d_X509", MEMORY_E);
return MEMORY_E;
}
@@ -11368,7 +11373,7 @@ WOLFSSL_X509_ALGOR* wolfSSL_d2i_X509_ALGOR(WOLFSSL_X509_ALGOR** out,
WOLFSSL_ENTER("wolfSSL_d2i_X509_ALGOR");
if (src == NULL || *src == NULL || len == 0)
if (src == NULL || *src == NULL || len <= 0)
return NULL;
if (GetAlgoId(*src, &idx, &oid, oidIgnoreType, (word32)len) != 0)
+331 -40
View File
@@ -235,6 +235,9 @@
#include <tests/api/test_signature.h>
#include <tests/api/test_dtls.h>
#include <tests/api/test_dtls13.h>
#include <tests/api/test_ssl_cert.h>
#include <tests/api/test_ssl_pk.h>
#include <tests/api/test_ssl_ext.h>
#include <tests/api/test_ocsp.h>
#include <tests/api/test_evp.h>
#include <tests/api/test_tls_ext.h>
@@ -2520,6 +2523,28 @@ static int test_wolfSSL_CTX_use_certificate_buffer(void)
} /* END test_wolfSSL_CTX_use_certificate_buffer */
static int test_ProcessBuffer_negative_size(void)
{
EXPECT_DECLS;
#if !defined(NO_CERTS) && !defined(NO_TLS) && !defined(NO_WOLFSSL_SERVER) && \
defined(USE_CERT_BUFFERS_2048) && !defined(NO_RSA)
WOLFSSL_CTX* ctx = NULL;
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));
ExpectIntEQ(wolfSSL_CTX_use_certificate_buffer(ctx,
server_cert_der_2048, -1, WOLFSSL_FILETYPE_ASN1),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wolfSSL_CTX_use_certificate_buffer(ctx,
server_cert_der_2048, sizeof_server_cert_der_2048,
WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
wolfSSL_CTX_free(ctx);
#endif
return EXPECT_RESULT();
}
static int test_wolfSSL_use_certificate_buffer(void)
{
EXPECT_DECLS;
@@ -11057,6 +11082,12 @@ static int test_wc_PemToDer(void)
XMEMSET(&info, 0, sizeof(info));
{
const byte dummy = 'X';
ExpectIntEQ(wc_PemToDer(&dummy, -1, CERT_TYPE, &pDer, NULL,
&info, &eccKey), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
}
ExpectIntEQ(ret = load_file(ca_cert, &cert_buf, &cert_sz), 0);
ExpectIntEQ(ret = wc_PemToDer(cert_buf, (long int)cert_sz, CERT_TYPE, &pDer, NULL,
&info, &eccKey), 0);
@@ -11230,6 +11261,10 @@ static int test_wc_KeyPemToDer(void)
ExpectIntEQ(wc_KeyPemToDer(cert_buf, 0, (byte*)&cert_der, cert_sz, ""),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* Bad arg: NULL der buffer with negative pemSz (NULL-deref guard). */
ExpectIntEQ(wc_KeyPemToDer(cert_buf, -1, NULL, 0, ""),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* Test normal operation */
cert_dersz = cert_sz; /* DER will be smaller than PEM */
ExpectNotNull(cert_der = (byte*)malloc((size_t)cert_dersz));
@@ -13431,7 +13466,7 @@ static int test_wolfSSL_Tls12_Key_Logging_test(void)
XMEMSET(buff, 0, sizeof(buff));
while (EXPECT_SUCCESS() && XFGETS(buff, (int)sizeof(buff), fp) != NULL) {
if (0 == strncmp(buff,"CLIENT_RANDOM ", sizeof("CLIENT_RANDOM ")-1)) {
if (0 == XSTRNCMP(buff,"CLIENT_RANDOM ", sizeof("CLIENT_RANDOM ")-1)) {
found = 1;
break;
}
@@ -13449,12 +13484,57 @@ static int test_wolfSSL_Tls12_Key_Logging_test(void)
#if defined(WOLFSSL_TLS13) && defined(OPENSSL_EXTRA) && \
defined(HAVE_SECRET_CALLBACK)
#ifdef HAVE_ECH
static int test_ech_server_ctx_ready(WOLFSSL_CTX* ctx);
static int test_ech_server_ssl_ready(WOLFSSL* ssl);
static int test_ech_client_ssl_ready(WOLFSSL* ssl);
#endif
static int test_wolfSSL_Tls13_Key_Logging_client_ctx_ready(WOLFSSL_CTX* ctx)
{
/* set keylog callback */
wolfSSL_CTX_set_keylog_callback(ctx, keyLog_callback);
return TEST_SUCCESS;
}
static int test_wolfSSL_Tls13_Key_Logging_server_ctx_ready(WOLFSSL_CTX* ctx)
{
#ifdef HAVE_ECH
if (test_ech_server_ctx_ready(ctx) != TEST_SUCCESS)
return TEST_FAIL;
#endif
/* set keylog callback */
wolfSSL_CTX_set_keylog_callback(ctx, keyLog_callback);
return TEST_SUCCESS;
}
static int test_wolfSSL_Tls13_Key_Logging_client_ssl_ready(WOLFSSL* ssl)
{
#ifdef HAVE_KEYING_MATERIAL
/* retain arrays so EXPORTER_SECRET is logged */
wolfSSL_KeepArrays(ssl);
#endif
#ifdef HAVE_ECH
return test_ech_client_ssl_ready(ssl);
#else
(void)ssl;
return TEST_SUCCESS;
#endif
}
static int test_wolfSSL_Tls13_Key_Logging_server_ssl_ready(WOLFSSL* ssl)
{
#ifdef HAVE_KEYING_MATERIAL
/* retain arrays so EXPORTER_SECRET is logged */
wolfSSL_KeepArrays(ssl);
#endif
#ifdef HAVE_ECH
return test_ech_server_ssl_ready(ssl);
#else
(void)ssl;
return TEST_SUCCESS;
#endif
}
#endif
static int test_wolfSSL_Tls13_Key_Logging_test(void)
@@ -13463,7 +13543,7 @@ static int test_wolfSSL_Tls13_Key_Logging_test(void)
#if defined(WOLFSSL_TLS13) && defined(OPENSSL_EXTRA) && \
defined(HAVE_SECRET_CALLBACK)
/* This test is intended for checking whether keylog callback is called
* in client during TLS handshake between the client and a server.
* in the client/server during a TLS handshake.
*/
test_ssl_cbf server_cbf;
test_ssl_cbf client_cbf;
@@ -13473,6 +13553,9 @@ static int test_wolfSSL_Tls13_Key_Logging_test(void)
XMEMSET(&client_cbf, 0, sizeof(test_ssl_cbf));
server_cbf.method = wolfTLSv1_3_server_method; /* TLS1.3 */
client_cbf.ctx_ready = &test_wolfSSL_Tls13_Key_Logging_client_ctx_ready;
client_cbf.ssl_ready = &test_wolfSSL_Tls13_Key_Logging_client_ssl_ready;
server_cbf.ctx_ready = &test_wolfSSL_Tls13_Key_Logging_server_ctx_ready;
server_cbf.ssl_ready = &test_wolfSSL_Tls13_Key_Logging_server_ssl_ready;
/* clean up keylog file */
ExpectTrue((fp = XFOPEN("./MyKeyLog.txt", "w")) != XBADFILE);
@@ -13487,44 +13570,181 @@ static int test_wolfSSL_Tls13_Key_Logging_test(void)
/* check if the keylog file exists */
{
char buff[300] = {0};
int found[4] = {0};
int numfnd = 0;
int i;
int found[7] = {0};
#ifdef HAVE_ECH
char echRandom[RAN_LEN * 2] = {0};
char chtsRandom[RAN_LEN * 2] = {0};
#endif
ExpectTrue((fp = XFOPEN("./MyKeyLog.txt", "rb")) != XBADFILE);
while (EXPECT_SUCCESS() &&
XFGETS(buff, (int)sizeof(buff), fp) != NULL) {
if (0 == strncmp(buff, "CLIENT_HANDSHAKE_TRAFFIC_SECRET ",
if (0 == XSTRNCMP(buff, "CLIENT_HANDSHAKE_TRAFFIC_SECRET ",
sizeof("CLIENT_HANDSHAKE_TRAFFIC_SECRET ")-1)) {
found[0] = 1;
found[0]++;
#ifdef HAVE_ECH
XMEMCPY(chtsRandom,
buff + sizeof("CLIENT_HANDSHAKE_TRAFFIC_SECRET ")-1,
RAN_LEN * 2);
#endif
continue;
}
else if (0 == strncmp(buff, "SERVER_HANDSHAKE_TRAFFIC_SECRET ",
else if (0 == XSTRNCMP(buff, "SERVER_HANDSHAKE_TRAFFIC_SECRET ",
sizeof("SERVER_HANDSHAKE_TRAFFIC_SECRET ")-1)) {
found[1] = 1;
found[1]++;
continue;
}
else if (0 == strncmp(buff, "CLIENT_TRAFFIC_SECRET_0 ",
else if (0 == XSTRNCMP(buff, "CLIENT_TRAFFIC_SECRET_0 ",
sizeof("CLIENT_TRAFFIC_SECRET_0 ")-1)) {
found[2] = 1;
found[2]++;
continue;
}
else if (0 == strncmp(buff, "SERVER_TRAFFIC_SECRET_0 ",
else if (0 == XSTRNCMP(buff, "SERVER_TRAFFIC_SECRET_0 ",
sizeof("SERVER_TRAFFIC_SECRET_0 ")-1)) {
found[3] = 1;
found[3]++;
continue;
}
#ifdef HAVE_KEYING_MATERIAL
else if (0 == XSTRNCMP(buff, "EXPORTER_SECRET ",
sizeof("EXPORTER_SECRET ")-1)) {
found[4]++;
continue;
}
#endif
#ifdef HAVE_ECH
else if (0 == XSTRNCMP(buff, "ECH_SECRET ",
sizeof("ECH_SECRET ")-1)) {
found[5]++;
XMEMCPY(echRandom, buff + sizeof("ECH_SECRET ")-1,
RAN_LEN * 2);
continue;
}
else if (0 == XSTRNCMP(buff, "ECH_CONFIG ",
sizeof("ECH_CONFIG ")-1)) {
found[6]++;
continue;
}
#endif
}
if (fp != XBADFILE)
XFCLOSE(fp);
/* the four traffic secrets are derived by both client and server, so
* each label should appear twice with the callback set on both sides */
ExpectIntEQ(found[0], 2);
ExpectIntEQ(found[1], 2);
ExpectIntEQ(found[2], 2);
ExpectIntEQ(found[3], 2);
#ifdef HAVE_KEYING_MATERIAL
/* both sides retain arrays via KeepArrays, so EXPORTER_SECRET fires
* on each */
ExpectIntEQ(found[4], 2);
#endif
#ifdef HAVE_ECH
/* both sides also log ECH_SECRET and ECH_CONFIG (seal on client,
* open on server) */
ExpectIntEQ(found[5], 2);
ExpectIntEQ(found[6], 2);
/* both lines must have been logged */
ExpectIntNE(echRandom[0], 0);
ExpectIntNE(chtsRandom[0], 0);
/* ECH_SECRET MUST be logged against the outer random while
* CLIENT_HANDSHAKE_TRAFFIC_SECRET uses the inner random when ECH is
* accepted */
ExpectIntNE(XSTRNCMP(echRandom, chtsRandom, RAN_LEN * 2), 0);
#endif
}
#endif /* OPENSSL_EXTRA && HAVE_SECRET_CALLBACK && WOLFSSL_TLS13 */
return EXPECT_RESULT();
}
/* When ECH is rejected the inner random is never swapped in, so ECH_SECRET and
* CLIENT_HANDSHAKE_TRAFFIC_SECRET are both logged against the outer random. */
static int test_wolfSSL_Tls13_Key_Logging_ech_rejected(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && defined(OPENSSL_EXTRA) && \
defined(HAVE_SECRET_CALLBACK) && defined(HAVE_ECH) && \
defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES)
test_ssl_memio_ctx test_ctx;
WOLFSSL_CTX* tempCtx = NULL;
byte badConfig[128];
word32 badConfigLen = sizeof(badConfig);
XFILE fp = XBADFILE;
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
test_ctx.s_cb.method = wolfTLSv1_3_server_method;
test_ctx.c_cb.method = wolfTLSv1_3_client_method;
/* server generates its real ECH config and sets the keylog callback */
test_ctx.s_cb.ctx_ready = test_wolfSSL_Tls13_Key_Logging_server_ctx_ready;
/* client sets the keylog callback */
test_ctx.c_cb.ctx_ready = test_wolfSSL_Tls13_Key_Logging_client_ctx_ready;
ExpectIntEQ(test_ssl_memio_setup(&test_ctx), TEST_SUCCESS);
/* generate a throwaway ECH config the server cannot decrypt */
ExpectNotNull(tempCtx = wolfSSL_CTX_new(wolfTLSv1_3_server_method()));
ExpectIntEQ(wolfSSL_CTX_GenerateEchConfig(tempCtx, "ech-public-name.com",
0, 0, 0), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_CTX_GetEchConfigs(tempCtx, badConfig, &badConfigLen),
WOLFSSL_SUCCESS);
wolfSSL_CTX_free(tempCtx);
tempCtx = NULL;
/* client uses the bad config so the server rejects ECH */
ExpectIntEQ(wolfSSL_SetEchConfigs(test_ctx.c_ssl, badConfig, badConfigLen),
WOLFSSL_SUCCESS);
/* set inner SNI */
ExpectIntEQ(wolfSSL_UseSNI(test_ctx.c_ssl, WOLFSSL_SNI_HOST_NAME,
"ech-private-name.com", (word16)XSTRLEN("ech-private-name.com")),
WOLFSSL_SUCCESS);
/* client sends empty cert on rejection, server should not ask for one */
wolfSSL_set_verify(test_ctx.s_ssl, WOLFSSL_VERIFY_NONE, NULL);
/* clean up keylog file */
ExpectTrue((fp = XFOPEN("./MyKeyLog.txt", "w")) != XBADFILE);
if (fp != XBADFILE) {
XFCLOSE(fp);
fp = XBADFILE;
}
/* handshake fails because ECH was rejected */
ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
WOLFSSL_ECH_STATUS_REJECTED);
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.s_ssl),
WOLFSSL_ECH_STATUS_REJECTED);
test_ssl_memio_cleanup(&test_ctx);
{
char buff[300] = {0};
char echRandom[RAN_LEN * 2] = {0};
char chtsRandom[RAN_LEN * 2] = {0};
ExpectTrue((fp = XFOPEN("./MyKeyLog.txt", "rb")) != XBADFILE);
while (EXPECT_SUCCESS() &&
XFGETS(buff, (int)sizeof(buff), fp) != NULL) {
if (0 == XSTRNCMP(buff, "CLIENT_HANDSHAKE_TRAFFIC_SECRET ",
sizeof("CLIENT_HANDSHAKE_TRAFFIC_SECRET ")-1)) {
XMEMCPY(chtsRandom,
buff + sizeof("CLIENT_HANDSHAKE_TRAFFIC_SECRET ")-1,
RAN_LEN * 2);
}
else if (0 == XSTRNCMP(buff, "ECH_SECRET ",
sizeof("ECH_SECRET ")-1)) {
XMEMCPY(echRandom, buff + sizeof("ECH_SECRET ")-1, RAN_LEN * 2);
}
}
if (fp != XBADFILE)
XFCLOSE(fp);
for (i = 0; i < 4; i++) {
if (found[i] != 0)
numfnd++;
}
ExpectIntEQ(numfnd, 4);
/* both lines must have been logged */
ExpectIntNE(echRandom[0], 0);
ExpectIntNE(chtsRandom[0], 0);
/* ECH was rejected so both should be the outer random */
ExpectIntEQ(XSTRNCMP(echRandom, chtsRandom, RAN_LEN * 2), 0);
}
#endif /* OPENSSL_EXTRA && HAVE_SECRET_CALLBACK && WOLFSSL_TLS13 */
#endif
return EXPECT_RESULT();
}
@@ -14978,7 +15198,8 @@ static int ech_find_extension(byte* buf, word16* idx_p, word16 extType)
/* Test the HRR ECH rejection fallback path:
* client offers ECH, HRR is triggered, server sends HRR without ECH extension,
* client falls back to the outer transcript, then aborts with ech_required. */
* client falls back to the outer transcript, then aborts with ech_required.
* encrypted_client_hello should still be present in CH2 */
static int test_wolfSSL_Tls13_ECH_HRR_rejection(void)
{
EXPECT_DECLS;
@@ -15012,7 +15233,25 @@ static int test_wolfSSL_Tls13_ECH_HRR_rejection(void)
* outer transcript */
ExpectIntEQ(wolfSSL_NoKeyShares(test_ctx.c_ssl), WOLFSSL_SUCCESS);
/* Handshake must fail: client aborts with ech_required */
if (EXPECT_SUCCESS()) {
word16 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
/* One round: client sends CH1, server consumes it and writes HRR */
(void)test_ssl_memio_do_handshake(&test_ctx, 1, NULL);
/* Client reads HRR and writes CH2 into s_buff.
* CH2 carries encrypted_client_hello so the connection doesn't
* 'stick out' on the wire. */
(void)wolfSSL_connect(test_ctx.c_ssl);
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
WOLFSSL_ECH_STATUS_REJECTED);
/* hsHashesEch must have been freed by the HRR rejection code path */
ExpectNull(test_ctx.c_ssl->hsHashesEch);
ExpectIntEQ(ech_find_extension(test_ctx.s_buff, &idx, TLSXT_ECH), 0);
}
/* Finish handshake: client aborts with ech_required */
ExpectIntNE(test_ssl_memio_do_handshake(&test_ctx, 10, NULL), TEST_SUCCESS);
ExpectIntEQ(wolfSSL_GetEchStatus(test_ctx.c_ssl),
WOLFSSL_ECH_STATUS_REJECTED);
@@ -19340,7 +19579,10 @@ static int test_wolfSSL_verify_result(void)
WOLFSSL_CTX* ctx = NULL;
long result = 0xDEADBEEF;
ExpectIntEQ(WC_NO_ERR_TRACE(WOLFSSL_FAILURE), wolfSSL_get_verify_result(ssl));
/* A NULL ssl returns a non-zero verify error (not X509_V_OK) so the
* OpenSSL-idiomatic "!= X509_V_OK" check is not fooled. See F-4594. */
ExpectIntEQ(WOLFSSL_X509_V_ERR_APPLICATION_VERIFICATION,
wolfSSL_get_verify_result(ssl));
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
ExpectNotNull(ssl = SSL_new(ctx));
@@ -21778,6 +22020,13 @@ static int test_wc_SetIssueBuffer(void)
ExpectIntEQ(0, wc_SetIssuerBuffer(&forgedCert, peerCertBuf, peerCertSz));
/* Negative-size rejection: pin both wc_SetIssuerBuffer and
* wc_SetSubjectBuffer (representatives for the seven wc_Set* siblings). */
ExpectIntEQ(wc_SetIssuerBuffer(&forgedCert, peerCertBuf, -1),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_SetSubjectBuffer(&forgedCert, peerCertBuf, -1),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
wolfSSL_FreeX509(x509);
#endif
return EXPECT_RESULT();
@@ -23157,6 +23406,11 @@ static int test_wc_SignCert_cb(void)
/* Invalid keyType for ECC signature */
ExpectIntEQ(wc_SignCert_cb(cert.bodySz, cert.sigType, der,
FOURK_BUF, ED25519_TYPE, mockSignCb, &signCtx, &rng), BAD_FUNC_ARG);
/* sigType/key family mismatch: an RSA signature OID against an ECC
* key must be rejected with ALGO_ID_E before any signing happens. */
ExpectIntEQ(wc_SignCert_cb(cert.bodySz, CTC_SHA256wRSA, der,
FOURK_BUF, ECC_TYPE, mockSignCb, &signCtx, &rng),
WC_NO_ERR_TRACE(ALGO_ID_E));
#endif
ret = wc_ecc_free(&key);
@@ -23243,6 +23497,11 @@ static int test_wc_SignCert_cb(void)
/* Invalid keyType */
ExpectIntEQ(wc_SignCert_cb(cert.bodySz, cert.sigType, der,
FOURK_BUF, ED448_TYPE, mockSignCb, &signCtx, &rng), BAD_FUNC_ARG);
/* sigType/key family mismatch: an ECDSA signature OID against an RSA
* key must be rejected with ALGO_ID_E before any signing happens. */
ExpectIntEQ(wc_SignCert_cb(cert.bodySz, CTC_SHA256wECDSA, der,
FOURK_BUF, RSA_TYPE, mockSignCb, &signCtx, &rng),
WC_NO_ERR_TRACE(ALGO_ID_E));
#endif
ret = wc_FreeRsaKey(&key);
@@ -23607,7 +23866,7 @@ static int test_sk_X509_CRL_decode(void)
}
#if (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) && !defined(NO_CERTS) && \
defined(HAVE_CRL) && defined(WOLFSSL_CERT_GEN)
defined(HAVE_CRL) && defined(WOLFSSL_CERT_GEN) && !defined(NO_ASN_TIME)
/* Ensure oversized caller-provided revocationDate is rejected. */
static int test_wolfSSL_X509_CRL_add_revoked_oversized_revocation_date(void)
{
@@ -24182,6 +24441,15 @@ static int test_wc_MakeCRL_max_crlnum(void)
ExpectIntGT(crlSz, 0);
}
/* --- Negative: a sigType whose family does not match the signing key
* must be rejected before any signature is produced. The RSA key here
* paired with an ECDSA OID must return ALGO_ID_E. --- */
if (EXPECT_SUCCESS()) {
ExpectIntEQ(wc_SignCRL_ex(tbsBuf, tbsSz, CTC_SHA256wECDSA,
crlBuf, (word32)bufSz, &rsaKey, NULL, &rng),
WC_NO_ERR_TRACE(ALGO_ID_E));
}
/* --- Decode the CRL and verify CRL number --- */
if (EXPECT_SUCCESS()) {
ExpectNotNull(decodedCrl = d2i_X509_CRL(NULL, crlBuf, crlSz));
@@ -25950,6 +26218,9 @@ static int test_wolfSSL_CTX_LoadCRL_largeCRLnum(void)
WOLFSSL_SUCCESS);
AssertIntEQ(XMEMCMP(
crlInfo.crlNumber, exp_crlnum, XSTRLEN(exp_crlnum)), 0);
ExpectIntEQ(wolfSSL_CertManagerGetCRLInfo(
cm, &crlInfo, crlLrgCrlNumBuff, -1, WOLFSSL_FILETYPE_PEM),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* Expect to fail loading CRL because of >21 octets CRL number */
ExpectIntEQ(wolfSSL_CertManagerLoadCRLFile(cm, crl_lrgcrlnum2,
WOLFSSL_FILETYPE_PEM),
@@ -28069,7 +28340,8 @@ static int test_SSL_CIPHER_get_xxx(void)
#if defined(WOLF_CRYPTO_CB) && defined(HAVE_IO_TESTS_DEPENDENCIES) && \
(!defined(WOLF_CRYPTO_CB_ONLY_SHA256) && !defined(WOLF_CRYPTO_CB_ONLY_AES) && \
!defined(WOLF_CRYPTO_CB_ONLY_ECC) && !defined(WOLF_CRYPTO_CB_ONLY_RSA))
!defined(WOLF_CRYPTO_CB_ONLY_ECC) && !defined(WOLF_CRYPTO_CB_ONLY_RSA) && \
!defined(WOLF_CRYPTO_CB_ONLY_SHA512))
static int load_pem_key_file_as_der(const char* privKeyFile, DerBuffer** pDer,
int* keyFormat)
@@ -29073,7 +29345,8 @@ static int test_wc_CryptoCb(void)
EXPECT_DECLS;
#if defined(WOLF_CRYPTO_CB) && \
(!defined(WOLF_CRYPTO_CB_ONLY_SHA256) && !defined(WOLF_CRYPTO_CB_ONLY_AES) && \
!defined(WOLF_CRYPTO_CB_ONLY_ECC) && !defined(WOLF_CRYPTO_CB_ONLY_RSA))
!defined(WOLF_CRYPTO_CB_ONLY_ECC) && !defined(WOLF_CRYPTO_CB_ONLY_RSA) && \
!defined(WOLF_CRYPTO_CB_ONLY_SHA512))
/* TODO: Add crypto callback API tests */
#ifdef HAVE_IO_TESTS_DEPENDENCIES
@@ -31493,8 +31766,9 @@ static int test_session_ticket_hs_update(void)
/**
* Make sure we don't send RSA Signature Hash Algorithms in the
* CertificateRequest when we don't have any such ciphers set.
* Make sure the CertificateRequest advertises ECDSA signature hash algorithms
* for an ECDHE-ECDSA server, and also includes RSA algorithms so that RSA
* clients can authenticate (the certificate_type advertised covers both).
* @return EXPECT_RESULT()
*/
static int test_certreq_sighash_algos(void)
@@ -31555,17 +31829,24 @@ static int test_certreq_sighash_algos(void)
idx += OPAQUE16_LEN;
maxIdx = idx + (int)len;
for (; idx < maxIdx && EXPECT_SUCCESS(); idx += OPAQUE16_LEN) {
if (test_ctx.c_buff[idx+1] == ED25519_SA_MINOR ||
test_ctx.c_buff[idx+1] == ED448_SA_MINOR ||
test_ctx.c_buff[idx+1] ==
ECDSA_BRAINPOOLP256R1TLS13_SHA256_MINOR ||
test_ctx.c_buff[idx+1] ==
ECDSA_BRAINPOOLP384R1TLS13_SHA384_MINOR ||
test_ctx.c_buff[idx+1] ==
ECDSA_BRAINPOOLP512R1TLS13_SHA512_MINOR)
ExpectIntEQ(test_ctx.c_buff[idx], NEW_SA_MAJOR);
else
ExpectIntEQ(test_ctx.c_buff[idx+1], ecc_dsa_sa_algo);
byte first = test_ctx.c_buff[idx];
byte second = test_ctx.c_buff[idx+1];
if (second == ED25519_SA_MINOR ||
second == ED448_SA_MINOR ||
second == ECDSA_BRAINPOOLP256R1TLS13_SHA256_MINOR ||
second == ECDSA_BRAINPOOLP384R1TLS13_SHA384_MINOR ||
second == ECDSA_BRAINPOOLP512R1TLS13_SHA512_MINOR) {
ExpectIntEQ(first, NEW_SA_MAJOR);
}
else {
/* ECDHE-ECDSA suites advertise ECDSA so the negotiated
* cipher can be used, and also RSA / RSA-PSS so RSA
* clients can authenticate via mutual auth. Note that
* RSA-PSS is encoded with sigAlgo first then mac. */
ExpectTrue(second == ecc_dsa_sa_algo ||
second == rsa_sa_algo ||
first == rsa_pss_sa_algo);
}
}
break;
}
@@ -33378,7 +33659,8 @@ static int test_DhAgree_rejects_p_minus_1(void)
static int test_ed448_rejects_identity_key(void)
{
EXPECT_DECLS;
#if defined(HAVE_ED448) && !defined(HAVE_SELFTEST) && \
#if defined(HAVE_ED448) && defined(HAVE_ED448_VERIFY) && \
defined(HAVE_ED448_KEY_IMPORT) && !defined(HAVE_SELFTEST) && \
(!defined(HAVE_FIPS) || FIPS_VERSION_GE(7,0))
ed448_key key;
byte identity[ED448_PUB_KEY_SIZE];
@@ -34636,7 +34918,7 @@ TEST_CASE testCases[] = {
/* OpenSSL sk_X509_CRL API test */
TEST_DECL(test_sk_X509_CRL_decode),
#if (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) && !defined(NO_CERTS) && \
defined(HAVE_CRL) && defined(WOLFSSL_CERT_GEN)
defined(HAVE_CRL) && defined(WOLFSSL_CERT_GEN) && !defined(NO_ASN_TIME)
TEST_DECL(test_wolfSSL_X509_CRL_add_revoked_oversized_revocation_date),
#endif
#if (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) && !defined(NO_CERTS) && \
@@ -34859,6 +35141,7 @@ TEST_CASE testCases[] = {
TEST_DECL(test_wolfSSL_CTX_use_certificate),
TEST_DECL(test_wolfSSL_CTX_use_certificate_file),
TEST_DECL(test_wolfSSL_CTX_use_certificate_buffer),
TEST_DECL(test_ProcessBuffer_negative_size),
TEST_DECL(test_wolfSSL_use_certificate_buffer),
TEST_DECL(test_wolfSSL_CTX_use_PrivateKey_file),
TEST_DECL(test_wolfSSL_CTX_use_RSAPrivateKey_file),
@@ -34935,6 +35218,7 @@ TEST_CASE testCases[] = {
TEST_DECL(test_wolfSSL_Tls12_Key_Logging_test),
/* Can't memory test as server hangs. */
TEST_DECL(test_wolfSSL_Tls13_Key_Logging_test),
TEST_DECL(test_wolfSSL_Tls13_Key_Logging_ech_rejected),
TEST_DECL(test_wolfSSL_Tls13_postauth),
TEST_DECL(test_wolfSSL_set_ecdh_auto),
TEST_DECL(test_wolfSSL_CTX_set_ecdh_auto),
@@ -34979,6 +35263,9 @@ TEST_CASE testCases[] = {
TEST_DECL(test_TLSX_SNI_GetSize_overflow),
TEST_DECL(test_TLSX_ECH_msg_type_validation),
TEST_DECL(test_TLSX_SRTP_msg_type_validation),
TEST_DECL(test_TLSX_ALPN_server_response_count),
TEST_DECL(test_TLSX_SupportedCurve_empty_or_unsupported),
TEST_DECL(test_TLSX_PointFormat_uncompressed_required),
TEST_DECL(test_wolfSSL_wolfSSL_UseSecureRenegotiation),
TEST_DECL(test_wolfSSL_clear_secure_renegotiation),
TEST_DECL(test_wolfSSL_SCR_Reconnect),
@@ -35109,6 +35396,9 @@ TEST_CASE testCases[] = {
TEST_DECL(test_revoked_loaded_int_cert),
TEST_DTLS_DECLS,
TEST_DTLS13_DECLS,
TEST_SSL_CERT_DECLS,
TEST_SSL_PK_DECLS,
TEST_SSL_EXT_DECLS,
TEST_DECL(test_tls_multi_handshakes_one_record),
TEST_DECL(test_write_dup),
TEST_DECL(test_write_dup_want_write),
@@ -35124,6 +35414,7 @@ TEST_CASE testCases[] = {
TEST_DECL(test_wolfSSL_inject),
TEST_DECL(test_ocsp_status_callback),
TEST_DECL(test_ocsp_basic_verify),
TEST_DECL(test_ocsp_ancestor_responder_rejected),
TEST_DECL(test_ocsp_responder_keyhash_binding),
TEST_DECL(test_ocsp_response_parsing),
TEST_DECL(test_ocsp_certid_enc_dec),
+19 -1
View File
@@ -421,6 +421,23 @@ if __name__ == '__main__':
'name': 'resp_bad_embedded_cert'
},
{
# intermediate1 signs OCSP for its subordinate server1
'response_status': 0,
'signature_algorithm': signature_algorithm(),
'responder_by_name': True,
'responder_cert': WOLFSSL_OCSP_CERT_PATH + 'intermediate1-ca-cert.pem',
'responses': [
{
'issuer_cert': WOLFSSL_OCSP_CERT_PATH + 'intermediate1-ca-cert.pem',
'serial': 0x05,
'status': CERT_GOOD
}
],
'responder_key': WOLFSSL_OCSP_CERT_PATH + 'intermediate1-ca-key.pem',
'name': 'resp_server1_cert'
},
{
# Ancestor-issued responder; rejected by RFC 6960 4.2.2.2 enforcement
'response_status': 0,
'signature_algorithm': signature_algorithm(),
'certs_path': [WOLFSSL_OCSP_CERT_PATH + 'ocsp-responder-cert.pem'],
@@ -433,7 +450,7 @@ if __name__ == '__main__':
}
],
'responder_key': WOLFSSL_OCSP_CERT_PATH + 'ocsp-responder-key.pem',
'name': 'resp_server1_cert'
'name': 'resp_server1_cert_ancestor_responder'
},
{
'response_status': 0,
@@ -557,6 +574,7 @@ if __name__ == '__main__':
add_certificate(WOLFSSL_OCSP_CERT_PATH + '../server-cert.pem', f)
add_certificate(WOLFSSL_OCSP_CERT_PATH + 'intermediate1-ca-cert.pem', f)
add_certificate(WOLFSSL_OCSP_CERT_PATH + 'imposter-root-ca-cert.pem', f)
add_certificate(WOLFSSL_OCSP_CERT_PATH + 'server1-cert.pem', f)
br = create_bad_response({
'response_status': 0,
'responder_by_key': True,
+6
View File
@@ -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
+9
View File
@@ -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));
+37
View File
@@ -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 <wolfssl/wolfcrypt/random.h>
+2
View File
@@ -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 */
+55
View File
@@ -1318,6 +1318,61 @@ int test_wc_DecodeRsaPssParams(void)
&hash, &mgf, &saltLen), WC_NO_ERR_TRACE(ASN_PARSE_E));
}
/* --- Test 9: trailerField = 1 (trailerFieldBC) => valid in all modes --- */
/* SEQUENCE { [3] CONSTRUCTED { INTEGER 1 } } = 30 05 a3 03 02 01 01 */
{
static const byte trailerValid[] = {
0x30, 0x05, 0xa3, 0x03, 0x02, 0x01, 0x01
};
hash = WC_HASH_TYPE_NONE;
mgf = 0;
saltLen = 0;
ExpectIntEQ(wc_DecodeRsaPssParams(trailerValid,
(word32)sizeof(trailerValid), &hash, &mgf, &saltLen), 0);
ExpectIntEQ((int)hash, (int)WC_HASH_TYPE_SHA);
ExpectIntEQ(mgf, WC_MGF1SHA1);
ExpectIntEQ(saltLen, 20);
}
#ifndef WOLFSSL_NO_ASN_STRICT
/* --- Test 10: trailerField = 2 => ASN_PARSE_E (strict mode) --- */
/* RFC 8017 A.2.3: trailerField SHALL be trailerFieldBC(1). */
/* SEQUENCE { [3] CONSTRUCTED { INTEGER 2 } } = 30 05 a3 03 02 01 02 */
{
static const byte trailerTwo[] = {
0x30, 0x05, 0xa3, 0x03, 0x02, 0x01, 0x02
};
ExpectIntEQ(wc_DecodeRsaPssParams(trailerTwo,
(word32)sizeof(trailerTwo), &hash, &mgf, &saltLen),
WC_NO_ERR_TRACE(ASN_PARSE_E));
}
/* --- Test 11: trailerField = 0 => ASN_PARSE_E (strict mode) --- */
/* SEQUENCE { [3] CONSTRUCTED { INTEGER 0 } } = 30 05 a3 03 02 01 00 */
{
static const byte trailerZero[] = {
0x30, 0x05, 0xa3, 0x03, 0x02, 0x01, 0x00
};
ExpectIntEQ(wc_DecodeRsaPssParams(trailerZero,
(word32)sizeof(trailerZero), &hash, &mgf, &saltLen),
WC_NO_ERR_TRACE(ASN_PARSE_E));
}
/* --- Test 12: trailerField = 256 (multi-byte INTEGER) => ASN_PARSE_E ---
* Exercises the 2-byte integer branch in GetInteger16Bit (non-template)
* and the len==2 case of ASN_DATA_TYPE_WORD16 (template path).
* SEQUENCE { [3] CONSTRUCTED { INTEGER 256 } } = 30 06 a3 04 02 02 01 00
*/
{
static const byte trailerMultiByte[] = {
0x30, 0x06, 0xa3, 0x04, 0x02, 0x02, 0x01, 0x00
};
ExpectIntEQ(wc_DecodeRsaPssParams(trailerMultiByte,
(word32)sizeof(trailerMultiByte), &hash, &mgf, &saltLen),
WC_NO_ERR_TRACE(ASN_PARSE_E));
}
#endif /* !WOLFSSL_NO_ASN_STRICT */
#endif /* WC_RSA_PSS && !NO_RSA && !NO_ASN */
return EXPECT_RESULT();
}
+166 -241
View File
@@ -2933,253 +2933,178 @@ int test_wolfSSL_CertManagerCheckOCSPResponse(void)
* - Run responder with
* openssl ocsp -port 9999 -ndays 9999
* -index certs/ocsp/index-intermediate1-ca-issued-certs.txt
* -rsigner certs/ocsp/ocsp-responder-cert.pem
* -rkey certs/ocsp/ocsp-responder-key.pem
* -rsigner certs/ocsp/intermediate1-ca-cert.pem
* -rkey certs/ocsp/intermediate1-ca-key.pem
* -CA certs/ocsp/intermediate1-ca-cert.pem
* - Run client with
* openssl ocsp -host 127.0.0.1:9999 -respout resp.out
* -issuer certs/ocsp/intermediate1-ca-cert.pem
* -cert certs/ocsp/server1-cert.pem
* -CAfile certs/ocsp/root-ca-cert.pem -noverify
* - Select the response packet in Wireshark, and export it using
* "File->Export Packet Dissection->As "C" Arrays". Select "Selected
* packets only". After importing into the editor, remove the initial
* ~148 bytes of header, ending with the Content-Length and the \r\n\r\n.
* - Convert resp.out to a C array (e.g. xxd -i -c 12 resp.out) and paste
* the bytes below.
*/
static const byte response[] = {
0x30, 0x82, 0x07, 0x40, /* ....0..@ */
0x0a, 0x01, 0x00, 0xa0, 0x82, 0x07, 0x39, 0x30, /* ......90 */
0x82, 0x07, 0x35, 0x06, 0x09, 0x2b, 0x06, 0x01, /* ..5..+.. */
0x05, 0x05, 0x07, 0x30, 0x01, 0x01, 0x04, 0x82, /* ...0.... */
0x07, 0x26, 0x30, 0x82, 0x07, 0x22, 0x30, 0x82, /* .&0.."0. */
0x01, 0x40, 0xa1, 0x81, 0xa1, 0x30, 0x81, 0x9e, /* .@...0.. */
0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, /* 1.0...U. */
0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, /* ...US1.0 */
0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, /* ...U.... */
0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, /* Washingt */
0x6f, 0x6e, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, /* on1.0... */
0x55, 0x04, 0x07, 0x0c, 0x07, 0x53, 0x65, 0x61, /* U....Sea */
0x74, 0x74, 0x6c, 0x65, 0x31, 0x10, 0x30, 0x0e, /* ttle1.0. */
0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x07, 0x77, /* ..U....w */
0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, 0x31, 0x14, /* olfSSL1. */
0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, /* 0...U... */
0x0b, 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x65, /* .Enginee */
0x72, 0x69, 0x6e, 0x67, 0x31, 0x1f, 0x30, 0x1d, /* ring1.0. */
0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x77, /* ..U....w */
0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, 0x20, 0x4f, /* olfSSL O */
0x43, 0x53, 0x50, 0x20, 0x52, 0x65, 0x73, 0x70, /* CSP Resp */
0x6f, 0x6e, 0x64, 0x65, 0x72, 0x31, 0x1f, 0x30, /* onder1.0 */
0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, /* ...*.H.. */
0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6e, /* ......in */
0x66, 0x6f, 0x40, 0x77, 0x6f, 0x6c, 0x66, 0x73, /* fo@wolfs */
0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x18, 0x0f, /* sl.com.. */
0x32, 0x30, 0x32, 0x34, 0x31, 0x32, 0x32, 0x30, /* 20241220 */
0x31, 0x37, 0x30, 0x37, 0x30, 0x34, 0x5a, 0x30, /* 170704Z0 */
0x64, 0x30, 0x62, 0x30, 0x3a, 0x30, 0x09, 0x06, /* d0b0:0.. */
0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, /* .+...... */
0x04, 0x14, 0x71, 0x4d, 0x82, 0x23, 0x40, 0x59, /* ..qM.#@Y */
0xc0, 0x96, 0xa1, 0x37, 0x43, 0xfa, 0x31, 0xdb, /* ...7C.1. */
0xba, 0xb1, 0x43, 0x18, 0xda, 0x04, 0x04, 0x14, /* ..C..... */
0x83, 0xc6, 0x3a, 0x89, 0x2c, 0x81, 0xf4, 0x02, /* ..:.,... */
0xd7, 0x9d, 0x4c, 0xe2, 0x2a, 0xc0, 0x71, 0x82, /* ..L.*.q. */
0x64, 0x44, 0xda, 0x0e, 0x02, 0x01, 0x05, 0x80, /* dD...... */
0x00, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x34, 0x31, /* ...20241 */
0x32, 0x32, 0x30, 0x31, 0x37, 0x30, 0x37, 0x30, /* 22017070 */
0x34, 0x5a, 0xa0, 0x11, 0x18, 0x0f, 0x32, 0x30, /* 4Z....20 */
0x35, 0x32, 0x30, 0x35, 0x30, 0x36, 0x31, 0x37, /* 52050617 */
0x30, 0x37, 0x30, 0x34, 0x5a, 0xa1, 0x23, 0x30, /* 0704Z.#0 */
0x21, 0x30, 0x1f, 0x06, 0x09, 0x2b, 0x06, 0x01, /* !0...+.. */
0x05, 0x05, 0x07, 0x30, 0x01, 0x02, 0x04, 0x12, /* ...0.... */
0x04, 0x10, 0x12, 0x7c, 0x27, 0xbd, 0x22, 0x28, /* ...|'."( */
0x5e, 0x62, 0x81, 0xed, 0x6d, 0x2c, 0x2d, 0x59, /* ^b..m,-Y */
0x42, 0xd7, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, /* B.0...*. */
0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, /* H....... */
0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x6c, 0xce, /* ......l. */
0xa8, 0xe8, 0xfe, 0xaf, 0x33, 0xe2, 0xce, 0x4e, /* ....3..N */
0x63, 0x8d, 0x61, 0x16, 0x0f, 0x70, 0xb2, 0x0c, /* c.a..p.. */
0x9a, 0xe3, 0x01, 0xd5, 0xca, 0xe5, 0x9b, 0x70, /* .......p */
0x81, 0x6f, 0x94, 0x09, 0xe8, 0x88, 0x98, 0x1a, /* .o...... */
0x67, 0xa0, 0xc2, 0xe7, 0x8f, 0x9b, 0x5f, 0x13, /* g....._. */
0x17, 0x8d, 0x93, 0x8c, 0x31, 0x61, 0x7d, 0x72, /* ....1a}r */
0x34, 0xbd, 0x21, 0x48, 0xca, 0xb2, 0xc9, 0xae, /* 4.!H.... */
0x28, 0x5f, 0x97, 0x19, 0xcb, 0xdf, 0xed, 0xd4, /* (_...... */
0x6e, 0x89, 0x30, 0x89, 0x11, 0xd1, 0x05, 0x08, /* n.0..... */
0x81, 0xe9, 0xa7, 0xba, 0xf7, 0x16, 0x0c, 0xbe, /* ........ */
0x48, 0x2e, 0xc0, 0x05, 0xac, 0x90, 0xc2, 0x35, /* H......5 */
0xce, 0x6c, 0x94, 0x5d, 0x2b, 0xad, 0x4f, 0x19, /* .l.]+.O. */
0xea, 0x7b, 0xd9, 0x4f, 0x49, 0x20, 0x8d, 0x98, /* .{.OI .. */
0xa9, 0xe4, 0x53, 0x6d, 0xca, 0x34, 0xdb, 0x4a, /* ..Sm.4.J */
0x28, 0xb3, 0x33, 0xfb, 0xfd, 0xcc, 0x4b, 0xfa, /* (.3...K. */
0xdb, 0x70, 0xe1, 0x96, 0xc8, 0xd4, 0xf1, 0x85, /* .p...... */
0x99, 0xaf, 0x06, 0xeb, 0xfd, 0x96, 0x21, 0x86, /* ......!. */
0x81, 0xee, 0xcf, 0xd2, 0xf4, 0x83, 0xc9, 0x1d, /* ........ */
0x8f, 0x42, 0xd1, 0xc1, 0xbc, 0x50, 0x0a, 0xfb, /* .B...P.. */
0x95, 0x39, 0x4c, 0x36, 0xa8, 0xfe, 0x2b, 0x8e, /* .9L6..+. */
0xc5, 0xb5, 0xe0, 0xab, 0xdb, 0xc0, 0xbf, 0x1d, /* ........ */
0x35, 0x4d, 0xc0, 0x52, 0xfb, 0x08, 0x04, 0x4c, /* 5M.R...L */
0x98, 0xf0, 0xb5, 0x5b, 0xff, 0x99, 0x74, 0xce, /* ...[..t. */
0xb7, 0xc9, 0xe3, 0xe5, 0x70, 0x2e, 0xd3, 0x1d, /* ....p... */
0x46, 0x38, 0xf9, 0x51, 0x17, 0x73, 0xd1, 0x08, /* F8.Q.s.. */
0x8d, 0x3d, 0x12, 0x47, 0xd0, 0x66, 0x77, 0xaf, /* .=.G.fw. */
0xfd, 0x4c, 0x75, 0x1f, 0xe9, 0x6c, 0xf4, 0x5a, /* .Lu..l.Z */
0xde, 0xec, 0x37, 0xc7, 0xc4, 0x0a, 0xbe, 0x91, /* ..7..... */
0xbc, 0x05, 0x08, 0x86, 0x47, 0x30, 0x2a, 0xc6, /* ....G0*. */
0x85, 0x4b, 0x55, 0x6c, 0xef, 0xdf, 0x2d, 0x5a, /* .KUl..-Z */
0xf7, 0x5b, 0xb5, 0xba, 0xed, 0x38, 0xb0, 0xcb, /* .[...8.. */
0xeb, 0x7e, 0x84, 0x3a, 0x69, 0x2c, 0xa0, 0x82, /* .~.:i,.. */
0x04, 0xc6, 0x30, 0x82, 0x04, 0xc2, 0x30, 0x82, /* ..0...0. */
0x04, 0xbe, 0x30, 0x82, 0x03, 0xa6, 0xa0, 0x03, /* ..0..... */
0x02, 0x01, 0x02, 0x02, 0x01, 0x04, 0x30, 0x0d, /* ......0. */
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, /* ..*.H... */
0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0x97, /* .....0.. */
0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, /* 1.0...U. */
0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, /* ...US1.0 */
0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, /* ...U.... */
0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, /* Washingt */
0x6f, 0x6e, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, /* on1.0... */
0x55, 0x04, 0x07, 0x0c, 0x07, 0x53, 0x65, 0x61, /* U....Sea */
0x74, 0x74, 0x6c, 0x65, 0x31, 0x10, 0x30, 0x0e, /* ttle1.0. */
0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x07, 0x77, /* ..U....w */
0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, 0x31, 0x14, /* olfSSL1. */
0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, /* 0...U... */
0x0b, 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x65, /* .Enginee */
0x72, 0x69, 0x6e, 0x67, 0x31, 0x18, 0x30, 0x16, /* ring1.0. */
0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0f, 0x77, /* ..U....w */
0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, 0x20, 0x72, /* olfSSL r */
0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1f, /* oot CA1. */
0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, /* 0...*.H. */
0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, /* .......i */
0x6e, 0x66, 0x6f, 0x40, 0x77, 0x6f, 0x6c, 0x66, /* nfo@wolf */
0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x30, /* ssl.com0 */
0x1e, 0x17, 0x0d, 0x32, 0x34, 0x31, 0x32, 0x31, /* ...24121 */
0x38, 0x32, 0x31, 0x32, 0x35, 0x33, 0x31, 0x5a, /* 8212531Z */
0x17, 0x0d, 0x32, 0x37, 0x30, 0x39, 0x31, 0x34, /* ..270914 */
0x32, 0x31, 0x32, 0x35, 0x33, 0x31, 0x5a, 0x30, /* 212531Z0 */
0x81, 0x9e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, /* ..1.0... */
0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, /* U....US1 */
0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, /* .0...U.. */
0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, /* ..Washin */
0x67, 0x74, 0x6f, 0x6e, 0x31, 0x10, 0x30, 0x0e, /* gton1.0. */
0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x07, 0x53, /* ..U....S */
0x65, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x31, 0x10, /* eattle1. */
0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, /* 0...U... */
0x07, 0x77, 0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, /* .wolfSSL */
0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, /* 1.0...U. */
0x0b, 0x0c, 0x0b, 0x45, 0x6e, 0x67, 0x69, 0x6e, /* ...Engin */
0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x31, 0x1f, /* eering1. */
0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, /* 0...U... */
0x16, 0x77, 0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, /* .wolfSSL */
0x20, 0x4f, 0x43, 0x53, 0x50, 0x20, 0x52, 0x65, /* OCSP Re */
0x73, 0x70, 0x6f, 0x6e, 0x64, 0x65, 0x72, 0x31, /* sponder1 */
0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, /* .0...*.H */
0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, /* ........ */
0x69, 0x6e, 0x66, 0x6f, 0x40, 0x77, 0x6f, 0x6c, /* info@wol */
0x66, 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, /* fssl.com */
0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, /* 0.."0... */
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, /* *.H..... */
0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, /* ........ */
0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, /* 0....... */
0x00, 0xb8, 0xba, 0x23, 0xb4, 0xf6, 0xc3, 0x7b, /* ...#...{ */
0x14, 0xc3, 0xa4, 0xf5, 0x1d, 0x61, 0xa1, 0xf5, /* .....a.. */
0x1e, 0x63, 0xb9, 0x85, 0x23, 0x34, 0x50, 0x6d, /* .c..#4Pm */
0xf8, 0x7c, 0xa2, 0x8a, 0x04, 0x8b, 0xd5, 0x75, /* .|.....u */
0x5c, 0x2d, 0xf7, 0x63, 0x88, 0xd1, 0x07, 0x7a, /* \-.c...z */
0xea, 0x0b, 0x45, 0x35, 0x2b, 0xeb, 0x1f, 0xb1, /* ..E5+... */
0x22, 0xb4, 0x94, 0x41, 0x38, 0xe2, 0x9d, 0x74, /* "..A8..t */
0xd6, 0x8b, 0x30, 0x22, 0x10, 0x51, 0xc5, 0xdb, /* ..0".Q.. */
0xca, 0x3f, 0x46, 0x2b, 0xfe, 0xe5, 0x5a, 0x3f, /* .?F+..Z? */
0x41, 0x74, 0x67, 0x75, 0x95, 0xa9, 0x94, 0xd5, /* Atgu.... */
0xc3, 0xee, 0x42, 0xf8, 0x8d, 0xeb, 0x92, 0x95, /* ..B..... */
0xe1, 0xd9, 0x65, 0xb7, 0x43, 0xc4, 0x18, 0xde, /* ..e.C... */
0x16, 0x80, 0x90, 0xce, 0x24, 0x35, 0x21, 0xc4, /* ....$5!. */
0x55, 0xac, 0x5a, 0x51, 0xe0, 0x2e, 0x2d, 0xb3, /* U.ZQ..-. */
0x0a, 0x5a, 0x4f, 0x4a, 0x73, 0x31, 0x50, 0xee, /* .ZOJs1P. */
0x4a, 0x16, 0xbd, 0x39, 0x8b, 0xad, 0x05, 0x48, /* J..9...H */
0x87, 0xb1, 0x99, 0xe2, 0x10, 0xa7, 0x06, 0x72, /* .......r */
0x67, 0xca, 0x5c, 0xd1, 0x97, 0xbd, 0xc8, 0xf1, /* g.\..... */
0x76, 0xf8, 0xe0, 0x4a, 0xec, 0xbc, 0x93, 0xf4, /* v..J.... */
0x66, 0x4c, 0x28, 0x71, 0xd1, 0xd8, 0x66, 0x03, /* fL(q..f. */
0xb4, 0x90, 0x30, 0xbb, 0x17, 0xb0, 0xfe, 0x97, /* ..0..... */
0xf5, 0x1e, 0xe8, 0xc7, 0x5d, 0x9b, 0x8b, 0x11, /* ....]... */
0x19, 0x12, 0x3c, 0xab, 0x82, 0x71, 0x78, 0xff, /* ..<..qx. */
0xae, 0x3f, 0x32, 0xb2, 0x08, 0x71, 0xb2, 0x1b, /* .?2..q.. */
0x8c, 0x27, 0xac, 0x11, 0xb8, 0xd8, 0x43, 0x49, /* .'....CI */
0xcf, 0xb0, 0x70, 0xb1, 0xf0, 0x8c, 0xae, 0xda, /* ..p..... */
0x24, 0x87, 0x17, 0x3b, 0xd8, 0x04, 0x65, 0x6c, /* $..;..el */
0x00, 0x76, 0x50, 0xef, 0x15, 0x08, 0xd7, 0xb4, /* .vP..... */
0x73, 0x68, 0x26, 0x14, 0x87, 0x95, 0xc3, 0x5f, /* sh&...._ */
0x6e, 0x61, 0xb8, 0x87, 0x84, 0xfa, 0x80, 0x1a, /* na...... */
0x0a, 0x8b, 0x98, 0xf3, 0xe3, 0xff, 0x4e, 0x44, /* ......ND */
0x1c, 0x65, 0x74, 0x7c, 0x71, 0x54, 0x65, 0xe5, /* .et|qTe. */
0x39, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, /* 9....... */
0x01, 0x0a, 0x30, 0x82, 0x01, 0x06, 0x30, 0x09, /* ..0...0. */
0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, /* ..U....0 */
0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, /* .0...U.. */
0x04, 0x16, 0x04, 0x14, 0x32, 0x67, 0xe1, 0xb1, /* ....2g.. */
0x79, 0xd2, 0x81, 0xfc, 0x9f, 0x23, 0x0c, 0x70, /* y....#.p */
0x40, 0x50, 0xb5, 0x46, 0x56, 0xb8, 0x30, 0x36, /* @P.FV.06 */
0x30, 0x81, 0xc4, 0x06, 0x03, 0x55, 0x1d, 0x23, /* 0....U.# */
0x04, 0x81, 0xbc, 0x30, 0x81, 0xb9, 0x80, 0x14, /* ...0.... */
0x73, 0xb0, 0x1c, 0xa4, 0x2f, 0x82, 0xcb, 0xcf, /* s.../... */
0x47, 0xa5, 0x38, 0xd7, 0xb0, 0x04, 0x82, 0x3a, /* G.8....: */
0x7e, 0x72, 0x15, 0x21, 0xa1, 0x81, 0x9d, 0xa4, /* ~r.!.... */
0x81, 0x9a, 0x30, 0x81, 0x97, 0x31, 0x0b, 0x30, /* ..0..1.0 */
0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, /* ...U.... */
0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, /* US1.0... */
0x55, 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, /* U....Was */
0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e, 0x31, /* hington1 */
0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, /* .0...U.. */
0x0c, 0x07, 0x53, 0x65, 0x61, 0x74, 0x74, 0x6c, /* ..Seattl */
0x65, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, /* e1.0...U */
0x04, 0x0a, 0x0c, 0x07, 0x77, 0x6f, 0x6c, 0x66, /* ....wolf */
0x53, 0x53, 0x4c, 0x31, 0x14, 0x30, 0x12, 0x06, /* SSL1.0.. */
0x03, 0x55, 0x04, 0x0b, 0x0c, 0x0b, 0x45, 0x6e, /* .U....En */
0x67, 0x69, 0x6e, 0x65, 0x65, 0x72, 0x69, 0x6e, /* gineerin */
0x67, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, /* g1.0...U */
0x04, 0x03, 0x0c, 0x0f, 0x77, 0x6f, 0x6c, 0x66, /* ....wolf */
0x53, 0x53, 0x4c, 0x20, 0x72, 0x6f, 0x6f, 0x74, /* SSL root */
0x20, 0x43, 0x41, 0x31, 0x1f, 0x30, 0x1d, 0x06, /* CA1.0.. */
0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, /* .*.H.... */
0x09, 0x01, 0x16, 0x10, 0x69, 0x6e, 0x66, 0x6f, /* ....info */
0x40, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73, 0x6c, /* @wolfssl */
0x2e, 0x63, 0x6f, 0x6d, 0x82, 0x01, 0x63, 0x30, /* .com..c0 */
0x13, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x0c, /* ...U.%.. */
0x30, 0x0a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, /* 0...+... */
0x05, 0x07, 0x03, 0x09, 0x30, 0x0d, 0x06, 0x09, /* ....0... */
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, /* *.H..... */
0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, /* ........ */
0x4d, 0xa2, 0xd8, 0x55, 0xe0, 0x2b, 0xf4, 0xad, /* M..U.+.. */
0x65, 0xe2, 0x92, 0x35, 0xcb, 0x60, 0xa0, 0xa2, /* e..5.`.. */
0x6b, 0xa6, 0x88, 0xc1, 0x86, 0x58, 0x57, 0x37, /* k....XW7 */
0xbd, 0x2e, 0x28, 0x6e, 0x1c, 0x56, 0x2a, 0x35, /* ..(n.V*5 */
0xde, 0xff, 0x3e, 0x8e, 0x3d, 0x47, 0x21, 0x1a, /* ..>.=G!. */
0xe9, 0xd3, 0xc6, 0xb4, 0xe2, 0xcb, 0x3e, 0xc6, /* ......>. */
0xaf, 0x9b, 0xef, 0x23, 0x88, 0x56, 0x95, 0x73, /* ...#.V.s */
0x2e, 0xb3, 0xed, 0xc5, 0x11, 0x4b, 0x69, 0xf7, /* .....Ki. */
0x13, 0x3a, 0x05, 0xe1, 0xaf, 0xba, 0xc9, 0x59, /* .:.....Y */
0xfd, 0xe2, 0xa0, 0x81, 0xa0, 0x4c, 0x0c, 0x2c, /* .....L., */
0xcb, 0x57, 0xad, 0x96, 0x3a, 0x8c, 0x32, 0xa6, /* .W..:.2. */
0x4a, 0xf8, 0x72, 0xb8, 0xec, 0xb3, 0x26, 0x69, /* J.r...&i */
0xd6, 0x6a, 0x4c, 0x4c, 0x78, 0x18, 0x3c, 0xca, /* .jLLx.<. */
0x19, 0xf1, 0xb5, 0x8e, 0x23, 0x81, 0x5b, 0x27, /* ....#.[' */
0x90, 0xe0, 0x5c, 0x2b, 0x17, 0x4d, 0x78, 0x99, /* ..\+.Mx. */
0x6b, 0x25, 0xbd, 0x2f, 0xae, 0x1b, 0xaa, 0xce, /* k%./.... */
0x84, 0xb9, 0x44, 0x21, 0x46, 0xc0, 0x34, 0x6b, /* ..D!F.4k */
0x5b, 0xb9, 0x1b, 0xca, 0x5c, 0x60, 0xf1, 0xef, /* [...\`.. */
0xe6, 0x66, 0xbc, 0x84, 0x63, 0x56, 0x50, 0x7d, /* .f..cVP} */
0xbb, 0x2c, 0x2f, 0x7b, 0x47, 0xb4, 0xfd, 0x58, /* .,/{G..X */
0x77, 0x87, 0xee, 0x27, 0x20, 0x96, 0x72, 0x8e, /* w..' .r. */
0x4c, 0x7e, 0x4f, 0x93, 0xeb, 0x5f, 0x8f, 0x9c, /* L~O.._.. */
0x1e, 0x59, 0x7a, 0x96, 0xaa, 0x53, 0x77, 0x22, /* .Yz..Sw" */
0x41, 0xd8, 0xd3, 0xf9, 0x89, 0x8f, 0xe8, 0x9d, /* A....... */
0x65, 0xbd, 0x0c, 0x71, 0x3c, 0xbb, 0xa3, 0x07, /* e..q<... */
0xbf, 0xfb, 0xa8, 0xd1, 0x18, 0x0a, 0xb4, 0xc4, /* ........ */
0xf7, 0x83, 0xb3, 0x86, 0x2b, 0xf0, 0x5b, 0x05, /* ....+.[. */
0x28, 0xc1, 0x01, 0x31, 0x73, 0x5c, 0x2b, 0xbd, /* (..1s\+. */
0x60, 0x97, 0xa3, 0x36, 0x82, 0x96, 0xd7, 0x83, /* `..6.... */
0xdf, 0x75, 0xee, 0x29, 0x42, 0x97, 0x86, 0x41, /* .u.)B..A */
0x55, 0xb9, 0x70, 0x87, 0xd5, 0x02, 0x85, 0x13, /* U.p..... */
0x41, 0xf8, 0x25, 0x05, 0xab, 0x6a, 0xaa, 0x57 /* A.%..j.W */
0x30, 0x82, 0x07, 0x75, 0x0a, 0x01, 0x00, 0xa0, 0x82, 0x07, 0x6e, 0x30,
0x82, 0x07, 0x6a, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30,
0x01, 0x01, 0x04, 0x82, 0x07, 0x5b, 0x30, 0x82, 0x07, 0x57, 0x30, 0x82,
0x01, 0x43, 0xa1, 0x81, 0xa4, 0x30, 0x81, 0xa1, 0x31, 0x0b, 0x30, 0x09,
0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30,
0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68,
0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03,
0x55, 0x04, 0x07, 0x0c, 0x07, 0x53, 0x65, 0x61, 0x74, 0x74, 0x6c, 0x65,
0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x07, 0x77,
0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03,
0x55, 0x04, 0x0b, 0x0c, 0x0b, 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x65,
0x72, 0x69, 0x6e, 0x67, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04,
0x03, 0x0c, 0x19, 0x77, 0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, 0x20, 0x69,
0x6e, 0x74, 0x65, 0x72, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x20,
0x43, 0x41, 0x20, 0x31, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86,
0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6e, 0x66,
0x6f, 0x40, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f,
0x6d, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x36, 0x30, 0x35, 0x32, 0x36, 0x31,
0x35, 0x30, 0x35, 0x30, 0x31, 0x5a, 0x30, 0x64, 0x30, 0x62, 0x30, 0x3a,
0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04,
0x14, 0x71, 0x4d, 0x82, 0x23, 0x40, 0x59, 0xc0, 0x96, 0xa1, 0x37, 0x43,
0xfa, 0x31, 0xdb, 0xba, 0xb1, 0x43, 0x18, 0xda, 0x04, 0x04, 0x14, 0x83,
0xc6, 0x3a, 0x89, 0x2c, 0x81, 0xf4, 0x02, 0xd7, 0x9d, 0x4c, 0xe2, 0x2a,
0xc0, 0x71, 0x82, 0x64, 0x44, 0xda, 0x0e, 0x02, 0x01, 0x05, 0x80, 0x00,
0x18, 0x0f, 0x32, 0x30, 0x32, 0x36, 0x30, 0x35, 0x32, 0x36, 0x31, 0x35,
0x30, 0x35, 0x30, 0x31, 0x5a, 0xa0, 0x11, 0x18, 0x0f, 0x32, 0x30, 0x35,
0x33, 0x31, 0x30, 0x31, 0x30, 0x31, 0x35, 0x30, 0x35, 0x30, 0x31, 0x5a,
0xa1, 0x23, 0x30, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x05,
0x05, 0x07, 0x30, 0x01, 0x02, 0x04, 0x12, 0x04, 0x10, 0x8b, 0xb7, 0x65,
0x51, 0xcf, 0x19, 0x82, 0x34, 0x51, 0x0a, 0xfb, 0x1a, 0x20, 0xad, 0x7c,
0x9a, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x1a, 0x5d, 0xa2,
0xf4, 0x02, 0x97, 0x5e, 0x0f, 0xf8, 0x6d, 0x9c, 0x81, 0xc1, 0x40, 0x5c,
0xae, 0xe4, 0x4f, 0x06, 0x68, 0x5b, 0x9c, 0xc3, 0xb0, 0x48, 0x51, 0xd7,
0x28, 0x59, 0x78, 0x97, 0x4b, 0x87, 0xca, 0x91, 0x78, 0x44, 0xaa, 0x63,
0xfd, 0x2e, 0xb3, 0xd0, 0x38, 0x79, 0xc3, 0x89, 0xee, 0xa5, 0x98, 0xf9,
0xb9, 0xfc, 0x5b, 0x40, 0x5d, 0x7b, 0x0b, 0xf0, 0xd9, 0xf0, 0x31, 0x00,
0xe8, 0x31, 0x47, 0xb9, 0x58, 0x0b, 0x20, 0x0d, 0x07, 0x9e, 0x2f, 0x6e,
0xba, 0xb2, 0x6d, 0x1e, 0x03, 0x9a, 0xa9, 0xd3, 0xac, 0x8e, 0xf0, 0x7f,
0x27, 0x3f, 0xd3, 0x30, 0x11, 0x17, 0x72, 0x5c, 0x46, 0x94, 0xc8, 0xb3,
0x23, 0xdc, 0x4a, 0x93, 0xe8, 0x8a, 0xdc, 0x9e, 0x55, 0x8f, 0x2b, 0xbf,
0x9f, 0x75, 0x05, 0xfc, 0xc6, 0x6f, 0xcc, 0x90, 0x80, 0x78, 0xc3, 0x13,
0x60, 0xe2, 0x53, 0xf2, 0xeb, 0xc0, 0x1b, 0xb8, 0x88, 0x1b, 0x01, 0xf7,
0x71, 0x6e, 0x4b, 0xdc, 0xdc, 0x9b, 0x0f, 0x6d, 0x5e, 0xe3, 0x2c, 0x58,
0x3d, 0xff, 0x74, 0xbc, 0xcd, 0x91, 0x0a, 0x80, 0x4a, 0xd9, 0xb4, 0xe2,
0x88, 0x7a, 0x6d, 0x16, 0x5d, 0xbc, 0x33, 0x1e, 0xae, 0x0d, 0xa3, 0xd8,
0xcb, 0xd6, 0x94, 0x31, 0xfa, 0x03, 0x80, 0xcd, 0x36, 0xa8, 0xbc, 0xce,
0xa4, 0x0f, 0x36, 0xc5, 0x44, 0x71, 0x34, 0xab, 0xe0, 0xbd, 0x56, 0xbd,
0x9b, 0x28, 0xde, 0x85, 0xf3, 0xe7, 0x66, 0x36, 0x0f, 0x80, 0x1c, 0x94,
0x4d, 0xd0, 0xb3, 0x5d, 0xbd, 0x0b, 0x93, 0xff, 0x67, 0x35, 0x40, 0xff,
0x85, 0xb8, 0xb9, 0xa8, 0xdc, 0xda, 0x90, 0xee, 0x18, 0x10, 0x6c, 0x2f,
0x1d, 0xbd, 0x5e, 0x2a, 0x29, 0x00, 0x62, 0x82, 0x33, 0xe4, 0xac, 0x82,
0x4f, 0x79, 0x53, 0x05, 0xf2, 0x38, 0x12, 0x9a, 0x3b, 0xe2, 0xce, 0xec,
0xd3, 0xa0, 0x82, 0x04, 0xf8, 0x30, 0x82, 0x04, 0xf4, 0x30, 0x82, 0x04,
0xf0, 0x30, 0x82, 0x03, 0xd8, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01,
0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0x97, 0x31, 0x0b, 0x30, 0x09, 0x06,
0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11,
0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69,
0x6e, 0x67, 0x74, 0x6f, 0x6e, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55,
0x04, 0x07, 0x0c, 0x07, 0x53, 0x65, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x31,
0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x07, 0x77, 0x6f,
0x6c, 0x66, 0x53, 0x53, 0x4c, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55,
0x04, 0x0b, 0x0c, 0x0b, 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x65, 0x72,
0x69, 0x6e, 0x67, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03,
0x0c, 0x0f, 0x77, 0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, 0x20, 0x72, 0x6f,
0x6f, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a,
0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6e,
0x66, 0x6f, 0x40, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73, 0x6c, 0x2e, 0x63,
0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x35, 0x31, 0x31, 0x31, 0x33,
0x32, 0x30, 0x34, 0x31, 0x33, 0x34, 0x5a, 0x17, 0x0d, 0x32, 0x38, 0x30,
0x38, 0x30, 0x39, 0x32, 0x30, 0x34, 0x31, 0x33, 0x34, 0x5a, 0x30, 0x81,
0xa1, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c,
0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e, 0x31,
0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x07, 0x53, 0x65,
0x61, 0x74, 0x74, 0x6c, 0x65, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55,
0x04, 0x0a, 0x0c, 0x07, 0x77, 0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c, 0x31,
0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x0b, 0x45, 0x6e,
0x67, 0x69, 0x6e, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x31, 0x22, 0x30,
0x20, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x19, 0x77, 0x6f, 0x6c, 0x66,
0x53, 0x53, 0x4c, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6d, 0x65, 0x64,
0x69, 0x61, 0x74, 0x65, 0x20, 0x43, 0x41, 0x20, 0x31, 0x31, 0x1f, 0x30,
0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01,
0x16, 0x10, 0x69, 0x6e, 0x66, 0x6f, 0x40, 0x77, 0x6f, 0x6c, 0x66, 0x73,
0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d,
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82,
0x01, 0x01, 0x00, 0xde, 0xb4, 0xc8, 0x5c, 0x77, 0xe0, 0x2d, 0xb1, 0xf5,
0xb9, 0xad, 0x16, 0x47, 0x35, 0xa0, 0x35, 0x65, 0x65, 0xc6, 0xe1, 0x40,
0xab, 0x1e, 0xb4, 0xb9, 0x13, 0xb7, 0xcb, 0x8c, 0xbb, 0x77, 0xa5, 0x76,
0xda, 0x6d, 0x87, 0x87, 0xf6, 0x4a, 0x4d, 0x13, 0xe4, 0x26, 0x3e, 0x27,
0x87, 0xee, 0x5b, 0xc7, 0x6a, 0x3f, 0x45, 0x30, 0x61, 0x55, 0x5c, 0xf6,
0x35, 0xd1, 0x65, 0xfa, 0x98, 0x11, 0xa3, 0xa7, 0x55, 0xd5, 0xbe, 0x91,
0x82, 0x4b, 0xfc, 0xbe, 0x90, 0xd6, 0x50, 0x53, 0x63, 0x9a, 0x2c, 0x22,
0xe1, 0x35, 0x11, 0xdc, 0x78, 0x02, 0x97, 0x8a, 0xe4, 0x46, 0x92, 0x9c,
0x53, 0x08, 0x76, 0xde, 0x1f, 0x53, 0xb6, 0xb8, 0xca, 0x77, 0x3e, 0x79,
0x6e, 0xbc, 0xd0, 0xe3, 0x0d, 0x30, 0x5b, 0x4c, 0xf6, 0x94, 0x0d, 0x30,
0x29, 0x64, 0x9f, 0x04, 0xe5, 0xdb, 0xfb, 0x89, 0x60, 0x67, 0xbb, 0xaf,
0x26, 0x83, 0x51, 0x77, 0x24, 0x2f, 0x2b, 0x0b, 0xa1, 0x94, 0x81, 0x10,
0x98, 0xe8, 0xeb, 0x26, 0xa8, 0x1e, 0x7c, 0xe4, 0xc4, 0x6c, 0x67, 0x06,
0x95, 0x55, 0x4a, 0xdd, 0x52, 0xf4, 0xf2, 0x60, 0x6d, 0x01, 0x2b, 0x19,
0x91, 0x35, 0x6d, 0xa4, 0x08, 0x47, 0x06, 0x71, 0x24, 0x00, 0xd9, 0xde,
0xc6, 0x56, 0xf3, 0x8b, 0x53, 0x2c, 0xe2, 0x9a, 0x96, 0xa5, 0xf3, 0x62,
0xe5, 0xc4, 0xe3, 0x23, 0xf2, 0xd2, 0xfc, 0x21, 0xea, 0x0f, 0x62, 0x76,
0x8d, 0xd5, 0x99, 0x48, 0xce, 0xdc, 0x58, 0xc4, 0xbb, 0x7f, 0xda, 0x94,
0x2c, 0x80, 0x74, 0x83, 0xc5, 0xe0, 0xb0, 0x15, 0x7e, 0x41, 0xfd, 0x0e,
0xf2, 0xf4, 0xf0, 0x78, 0x76, 0x7b, 0xad, 0x26, 0x0d, 0xaa, 0x48, 0x96,
0x17, 0x2f, 0x21, 0xe3, 0x95, 0x2b, 0x26, 0x37, 0xf9, 0xaa, 0x80, 0x2f,
0xfe, 0xde, 0xf6, 0x5e, 0xbc, 0x97, 0x7f, 0x02, 0x03, 0x01, 0x00, 0x01,
0xa3, 0x82, 0x01, 0x39, 0x30, 0x82, 0x01, 0x35, 0x30, 0x0c, 0x06, 0x03,
0x55, 0x1d, 0x13, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1d,
0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x83, 0xc6, 0x3a,
0x89, 0x2c, 0x81, 0xf4, 0x02, 0xd7, 0x9d, 0x4c, 0xe2, 0x2a, 0xc0, 0x71,
0x82, 0x64, 0x44, 0xda, 0x0e, 0x30, 0x81, 0xc4, 0x06, 0x03, 0x55, 0x1d,
0x23, 0x04, 0x81, 0xbc, 0x30, 0x81, 0xb9, 0x80, 0x14, 0x73, 0xb0, 0x1c,
0xa4, 0x2f, 0x82, 0xcb, 0xcf, 0x47, 0xa5, 0x38, 0xd7, 0xb0, 0x04, 0x82,
0x3a, 0x7e, 0x72, 0x15, 0x21, 0xa1, 0x81, 0x9d, 0xa4, 0x81, 0x9a, 0x30,
0x81, 0x97, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08,
0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e,
0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x07, 0x53,
0x65, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03,
0x55, 0x04, 0x0a, 0x0c, 0x07, 0x77, 0x6f, 0x6c, 0x66, 0x53, 0x53, 0x4c,
0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x0b, 0x45,
0x6e, 0x67, 0x69, 0x6e, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x31, 0x18,
0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0f, 0x77, 0x6f, 0x6c,
0x66, 0x53, 0x53, 0x4c, 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41,
0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6e, 0x66, 0x6f, 0x40, 0x77, 0x6f,
0x6c, 0x66, 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x82, 0x01, 0x63,
0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x01,
0x06, 0x30, 0x32, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01,
0x01, 0x04, 0x26, 0x30, 0x24, 0x30, 0x22, 0x06, 0x08, 0x2b, 0x06, 0x01,
0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x16, 0x68, 0x74, 0x74, 0x70, 0x3a,
0x2f, 0x2f, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x3a,
0x32, 0x32, 0x32, 0x32, 0x30, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01,
0x00, 0x77, 0xec, 0x89, 0x37, 0xd4, 0x35, 0x2e, 0x24, 0xfd, 0xd2, 0xde,
0xd9, 0x98, 0x87, 0xbe, 0x52, 0xae, 0xb5, 0xd4, 0xf6, 0x13, 0x34, 0x12,
0x2c, 0xf0, 0x78, 0x98, 0x07, 0x9f, 0xf7, 0xe4, 0x76, 0xdf, 0x6e, 0xeb,
0x97, 0xc7, 0x03, 0xa3, 0xe6, 0x15, 0x6e, 0xe2, 0x94, 0x16, 0x6b, 0xed,
0x59, 0xa9, 0x4a, 0x10, 0xa0, 0xcc, 0xc2, 0x61, 0x78, 0xc7, 0xfb, 0x1c,
0x04, 0x4a, 0x20, 0xc1, 0xfc, 0x94, 0xc6, 0x99, 0xb0, 0x3a, 0x8c, 0x2f,
0x2b, 0x7d, 0x15, 0x30, 0x53, 0xc7, 0x9b, 0x73, 0x54, 0x6f, 0x4d, 0x16,
0xa6, 0xab, 0x2d, 0x8a, 0x51, 0x70, 0x1f, 0x1b, 0x8e, 0x60, 0x0b, 0x56,
0x8b, 0xf2, 0x94, 0x01, 0xfd, 0x81, 0x5f, 0x73, 0xcb, 0xed, 0x5e, 0xcc,
0x4a, 0x71, 0xc1, 0xa9, 0x1a, 0xd7, 0xc7, 0x2b, 0x5a, 0x66, 0x02, 0x77,
0xda, 0x10, 0xe8, 0x45, 0x42, 0xa0, 0x7c, 0xef, 0x78, 0xff, 0xdd, 0x08,
0xf6, 0x84, 0x2f, 0x41, 0xf5, 0x18, 0xc9, 0xa2, 0x48, 0xd1, 0x5d, 0xb6,
0xa4, 0x4d, 0x32, 0xaf, 0x83, 0x5d, 0xb9, 0x64, 0xec, 0x40, 0xe9, 0x62,
0x38, 0xef, 0x1b, 0xd1, 0x8e, 0xc9, 0xe8, 0xfd, 0xb3, 0xe8, 0xe1, 0xa1,
0xda, 0x16, 0x1e, 0x26, 0x3c, 0x82, 0x36, 0xcb, 0x8d, 0x80, 0x67, 0x33,
0xca, 0x30, 0xbf, 0x93, 0x03, 0xc8, 0x9c, 0xbe, 0xa2, 0x6f, 0xaa, 0x7c,
0x76, 0x24, 0x3d, 0x06, 0x99, 0xab, 0xa7, 0xfe, 0x12, 0xf3, 0xdb, 0xfd,
0xa0, 0x8a, 0xb5, 0x0d, 0xc1, 0x9c, 0x90, 0xb7, 0xca, 0x7e, 0x6d, 0xfb,
0xff, 0x2a, 0xc3, 0xfe, 0x7c, 0x9f, 0x41, 0xe8, 0xc2, 0x7f, 0x4f, 0xfa,
0x4b, 0x49, 0xc4, 0xa0, 0xd0, 0xbc, 0xfd, 0x38, 0x34, 0x22, 0xff, 0xd5,
0x83, 0x79, 0x70, 0x7f, 0x6c, 0x30, 0x8d, 0xad, 0x93, 0xfb, 0xb8, 0x77,
0x01, 0x34, 0xaf, 0xcc, 0x0e
};
OcspEntry entry[1];
CertStatus status[1];
@@ -3227,7 +3152,7 @@ int test_wolfSSL_CertManagerCheckOCSPResponse(void)
/* Flip a byte in the request serial number, response should be invalid
* now. */
if ((request != NULL) && (request->serial != NULL))
request->serial[0] ^= request->serial[0];
request->serial[0] ^= 0xFF;
ExpectIntNE(wolfSSL_CertManagerCheckOCSPResponse(cm, (byte *)response,
sizeof(response), NULL, status, entry, request), WOLFSSL_SUCCESS);
@@ -3508,7 +3433,7 @@ int test_wolfSSL_CertManagerRejectMD5Cert(void)
#if !defined(NO_CERTS) && !defined(NO_RSA) && !defined(NO_MD5) && \
!defined(WOLFSSL_ALLOW_MD5_CERT_SIGS) && defined(WOLFSSL_CERT_GEN) && \
!defined(NO_WOLFSSL_CM_VERIFY) && !defined(NO_ASN_CRYPT) && \
!defined(USE_CERT_BUFFERS_1024)
!defined(USE_CERT_BUFFERS_1024) && !defined(NO_ASN_TIME)
WOLFSSL_CERT_MANAGER* cm = NULL;
RsaKey caKey;
WC_RNG rng;
+61
View File
@@ -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
*/
+7 -5
View File
@@ -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 */
+143
View File
@@ -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();
}
+4 -2
View File
@@ -25,8 +25,10 @@
#include <tests/api/api_decl.h>
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 */
+839 -3
View File
@@ -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();
}
+49 -2
View File
@@ -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 */
+4
View File
@@ -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();
}
+4
View File
@@ -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();
}
+44
View File
@@ -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));
+6 -3
View File
@@ -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;
+592 -270
View File
@@ -30,6 +30,9 @@
#include <wolfssl/ssl.h>
#include <wolfssl/wolfcrypt/asn.h>
#ifdef HAVE_ECC
#include <wolfssl/wolfcrypt/ecc.h>
#endif
#include <tests/api/api.h>
#include <tests/utils.h>
#include <tests/api/test_lms_xmss.h>
@@ -230,11 +233,14 @@ int test_wc_LmsKey_reload_cache(void)
* standard ISARA OIDs and wraps the raw RFC 8391 pub key in an OCTET
* STRING, so the fixtures were produced with a small generator that
* overrides the AlgorithmIdentifier and SPKI to match RFC 9802. */
#if (defined(WOLFSSL_HAVE_LMS) || defined(WOLFSSL_HAVE_XMSS)) && \
!defined(NO_FILESYSTEM) && !defined(NO_CERTS)
/* Sanity bound on a test fixture cert. The largest BC-generated
* fixture we ship (XMSS^MT 40/8) is ~19 KiB; 1 MiB is well above
* any realistic RFC 9802 cert and catches a wild XFTELL. Typed as
/* Only the LMS interop-anchor verification still loads a committed fixture
* (bc_lms_native_bc_root.der); everything else is generated in-process. Gate
* these file helpers on exactly that call site to avoid an unused-function
* warning in XMSS-only or truncated-hash builds. */
#if defined(WOLFSSL_HAVE_LMS) && !defined(NO_FILESYSTEM) && \
!defined(NO_CERTS) && !defined(WOLFSSL_NO_LMS_SHA256_256)
/* Sanity bound on a test fixture cert. 1 MiB is well above any realistic
* RFC 9802 cert and catches a wild XFTELL. Typed as
* long to match XFTELL's return so the size comparison below isn't
* a mixed long-vs-int compare. */
#define RFC9802_TEST_MAX_CERT_SIZE ((long)(1L << 20))
@@ -288,8 +294,8 @@ static int rfc9802_load_file(const char* path, byte** out, int* outLen)
return EXPECT_RESULT();
}
static int rfc9802_verify_one_cert(const char* path, word32 expectedKeyOID,
word32 expectedSigOID)
static WC_MAYBE_UNUSED int rfc9802_verify_one_cert(const char* path,
word32 expectedKeyOID, word32 expectedSigOID)
{
EXPECT_DECLS;
byte* buf = NULL;
@@ -512,6 +518,7 @@ static int rfc9802_xmss_import_negative(void)
wc_XmssKey_Free(&key);
}
#if !defined(WOLFSSL_XMSS_MIN_HEIGHT) || (WOLFSSL_XMSS_MIN_HEIGHT <= 10)
/* Once params have been configured (state != INITED), the OID
* prefix in the raw key MUST match key->oid and is_xmssmt MUST
* match key->is_xmssmt. Set XMSS-SHA2_10_256 and feed a valid-
@@ -561,10 +568,12 @@ static int rfc9802_xmss_import_negative(void)
ExpectIntEQ((int)key.is_xmssmt, 0);
wc_XmssKey_Free(&key);
#if WOLFSSL_XMSS_MAX_HEIGHT >= 20
ExpectIntEQ(wc_XmssKey_Init(&key, NULL, INVALID_DEVID), 0);
ExpectIntEQ(wc_XmssKey_ImportPubRaw_ex(&key, buf, sizeof(buf), 1), 0);
ExpectIntEQ((int)key.is_xmssmt, 1);
wc_XmssKey_Free(&key);
#endif
}
/* Lenient state: re-importing the same pub key into a VERIFYONLY
@@ -635,222 +644,38 @@ static int rfc9802_xmss_import_negative(void)
WC_NO_ERR_TRACE(BAD_STATE_E));
wc_XmssKey_Free(&key);
}
#endif
return EXPECT_RESULT();
}
#endif
/* Walk the AlgorithmIdentifier SEQUENCE that begins at sigIndex and
* locate the byte offset of the last byte of its OID content. Handles
* both short-form (length < 128) and long-form DER length encodings,
* so a future fixture-regenerator that emits longer OIDs / SEQUENCEs
* still drives this test rather than tripping the loud-fail branch.
*
* Returns 0 on success with *oidLastByte set; returns -1 on any DER
* shape mismatch. */
#if defined(WOLFSSL_HAVE_XMSS) && !defined(NO_FILESYSTEM) && !defined(NO_CERTS)
static int rfc9802_find_sig_alg_oid_last_byte(const byte* buf, word32 bufLen,
word32 sigIndex, word32* oidLastByte)
/* Collect the byte offset of the final sub-identifier of every
* 1.3.6.1.5.5.7.6.<lastByte> 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 <lastByte>. */
static const byte pfx[] = { 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x06 };
int n = 0;
word32 i;
/* AlgorithmIdentifier ::= SEQUENCE { algorithm OID, ... } */
if (idx >= bufLen || buf[idx] != 0x30)
return -1;
idx++;
/* Skip SEQUENCE length (short or long form). */
if (idx >= bufLen)
return -1;
if (buf[idx] < 0x80) {
idx++;
}
else {
word32 nbytes = (word32)(buf[idx] & 0x7F);
if (nbytes == 0 || nbytes > 4 || idx + 1 + nbytes > bufLen)
return -1;
idx += 1 + nbytes;
}
/* algorithm OID tag. */
if (idx >= bufLen || buf[idx] != 0x06)
return -1;
idx++;
/* OID length (short or long form). */
if (idx >= bufLen)
return -1;
if (buf[idx] < 0x80) {
oidContentLen = buf[idx];
idx++;
}
else {
word32 nbytes = (word32)(buf[idx] & 0x7F);
word32 i;
if (nbytes == 0 || nbytes > 4 || idx + 1 + nbytes > bufLen)
return -1;
for (i = 0; i < nbytes; i++)
oidContentLen = (oidContentLen << 8) | buf[idx + 1 + i];
idx += 1 + nbytes;
}
if (oidContentLen == 0 || idx + oidContentLen > bufLen)
return -1;
*oidLastByte = idx + oidContentLen - 1;
return 0;
}
/* Helper: load fixture, locate last byte of outer signatureAlgorithm
* OID, patch it from `expected` to `swap`, and assert that verifying
* the patched cert against itself as a trust anchor fails. */
static int rfc9802_assert_oid_patch_breaks_verify(const char* path,
byte expectedLastByte, byte patchedLastByte)
{
EXPECT_DECLS;
byte* buf = NULL;
int bytes = 0;
DecodedCert cert;
WOLFSSL_CERT_MANAGER* cm = NULL;
word32 sigIndex = 0;
word32 lastOidByte = 0;
ExpectIntEQ(rfc9802_load_file(path, &buf, &bytes), TEST_SUCCESS);
if (buf == NULL)
return TEST_FAIL;
wc_InitDecodedCert(&cert, buf, (word32)bytes, NULL);
ExpectIntEQ(wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL), 0);
sigIndex = cert.sigIndex;
wc_FreeDecodedCert(&cert);
ExpectIntEQ(rfc9802_find_sig_alg_oid_last_byte(buf, (word32)bytes,
sigIndex, &lastOidByte), 0);
/* Sanity-check the fixture matches the family the caller asserted,
* so a future regenerator swapping fixtures fails loudly here
* rather than silently testing the wrong direction. */
ExpectIntEQ((int)buf[lastOidByte], (int)expectedLastByte);
if (lastOidByte < (word32)bytes &&
buf[lastOidByte] == expectedLastByte) {
buf[lastOidByte] = patchedLastByte;
ExpectNotNull(cm = wolfSSL_CertManagerNew());
/* After the patch the cert's outer signatureAlgorithm and SPKI
* disagree. Verification must fail somewhere (at parse, at
* load, or at ConfirmSignature). The load is best-effort -
* some shape changes get caught there, others only at verify. */
(void)wolfSSL_CertManagerLoadCABuffer(cm, buf, (long)bytes,
WOLFSSL_FILETYPE_ASN1);
ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, buf,
(long)bytes, WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
if (cm != NULL) {
wolfSSL_CertManagerFree(cm);
cm = NULL;
for (i = 0; (word32)(i + sizeof(pfx)) < derSz; i++) {
if (XMEMCMP(der + i, pfx, sizeof(pfx)) == 0 &&
der[i + sizeof(pfx)] == lastByte) {
if (n < maxOff)
offsets[n] = i + (word32)sizeof(pfx);
n++;
}
}
XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return EXPECT_RESULT();
}
/* X.509-level negative: swap the outer signatureAlgorithm OID byte so
* the cert declares XMSS where the SPKI is XMSS^MT, and vice versa.
* SigOidMatchesKeyOid must reject both directions before any crypto. */
static int rfc9802_xmss_sig_oid_mismatch(void)
{
EXPECT_DECLS;
/* XMSS sigOID ends 0x22; XMSS^MT sigOID ends 0x23. Patch each
* direction so the asymmetric-key path is exercised both ways -
* a regression that only stripped the check from one branch of
* SigOidMatchesKeyOid would otherwise be missed. */
ExpectIntEQ(rfc9802_assert_oid_patch_breaks_verify(
"./certs/xmss/bc_xmss_sha2_10_256_root.der",
/* expected XMSS */ 0x22, /* patched to XMSS^MT */ 0x23),
TEST_SUCCESS);
ExpectIntEQ(rfc9802_assert_oid_patch_breaks_verify(
"./certs/xmss/bc_xmssmt_sha2_20_2_256_root.der",
/* expected XMSS^MT */ 0x23, /* patched to XMSS */ 0x22),
TEST_SUCCESS);
return EXPECT_RESULT();
}
#endif
/* Exercise a real CA -> leaf certificate chain, not just self-signed.
* Loads the CA as a trust anchor and verifies the leaf against it. */
#if defined(WOLFSSL_HAVE_LMS) && !defined(NO_FILESYSTEM) && !defined(NO_CERTS)
static int rfc9802_lms_chain_verify(void)
{
EXPECT_DECLS;
byte* caBuf = NULL;
byte* leafBuf = NULL;
int caLen = 0;
int leafLen = 0;
WOLFSSL_CERT_MANAGER* cm = NULL;
ExpectIntEQ(rfc9802_load_file("./certs/lms/bc_lms_chain_ca.der",
&caBuf, &caLen), TEST_SUCCESS);
ExpectIntEQ(rfc9802_load_file("./certs/lms/bc_lms_chain_leaf.der",
&leafBuf, &leafLen), TEST_SUCCESS);
ExpectNotNull(cm = wolfSSL_CertManagerNew());
/* Only the CA is a trust anchor; the leaf is verified against it. */
ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, caBuf, (long)caLen,
WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_CertManagerVerifyBuffer(cm, leafBuf, (long)leafLen,
WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
/* Without loading the CA the leaf must NOT verify. */
if (cm != NULL) {
wolfSSL_CertManagerFree(cm);
cm = NULL;
}
ExpectNotNull(cm = wolfSSL_CertManagerNew());
ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, leafBuf, (long)leafLen,
WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
if (cm != NULL) {
wolfSSL_CertManagerFree(cm);
cm = NULL;
}
XFREE(leafBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(caBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return EXPECT_RESULT();
}
#endif
/* Mirror of rfc9802_lms_chain_verify but for an XMSS CA -> leaf pair. */
#if defined(WOLFSSL_HAVE_XMSS) && !defined(NO_FILESYSTEM) && !defined(NO_CERTS)
static int rfc9802_xmss_chain_verify(void)
{
EXPECT_DECLS;
byte* caBuf = NULL;
byte* leafBuf = NULL;
int caLen = 0;
int leafLen = 0;
WOLFSSL_CERT_MANAGER* cm = NULL;
ExpectIntEQ(rfc9802_load_file("./certs/xmss/bc_xmss_chain_ca.der",
&caBuf, &caLen), TEST_SUCCESS);
ExpectIntEQ(rfc9802_load_file("./certs/xmss/bc_xmss_chain_leaf.der",
&leafBuf, &leafLen), TEST_SUCCESS);
ExpectNotNull(cm = wolfSSL_CertManagerNew());
ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, caBuf, (long)caLen,
WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_CertManagerVerifyBuffer(cm, leafBuf, (long)leafLen,
WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
if (cm != NULL) {
wolfSSL_CertManagerFree(cm);
cm = NULL;
}
ExpectNotNull(cm = wolfSSL_CertManagerNew());
ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, leafBuf, (long)leafLen,
WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
if (cm != NULL) {
wolfSSL_CertManagerFree(cm);
cm = NULL;
}
XFREE(leafBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(caBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return EXPECT_RESULT();
return n;
}
#endif
@@ -860,38 +685,15 @@ int test_rfc9802_lms_x509_verify(void)
#if defined(WOLFSSL_HAVE_LMS)
#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && \
!defined(WOLFSSL_NO_LMS_SHA256_256)
/* Mixed single-level LMS and multi-level HSS fixtures. The HSS
* public key carries only the top-level LMS/LM-OTS types, so
* wc_LmsKey_ImportPubRaw's auto-derive path searches the map
* by (levels, lmsType, lmOtsType). The bc_lms_native_bc_root
* fixture is generated through Bouncy Castle's stock
* JcaContentSignerBuilder("LMS") + JcaX509v3CertificateBuilder
* with no overrides; including it here is the cross-impl interop
* gate (BC's native LMS X.509 path is RFC 9802-compliant for HSS/
* LMS, so wolfSSL must accept it end-to-end).
*
* All fixtures use the SHA-256/M32 family, so the whole block
* is gated on that family being compiled in. Truncated SHA-256/192
* or SHAKE-only builds skip this block. */
static const char* const lmsFiles[] = {
"./certs/lms/bc_lms_sha256_h5_w4_root.der",
#if !defined(WOLFSSL_LMS_MAX_HEIGHT) || (WOLFSSL_LMS_MAX_HEIGHT >= 10)
"./certs/lms/bc_lms_sha256_h10_w8_root.der",
#endif
#if !defined(WOLFSSL_LMS_MAX_LEVELS) || (WOLFSSL_LMS_MAX_LEVELS >= 2)
"./certs/lms/bc_hss_L2_H5_W8_root.der",
#endif
#if !defined(WOLFSSL_LMS_MAX_LEVELS) || (WOLFSSL_LMS_MAX_LEVELS >= 3)
"./certs/lms/bc_hss_L3_H5_W4_root.der",
#endif
"./certs/lms/bc_lms_native_bc_root.der",
};
size_t i;
for (i = 0; i < sizeof(lmsFiles) / sizeof(lmsFiles[0]); i++) {
ExpectIntEQ(rfc9802_verify_one_cert(lmsFiles[i],
HSS_LMSk, CTC_HSS_LMS), TEST_SUCCESS);
}
ExpectIntEQ(rfc9802_lms_chain_verify(), TEST_SUCCESS);
/* Cross-implementation interop gate. bc_lms_native_bc_root.der is
* generated through Bouncy Castle's stock JcaContentSignerBuilder("LMS")
* + JcaX509v3CertificateBuilder with no overrides; BC's native LMS X.509
* path is RFC 9802-compliant for HSS/LMS, so wolfSSL must accept it
* end-to-end. This is the one fixture from an independent implementation
* that we keep; wolfSSL's own generation is exercised by
* test_rfc9802_lms_x509_gen instead of committed wolfSSL fixtures. */
ExpectIntEQ(rfc9802_verify_one_cert("./certs/lms/bc_lms_native_bc_root.der",
HSS_LMSk, CTC_HSS_LMS), TEST_SUCCESS);
#endif /* !NO_FILESYSTEM && !NO_CERTS && !WOLFSSL_NO_LMS_SHA256_256 */
/* Pure wolfCrypt-level negative tests don't need filesystem or cert
* support, so they run for any LMS-enabled build. */
@@ -904,31 +706,551 @@ int test_rfc9802_xmss_x509_verify(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_HAVE_XMSS)
#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS)
static const char* const xmssFiles[] = {
"./certs/xmss/bc_xmss_sha2_10_256_root.der",
"./certs/xmss/bc_xmss_sha2_16_256_root.der",
};
static const char* const xmssmtFiles[] = {
"./certs/xmss/bc_xmssmt_sha2_20_2_256_root.der",
"./certs/xmss/bc_xmssmt_sha2_20_4_256_root.der",
"./certs/xmss/bc_xmssmt_sha2_40_8_256_root.der",
};
size_t i;
for (i = 0; i < sizeof(xmssFiles) / sizeof(xmssFiles[0]); i++) {
ExpectIntEQ(rfc9802_verify_one_cert(xmssFiles[i],
XMSSk, CTC_XMSS), TEST_SUCCESS);
}
for (i = 0; i < sizeof(xmssmtFiles) / sizeof(xmssmtFiles[0]); i++) {
ExpectIntEQ(rfc9802_verify_one_cert(xmssmtFiles[i],
XMSSMTk, CTC_XMSSMT), TEST_SUCCESS);
}
ExpectIntEQ(rfc9802_xmss_sig_oid_mismatch(), TEST_SUCCESS);
ExpectIntEQ(rfc9802_xmss_chain_verify(), TEST_SUCCESS);
#endif /* !NO_FILESYSTEM && !NO_CERTS */
/* Pure wolfCrypt-level negative tests don't need filesystem or cert
* support, so they run for any XMSS-enabled build. */
/* No independent (RFC 9802-aligned) third-party XMSS X.509 implementation
* exists to interop against - OpenSSL has no XMSS cert signing and Bouncy
* Castle's XMSS encoding is not yet aligned with the final RFC - so there
* is no committed interop fixture here. wolfSSL's own XMSS/XMSS^MT cert
* generation, chain signing and the X.509-level signatureAlgorithm/SPKI
* mismatch rejection are exercised in test_rfc9802_xmss_x509_gen.
*
* Pure wolfCrypt-level negative tests run for any XMSS-enabled build. */
ExpectIntEQ(rfc9802_xmss_import_negative(), TEST_SUCCESS);
#endif
return EXPECT_RESULT();
}
/* RFC 9802 certificate/CSR GENERATION tests.
*
* These exercise the cert-gen path (wc_MakeCert_ex / wc_SignCert_ex and
* wc_MakeCertReq_ex) with a freshly generated LMS or XMSS key, then feed
* the result back through the existing verification path to prove the
* generated SubjectPublicKeyInfo, signatureAlgorithm and signature are
* RFC 9802-compliant and self-consistent. */
/* RFC 9802 cert/CSR generation is only wired into the ASN.1 template
* implementation (the original/non-template path has no LMS/XMSS support),
* so all of these tests require WOLFSSL_ASN_TEMPLATE. */
#if defined(WOLFSSL_ASN_TEMPLATE) && defined(WOLFSSL_CERT_GEN) && \
!defined(NO_FILESYSTEM) && !defined(NO_CERTS) && \
((defined(WOLFSSL_HAVE_LMS) && !defined(WOLFSSL_LMS_VERIFY_ONLY)) || \
(defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY)))
/* Populate a minimal self-consistent subject/issuer name. */
static void rfc9802_gen_set_names(Cert* cert)
{
XSTRNCPY(cert->subject.country, "US", CTC_NAME_SIZE);
XSTRNCPY(cert->subject.state, "OR", CTC_NAME_SIZE);
XSTRNCPY(cert->subject.locality, "Portland", CTC_NAME_SIZE);
XSTRNCPY(cert->subject.org, "wolfSSL", CTC_NAME_SIZE);
XSTRNCPY(cert->subject.unit, "Testing", CTC_NAME_SIZE);
XSTRNCPY(cert->subject.commonName, "RFC9802 Gen Root CA", CTC_NAME_SIZE);
}
/* Verify a self-signed DER cert by loading it as its own CA. */
static int rfc9802_gen_verify_selfsigned(const byte* der, int derSz)
{
EXPECT_DECLS;
WOLFSSL_CERT_MANAGER* cm = NULL;
ExpectNotNull(cm = wolfSSL_CertManagerNew());
ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, der, (long)derSz,
WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_CertManagerVerifyBuffer(cm, der, (long)derSz,
WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
if (cm != NULL)
wolfSSL_CertManagerFree(cm);
return EXPECT_RESULT();
}
#ifdef WOLFSSL_CERT_REQ
/* Parse a generated CSR and confirm its proof-of-possession signature. */
static int rfc9802_gen_verify_csr(const byte* der, int derSz)
{
EXPECT_DECLS;
DecodedCert dc;
wc_InitDecodedCert(&dc, der, (word32)derSz, NULL);
ExpectIntEQ(wc_ParseCert(&dc, CERTREQ_TYPE, VERIFY, NULL), 0);
wc_FreeDecodedCert(&dc);
return EXPECT_RESULT();
}
#endif /* WOLFSSL_CERT_REQ */
/* Generate a self-signed root CA (and, when CSRs are enabled, a PKCS#10
* request) for an already-made key, then feed each back through the
* verification path. keyType is the wc_MakeCert_ex/wc_SignCert_ex selector
* (LMS_TYPE / XMSS_TYPE / XMSSMT_TYPE) and sigType the matching CTC_ OID.
* key is void* to mirror the public wc_MakeCert_ex API; callers must pass a
* key object whose type matches keyType. */
static int rfc9802_gen_roundtrip(void* key, int keyType, int sigType,
WC_RNG* rng, word32 derCap)
{
EXPECT_DECLS;
byte* der = NULL;
int derSz = 0;
ExpectNotNull(der = (byte*)XMALLOC(derCap, NULL, DYNAMIC_TYPE_TMP_BUFFER));
/* Self-signed root CA: generate -> sign -> verify round trip. */
if (EXPECT_SUCCESS() && der != NULL) {
Cert cert;
ExpectIntEQ(wc_InitCert(&cert), 0);
rfc9802_gen_set_names(&cert);
cert.sigType = sigType;
cert.isCA = 1;
cert.selfSigned = 1;
cert.daysValid = 365;
ExpectIntGT(wc_MakeCert_ex(&cert, der, derCap, keyType, key, rng), 0);
ExpectIntGT(derSz = wc_SignCert_ex(cert.bodySz, cert.sigType, der,
derCap, keyType, key, rng), 0);
ExpectIntEQ(rfc9802_gen_verify_selfsigned(der, derSz), TEST_SUCCESS);
}
#ifdef WOLFSSL_CERT_REQ
/* PKCS#10 CSR: generate -> self-sign proof-of-possession -> parse. */
if (EXPECT_SUCCESS() && der != NULL) {
Cert cert;
ExpectIntEQ(wc_InitCert(&cert), 0);
rfc9802_gen_set_names(&cert);
cert.sigType = sigType;
ExpectIntGT(wc_MakeCertReq_ex(&cert, der, derCap, keyType, key), 0);
ExpectIntGT(derSz = wc_SignCert_ex(cert.bodySz, cert.sigType, der,
derCap, keyType, key, rng), 0);
ExpectIntEQ(rfc9802_gen_verify_csr(der, derSz), TEST_SUCCESS);
}
#endif /* WOLFSSL_CERT_REQ */
XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return EXPECT_RESULT();
}
/* wc_ecc_make_key is available with HAVE_ECC; HAVE_ECC_KEY_EXPORT is needed
* for the leaf SPKI and !WC_NO_RNG for key generation. */
#if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_EXPORT) && !defined(WC_NO_RNG)
/* Subject name for the generated leaf (distinct from the CA subject). */
static void rfc9802_gen_set_leaf_names(Cert* cert)
{
XSTRNCPY(cert->subject.country, "US", CTC_NAME_SIZE);
XSTRNCPY(cert->subject.state, "OR", CTC_NAME_SIZE);
XSTRNCPY(cert->subject.locality, "Portland", CTC_NAME_SIZE);
XSTRNCPY(cert->subject.org, "wolfSSL", CTC_NAME_SIZE);
XSTRNCPY(cert->subject.unit, "Testing", CTC_NAME_SIZE);
XSTRNCPY(cert->subject.commonName, "RFC9802 Gen Leaf", CTC_NAME_SIZE);
}
/* Generate a self-signed LMS/XMSS CA, then an ECC leaf issued and signed by
* that CA, and confirm the leaf chains to the CA (and fails without it). This
* is the real RFC 9802 use case - a hash-based CA signing another cert - that
* self-signed roots and CSRs don't cover. caKey is the already-made CA key;
* caKeyType/caSigType select its algorithm. */
static int rfc9802_gen_chain(void* caKey, int caKeyType, int caSigType,
WC_RNG* rng, word32 derCap)
{
EXPECT_DECLS;
ecc_key leafKey;
int leafKeyInit = 0;
byte* caDer = NULL;
byte* leafDer = NULL;
int caSz = 0;
int leafSz = 0;
WOLFSSL_CERT_MANAGER* cm = NULL;
ExpectNotNull(caDer = (byte*)XMALLOC(derCap, NULL, DYNAMIC_TYPE_TMP_BUFFER));
ExpectNotNull(leafDer = (byte*)XMALLOC(derCap, NULL,
DYNAMIC_TYPE_TMP_BUFFER));
ExpectIntEQ(wc_ecc_init(&leafKey), 0);
leafKeyInit = 1;
ExpectIntEQ(wc_ecc_make_key(rng, 32, &leafKey), 0);
/* Self-signed CA root. */
if (EXPECT_SUCCESS() && caDer != NULL) {
Cert ca;
ExpectIntEQ(wc_InitCert(&ca), 0);
rfc9802_gen_set_names(&ca);
ca.sigType = caSigType;
ca.isCA = 1;
ca.selfSigned = 1;
ca.daysValid = 365;
ExpectIntGT(wc_MakeCert_ex(&ca, caDer, derCap, caKeyType, caKey, rng),
0);
ExpectIntGT(caSz = wc_SignCert_ex(ca.bodySz, caSigType, caDer, derCap,
caKeyType, caKey, rng), 0);
}
/* ECC leaf, issued by the CA's subject and signed with the CA key. */
if (EXPECT_SUCCESS() && leafDer != NULL && caSz > 0) {
Cert leaf;
ExpectIntEQ(wc_InitCert(&leaf), 0);
rfc9802_gen_set_leaf_names(&leaf);
leaf.sigType = caSigType;
leaf.daysValid = 365;
ExpectIntEQ(wc_SetIssuerBuffer(&leaf, caDer, caSz), 0);
ExpectIntGT(wc_MakeCert_ex(&leaf, leafDer, derCap, ECC_TYPE, &leafKey,
rng), 0);
ExpectIntGT(leafSz = wc_SignCert_ex(leaf.bodySz, caSigType, leafDer,
derCap, caKeyType, caKey, rng), 0);
}
/* Leaf verifies only when the CA is the trust anchor. */
if (EXPECT_SUCCESS() && leafSz > 0) {
ExpectNotNull(cm = wolfSSL_CertManagerNew());
ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, caDer, (long)caSz,
WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_CertManagerVerifyBuffer(cm, leafDer, (long)leafSz,
WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
if (cm != NULL) {
wolfSSL_CertManagerFree(cm);
cm = NULL;
}
ExpectNotNull(cm = wolfSSL_CertManagerNew());
ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, leafDer, (long)leafSz,
WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
if (cm != NULL) {
wolfSSL_CertManagerFree(cm);
cm = NULL;
}
}
/* Negative: corrupt the leaf's signature (last byte of the DER, in the
* signatureValue) and confirm verification fails even with the CA loaded.
* This proves the CA's hash-based signature is cryptographically checked,
* not accepted on issuer-name chaining alone. */
if (EXPECT_SUCCESS() && leafSz > 0) {
byte saved = leafDer[leafSz - 1];
leafDer[leafSz - 1] ^= 0xFF;
ExpectNotNull(cm = wolfSSL_CertManagerNew());
ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, caDer, (long)caSz,
WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, leafDer, (long)leafSz,
WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
if (cm != NULL) {
wolfSSL_CertManagerFree(cm);
cm = NULL;
}
leafDer[leafSz - 1] = saved;
}
if (leafKeyInit)
wc_ecc_free(&leafKey);
XFREE(leafDer, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(caDer, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return EXPECT_RESULT();
}
#endif /* HAVE_ECC && HAVE_ECC_KEY_EXPORT */
#endif /* gen test support */
#if defined(WOLFSSL_ASN_TEMPLATE) && defined(WOLFSSL_HAVE_LMS) && \
!defined(WOLFSSL_LMS_VERIFY_ONLY) && \
defined(WOLFSSL_CERT_GEN) && !defined(NO_FILESYSTEM) && \
!defined(NO_CERTS) && !defined(WOLFSSL_NO_LMS_SHA256_256)
/* Init an LMS key with the shared persistence callbacks and given params. */
static int rfc9802_gen_lms_init(LmsKey* key, int levels, int height, int win)
{
int ret = wc_LmsKey_Init(key, NULL, INVALID_DEVID);
if (ret == 0)
ret = wc_LmsKey_SetParameters(key, levels, height, win);
if (ret == 0)
ret = wc_LmsKey_SetWriteCb(key, test_lms_write_key);
if (ret == 0)
ret = wc_LmsKey_SetReadCb(key, test_lms_read_key);
if (ret == 0)
ret = wc_LmsKey_SetContext(key, (void*)LMS_TEST_PRIV_KEY_FILE);
return ret;
}
#endif
int test_rfc9802_lms_x509_gen(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_ASN_TEMPLATE) && defined(WOLFSSL_HAVE_LMS) && \
!defined(WOLFSSL_LMS_VERIFY_ONLY) && \
defined(WOLFSSL_CERT_GEN) && !defined(NO_FILESYSTEM) && \
!defined(NO_CERTS) && !defined(WOLFSSL_NO_LMS_SHA256_256)
LmsKey key;
WC_RNG rng;
ExpectIntEQ(wc_InitRng(&rng), 0);
/* Single-level LMS (L1-H5-W8). */
remove(LMS_TEST_PRIV_KEY_FILE);
ExpectIntEQ(rfc9802_gen_lms_init(&key, 1, 5, 8), 0);
ExpectIntEQ(wc_LmsKey_MakeKey(&key, &rng), 0);
ExpectIntEQ(rfc9802_gen_roundtrip(&key, LMS_TYPE, CTC_HSS_LMS, &rng, 8192),
TEST_SUCCESS);
/* Negative: signing an LMS key with a non-LMS signature OID must be
* rejected rather than emit a cert whose signatureAlgorithm contradicts
* its public key. The check fires before any signature is produced, so
* the key's one-time signatures are not consumed. */
if (EXPECT_SUCCESS()) {
Cert cert;
byte* tmp = NULL;
ExpectNotNull(tmp = (byte*)XMALLOC(8192, NULL, DYNAMIC_TYPE_TMP_BUFFER));
ExpectIntEQ(wc_InitCert(&cert), 0);
rfc9802_gen_set_names(&cert);
cert.sigType = CTC_HSS_LMS;
cert.isCA = 1;
cert.selfSigned = 1;
cert.daysValid = 365;
if (tmp != NULL) {
ExpectIntGT(wc_MakeCert_ex(&cert, tmp, 8192, LMS_TYPE, &key,
&rng), 0);
ExpectIntEQ(wc_SignCert_ex(cert.bodySz, CTC_XMSS, tmp, 8192,
LMS_TYPE, &key, &rng), WC_NO_ERR_TRACE(ALGO_ID_E));
}
XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
#if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_EXPORT) && !defined(WC_NO_RNG)
/* Real CA use case: the LMS CA signs an ECC leaf; the leaf must chain to
* the CA. Reuses the L1 key (plenty of one-time signatures remain). */
ExpectIntEQ(rfc9802_gen_chain(&key, LMS_TYPE, CTC_HSS_LMS, &rng, 8192),
TEST_SUCCESS);
#endif
wc_LmsKey_Free(&key);
remove(LMS_TEST_PRIV_KEY_FILE);
#if !defined(WOLFSSL_LMS_MAX_LEVELS) || (WOLFSSL_LMS_MAX_LEVELS >= 2)
/* Multi-level HSS (L2-H5-W8): the signature embeds a lower-level LMS
* public key + signature, exercising the larger, multi-level encoding. */
remove(LMS_TEST_PRIV_KEY_FILE);
ExpectIntEQ(rfc9802_gen_lms_init(&key, 2, 5, 8), 0);
ExpectIntEQ(wc_LmsKey_MakeKey(&key, &rng), 0);
ExpectIntEQ(rfc9802_gen_roundtrip(&key, LMS_TYPE, CTC_HSS_LMS, &rng, 8192),
TEST_SUCCESS);
wc_LmsKey_Free(&key);
remove(LMS_TEST_PRIV_KEY_FILE);
#endif
#if !defined(WOLFSSL_LMS_MAX_LEVELS) || (WOLFSSL_LMS_MAX_LEVELS >= 3)
/* Three-level HSS with Winternitz 4 (L3-H5-W4): exercises the deepest
* multi-level encoding and a different Winternitz parameter than the
* W8 cases above. */
remove(LMS_TEST_PRIV_KEY_FILE);
ExpectIntEQ(rfc9802_gen_lms_init(&key, 3, 5, 4), 0);
ExpectIntEQ(wc_LmsKey_MakeKey(&key, &rng), 0);
ExpectIntEQ(rfc9802_gen_roundtrip(&key, LMS_TYPE, CTC_HSS_LMS, &rng, 8192),
TEST_SUCCESS);
wc_LmsKey_Free(&key);
remove(LMS_TEST_PRIV_KEY_FILE);
#endif
wc_FreeRng(&rng);
#endif
return EXPECT_RESULT();
}
#if defined(WOLFSSL_ASN_TEMPLATE) && defined(WOLFSSL_HAVE_XMSS) && \
!defined(WOLFSSL_XMSS_VERIFY_ONLY) && \
defined(WOLFSSL_CERT_GEN) && !defined(NO_FILESYSTEM) && !defined(NO_CERTS)
#define XMSS_GEN_TEST_PRIV_KEY_FILE "/tmp/wolfssl_test_xmss_gen.key"
static enum wc_XmssRc xmss_gen_write_key(const byte* priv, word32 privSz,
void* context)
{
XFILE f = XFOPEN((const char*)context, "wb");
enum wc_XmssRc ret = WC_XMSS_RC_SAVED_TO_NV_MEMORY;
if (f == XBADFILE)
return WC_XMSS_RC_WRITE_FAIL;
if (XFWRITE(priv, 1, privSz, f) != privSz)
ret = WC_XMSS_RC_WRITE_FAIL;
XFCLOSE(f);
return ret;
}
static enum wc_XmssRc xmss_gen_read_key(byte* priv, word32 privSz,
void* context)
{
XFILE f = XFOPEN((const char*)context, "rb");
enum wc_XmssRc ret = WC_XMSS_RC_READ_TO_MEMORY;
if (f == XBADFILE)
return WC_XMSS_RC_READ_FAIL;
if (XFREAD(priv, 1, privSz, f) != privSz)
ret = WC_XMSS_RC_READ_FAIL;
XFCLOSE(f);
return ret;
}
/* Init an XMSS/XMSS^MT key with the shared persistence callbacks. */
static int rfc9802_gen_xmss_init(XmssKey* key, const char* paramStr)
{
int ret = wc_XmssKey_Init(key, NULL, INVALID_DEVID);
if (ret == 0)
ret = wc_XmssKey_SetParamStr(key, paramStr);
if (ret == 0)
ret = wc_XmssKey_SetWriteCb(key, xmss_gen_write_key);
if (ret == 0)
ret = wc_XmssKey_SetReadCb(key, xmss_gen_read_key);
if (ret == 0)
ret = wc_XmssKey_SetContext(key, (void*)XMSS_GEN_TEST_PRIV_KEY_FILE);
return ret;
}
/* X.509-level negative tests on a wolfSSL-generated XMSS/XMSS^MT cert, run
* against the already-made key (no extra keygen). oidLast is the cert's true
* final OID byte (XMSS 0x22, XMSS^MT 0x23) and oidSwap the other family's:
*
* (a) flip only the outer signatureAlgorithm OID -> it no longer equals the
* TBS signatureAlgorithm, which the generic X.509 algId-consistency check
* rejects (ASN_SIG_OID_E at parse);
* (b) flip both signatureAlgorithm copies (TBS + outer) but leave the SPKI
* key OID -> outer == TBS (that check passes), yet the signature
* algorithm now disagrees with the public-key algorithm, which RFC 9802
* requires verification to reject (SigOidMatchesKeyOid, before the - now
* also invalid - signature is even checked).
*
* Either way verification must fail. */
static int rfc9802_gen_xmss_oid_tamper(void* key, int keyType, int sigType,
WC_RNG* rng, byte oidLast, byte oidSwap)
{
EXPECT_DECLS;
byte* der = NULL;
int derSz = 0;
word32 off[8];
int n = 0;
WOLFSSL_CERT_MANAGER* cm = NULL;
ExpectNotNull(der = (byte*)XMALLOC(16384, NULL, DYNAMIC_TYPE_TMP_BUFFER));
if (EXPECT_SUCCESS() && der != NULL) {
Cert cert;
ExpectIntEQ(wc_InitCert(&cert), 0);
rfc9802_gen_set_names(&cert);
cert.sigType = sigType;
cert.isCA = 1;
cert.selfSigned = 1;
cert.daysValid = 365;
ExpectIntGT(wc_MakeCert_ex(&cert, der, 16384, keyType, key, rng), 0);
ExpectIntGT(derSz = wc_SignCert_ex(cert.bodySz, sigType, der, 16384,
keyType, key, rng), 0);
}
if (EXPECT_SUCCESS() && derSz > 0) {
n = rfc9802_collect_hbs_oid_offsets(der, (word32)derSz, oidLast, off, 8);
/* TBS-signature, SPKI-key, outer-signature - in that order. */
ExpectIntEQ(n, 3);
}
/* (a) Outer signatureAlgorithm != TBS signatureAlgorithm. */
if (EXPECT_SUCCESS() && n == 3) {
der[off[2]] = oidSwap;
ExpectNotNull(cm = wolfSSL_CertManagerNew());
(void)wolfSSL_CertManagerLoadCABuffer(cm, der, (long)derSz,
WOLFSSL_FILETYPE_ASN1);
ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, der, (long)derSz,
WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
if (cm != NULL) {
wolfSSL_CertManagerFree(cm);
cm = NULL;
}
der[off[2]] = oidLast; /* restore */
}
/* (b) signatureAlgorithm (both copies) disagrees with the SPKI key OID. */
if (EXPECT_SUCCESS() && n == 3) {
der[off[0]] = oidSwap;
der[off[2]] = oidSwap;
ExpectNotNull(cm = wolfSSL_CertManagerNew());
(void)wolfSSL_CertManagerLoadCABuffer(cm, der, (long)derSz,
WOLFSSL_FILETYPE_ASN1);
ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, der, (long)derSz,
WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
if (cm != NULL) {
wolfSSL_CertManagerFree(cm);
cm = NULL;
}
}
XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return EXPECT_RESULT();
}
#endif /* XMSS gen support */
int test_rfc9802_xmss_x509_gen(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_ASN_TEMPLATE) && defined(WOLFSSL_HAVE_XMSS) && \
!defined(WOLFSSL_XMSS_VERIFY_ONLY) && \
defined(WOLFSSL_CERT_GEN) && !defined(NO_FILESYSTEM) && !defined(NO_CERTS)
XmssKey key;
WC_RNG rng;
ExpectIntEQ(wc_InitRng(&rng), 0);
/* Single-tree XMSS. */
remove(XMSS_GEN_TEST_PRIV_KEY_FILE);
ExpectIntEQ(rfc9802_gen_xmss_init(&key, "XMSS-SHA2_10_256"), 0);
ExpectIntEQ(wc_XmssKey_MakeKey(&key, &rng), 0);
ExpectIntEQ((int)key.is_xmssmt, 0);
ExpectIntEQ(rfc9802_gen_roundtrip(&key, XMSS_TYPE, CTC_XMSS, &rng, 16384),
TEST_SUCCESS);
/* Negative: the XMSSMT_TYPE selector must not be accepted for a
* single-tree XMSS key, and signing a single-tree key as XMSS^MT must be
* rejected. Both checks fire before signing, so no signature is used. */
if (EXPECT_SUCCESS()) {
Cert cert;
byte* tmp = NULL;
ExpectNotNull(tmp = (byte*)XMALLOC(16384, NULL,
DYNAMIC_TYPE_TMP_BUFFER));
ExpectIntEQ(wc_InitCert(&cert), 0);
rfc9802_gen_set_names(&cert);
cert.sigType = CTC_XMSS;
cert.isCA = 1;
cert.selfSigned = 1;
cert.daysValid = 365;
/* Wrong selector for the key's tree variant. */
if (tmp != NULL) {
ExpectIntEQ(wc_MakeCert_ex(&cert, tmp, 16384, XMSSMT_TYPE, &key,
&rng), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* Correct selector, but signed with the XMSS^MT OID. */
ExpectIntGT(wc_MakeCert_ex(&cert, tmp, 16384, XMSS_TYPE, &key,
&rng), 0);
ExpectIntEQ(wc_SignCert_ex(cert.bodySz, CTC_XMSSMT, tmp, 16384,
XMSS_TYPE, &key, &rng), WC_NO_ERR_TRACE(ALGO_ID_E));
}
XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
#if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_EXPORT) && !defined(WC_NO_RNG)
/* Real CA use case: the XMSS CA signs an ECC leaf; the leaf must chain. */
ExpectIntEQ(rfc9802_gen_chain(&key, XMSS_TYPE, CTC_XMSS, &rng, 16384),
TEST_SUCCESS);
#endif
/* X.509-level signatureAlgorithm/SPKI OID consistency, reusing this key. */
ExpectIntEQ(rfc9802_gen_xmss_oid_tamper(&key, XMSS_TYPE, CTC_XMSS, &rng,
/* XMSS */ 0x22, /* swap */ 0x23), TEST_SUCCESS);
wc_XmssKey_Free(&key);
remove(XMSS_GEN_TEST_PRIV_KEY_FILE);
/* Multi-tree XMSS^MT: exercises the XMSSMT_TYPE selector, the
* XMSSMTk public-key OID branch and the CTC_XMSSMT signature OID. */
remove(XMSS_GEN_TEST_PRIV_KEY_FILE);
ExpectIntEQ(rfc9802_gen_xmss_init(&key, "XMSSMT-SHA2_20/2_256"), 0);
ExpectIntEQ(wc_XmssKey_MakeKey(&key, &rng), 0);
ExpectIntEQ((int)key.is_xmssmt, 1);
ExpectIntEQ(rfc9802_gen_roundtrip(&key, XMSSMT_TYPE, CTC_XMSSMT, &rng,
16384), TEST_SUCCESS);
#if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_EXPORT) && !defined(WC_NO_RNG)
ExpectIntEQ(rfc9802_gen_chain(&key, XMSSMT_TYPE, CTC_XMSSMT, &rng, 16384),
TEST_SUCCESS);
#endif
ExpectIntEQ(rfc9802_gen_xmss_oid_tamper(&key, XMSSMT_TYPE, CTC_XMSSMT, &rng,
/* XMSS^MT */ 0x23, /* swap */ 0x22), TEST_SUCCESS);
wc_XmssKey_Free(&key);
remove(XMSS_GEN_TEST_PRIV_KEY_FILE);
/* A second XMSS^MT parameter set (different embedded param-set OID and a
* larger signature) to keep the encoder/auto-derive decoder exercised
* across sizes now that the committed multi-size fixtures are gone. */
remove(XMSS_GEN_TEST_PRIV_KEY_FILE);
ExpectIntEQ(rfc9802_gen_xmss_init(&key, "XMSSMT-SHA2_20/4_256"), 0);
ExpectIntEQ(wc_XmssKey_MakeKey(&key, &rng), 0);
ExpectIntEQ((int)key.is_xmssmt, 1);
ExpectIntEQ(rfc9802_gen_roundtrip(&key, XMSSMT_TYPE, CTC_XMSSMT, &rng,
16384), TEST_SUCCESS);
wc_XmssKey_Free(&key);
remove(XMSS_GEN_TEST_PRIV_KEY_FILE);
wc_FreeRng(&rng);
#endif
return EXPECT_RESULT();
}
+5 -1
View File
@@ -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 */
-13
View File
@@ -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;
+27
View File
@@ -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,
+1
View File
@@ -34,5 +34,6 @@ int test_ocsp_cert_unknown_crl_fallback(void);
int test_ocsp_cert_unknown_crl_fallback_nonleaf(void);
int test_tls13_nonblock_ocsp_low_mfl(void);
int test_ocsp_responder(void);
int test_ocsp_ancestor_responder_rejected(void);
#endif /* WOLFSSL_TEST_OCSP_H */
File diff suppressed because it is too large Load Diff
+3 -1
View File
@@ -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));
+5
View File
@@ -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;
+61 -1
View File
@@ -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();
}
+6
View File
@@ -25,11 +25,17 @@
#include <tests/api/api_decl.h>
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)
+218
View File
@@ -3933,6 +3933,224 @@ int test_wc_PKCS7_EncodeEncryptedData(void)
} /* END test_wc_PKCS7_EncodeEncryptedData() */
/*
* Regression test for an integer overflow in the PKCS#7 attribute encode
* path. An application-supplied PKCS7Attrib.valueSz close to UINT32_MAX used
* to wrap the word32 size accumulation in EncodeAttributes() /
* FlattenEncodedAttribs(), yielding an undersized allocation followed by a
* multi-gigabyte XMEMCPY (heap buffer overflow). The encode call must now
* reject the oversized attribute with an error rather than overflow.
*/
int test_wc_PKCS7_EncodeEncryptedData_AttribOverflow(void)
{
EXPECT_DECLS;
#if defined(HAVE_PKCS7) && !defined(NO_PKCS7_ENCRYPTED_DATA) && ( \
(!defined(NO_AES) && defined(HAVE_AES_CBC) && \
(defined(WOLFSSL_AES_256) || defined(WOLFSSL_AES_128))) || \
!defined(NO_DES3))
PKCS7* pkcs7 = NULL;
byte output[TWOK_BUF];
PKCS7Attrib attrib;
int i;
/* Two values that each overflow the size arithmetic in EncodeAttributes()
* but trip a different guard:
* 0xFFFFFFF4 - wraps the word32 component sum (first guard), and
* 0x7FFFFFF0 - stays within word32 but pushes the per-attribute total
* past the signed int maximum (second guard). */
static const word32 overflowSz[] = { 0xFFFFFFF4U, 0x7FFFFFF0U };
/* Small, valid attribute buffers. The encode path must reject the
* oversized valueSz before ever dereferencing attrib.value. */
static const byte oid[] = { 0x06, 0x03, 0x55, 0x04, 0x03 };
static const byte value[] = { 0x04, 0x01, 0x00 };
const byte data[] = { /* Hello World */
0x48,0x65,0x6c,0x6c,0x6f,0x20,0x57,0x6f,0x72,0x6c,0x64
};
#if !defined(NO_AES) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_256)
byte key[] = {
0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,
0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,
0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,
0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08
};
int encryptOID = AES256CBCb;
#elif !defined(NO_AES) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_128)
byte key[] = {
0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,
0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08
};
int encryptOID = AES128CBCb;
#else
byte key[] = {
0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,
0xfe,0xde,0xba,0x98,0x76,0x54,0x32,0x10,
0x89,0xab,0xcd,0xef,0x01,0x23,0x45,0x67
};
int encryptOID = DES3b;
#endif
XMEMSET(&attrib, 0, sizeof(attrib));
attrib.oid = oid;
attrib.oidSz = (word32)sizeof(oid);
attrib.value = value;
for (i = 0; i < (int)(sizeof(overflowSz) / sizeof(overflowSz[0])); i++) {
attrib.valueSz = overflowSz[i];
ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId));
ExpectIntEQ(wc_PKCS7_Init(pkcs7, HEAP_HINT, testDevId), 0);
if (pkcs7 != NULL) {
pkcs7->content = (byte*)data;
pkcs7->contentSz = (word32)sizeof(data);
pkcs7->contentOID = DATA;
pkcs7->encryptOID = encryptOID;
pkcs7->encryptionKey = key;
pkcs7->encryptionKeySz = (word32)sizeof(key);
pkcs7->unprotectedAttribs = &attrib;
pkcs7->unprotectedAttribsSz = 1;
}
ExpectIntEQ(wc_PKCS7_EncodeEncryptedData(pkcs7, output, sizeof(output)),
WC_NO_ERR_TRACE(BUFFER_E));
wc_PKCS7_Free(pkcs7);
pkcs7 = NULL;
}
#endif
return EXPECT_RESULT();
} /* END test_wc_PKCS7_EncodeEncryptedData_AttribOverflow() */
/*
* Same overflow guard, exercised through the SignedData attribute path
* (pkcs7->signedAttribs -> wc_PKCS7_BuildSignedAttributes -> EncodeAttributes).
* The encode must reject the oversized attribute instead of overflowing.
*/
int test_wc_PKCS7_EncodeSignedData_AttribOverflow(void)
{
EXPECT_DECLS;
#if defined(HAVE_PKCS7) && defined(USE_CERT_BUFFERS_2048) && !defined(NO_RSA)
PKCS7* pkcs7 = NULL;
WC_RNG rng;
byte output[FOURK_BUF];
byte data[] = "Test data to encode.";
PKCS7Attrib attrib;
static const byte oid[] = { 0x06, 0x03, 0x55, 0x04, 0x03 };
static const byte value[] = { 0x04, 0x01, 0x00 };
XMEMSET(&rng, 0, sizeof(WC_RNG));
XMEMSET(&attrib, 0, sizeof(attrib));
attrib.oid = oid;
attrib.oidSz = (word32)sizeof(oid);
attrib.value = value;
/* word32 wraparound trigger */
attrib.valueSz = 0xFFFFFFF4U;
ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId));
ExpectIntEQ(wc_PKCS7_Init(pkcs7, HEAP_HINT, INVALID_DEVID), 0);
ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, (byte*)client_cert_der_2048,
(word32)sizeof(client_cert_der_2048)), 0);
if (pkcs7 != NULL) {
pkcs7->content = data;
pkcs7->contentSz = (word32)sizeof(data);
pkcs7->privateKey = (byte*)client_key_der_2048;
pkcs7->privateKeySz = (word32)sizeof(client_key_der_2048);
pkcs7->encryptOID = RSAk;
#if defined(NO_SHA) || defined(WC_FIPS_186_5_PLUS)
pkcs7->hashOID = SHA256h;
#else
pkcs7->hashOID = SHAh;
#endif
pkcs7->rng = &rng;
pkcs7->signedAttribs = &attrib;
pkcs7->signedAttribsSz = 1;
}
ExpectIntEQ(wc_PKCS7_EncodeSignedData(pkcs7, output, sizeof(output)),
WC_NO_ERR_TRACE(BUFFER_E));
wc_PKCS7_Free(pkcs7);
DoExpectIntEQ(wc_FreeRng(&rng), 0);
#endif
return EXPECT_RESULT();
} /* END test_wc_PKCS7_EncodeSignedData_AttribOverflow() */
/*
* Same overflow guard, exercised through the AuthEnvelopedData attribute
* paths. Case 1 covers a malicious authenticated attribute; case 2 supplies a
* valid authenticated attribute (which forces allocation of the auth attrib
* and AAD buffers) together with a malicious unauthenticated attribute, so the
* more complex unauth cleanup path (FreeEncodedRecipientSet + XFREE(aadBuffer)
* + XFREE(flatAuthAttribs)) is exercised. Both must return an error.
*/
int test_wc_PKCS7_EncodeAuthEnvelopedData_AttribOverflow(void)
{
EXPECT_DECLS;
#if defined(HAVE_PKCS7) && defined(USE_CERT_BUFFERS_2048) && !defined(NO_RSA) && \
defined(HAVE_AESGCM) && !defined(NO_AES) && defined(WOLFSSL_AES_256)
PKCS7* pkcs7 = NULL;
byte output[FOURK_BUF];
byte data[] = "Test data to encode.";
PKCS7Attrib bad;
PKCS7Attrib good;
static const byte oid[] = { 0x06, 0x03, 0x55, 0x04, 0x03 };
static const byte value[] = { 0x04, 0x01, 0x00 };
XMEMSET(&bad, 0, sizeof(bad));
bad.oid = oid;
bad.oidSz = (word32)sizeof(oid);
bad.value = value;
/* word32 wraparound trigger */
bad.valueSz = 0xFFFFFFF4U;
XMEMSET(&good, 0, sizeof(good));
good.oid = oid;
good.oidSz = (word32)sizeof(oid);
good.value = value;
good.valueSz = (word32)sizeof(value);
/* Case 1: malicious authenticated attribute. */
ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId));
ExpectIntEQ(wc_PKCS7_Init(pkcs7, HEAP_HINT, INVALID_DEVID), 0);
ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, (byte*)client_cert_der_2048,
(word32)sizeof(client_cert_der_2048)), 0);
if (pkcs7 != NULL) {
pkcs7->content = data;
pkcs7->contentSz = (word32)sizeof(data);
pkcs7->contentOID = DATA;
pkcs7->encryptOID = AES256GCMb;
pkcs7->authAttribs = &bad;
pkcs7->authAttribsSz = 1;
}
ExpectIntEQ(wc_PKCS7_EncodeAuthEnvelopedData(pkcs7, output, sizeof(output)),
WC_NO_ERR_TRACE(BUFFER_E));
wc_PKCS7_Free(pkcs7);
pkcs7 = NULL;
/* Case 2: valid authenticated attribute + malicious unauthenticated one. */
ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId));
ExpectIntEQ(wc_PKCS7_Init(pkcs7, HEAP_HINT, INVALID_DEVID), 0);
ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, (byte*)client_cert_der_2048,
(word32)sizeof(client_cert_der_2048)), 0);
if (pkcs7 != NULL) {
pkcs7->content = data;
pkcs7->contentSz = (word32)sizeof(data);
pkcs7->contentOID = DATA;
pkcs7->encryptOID = AES256GCMb;
pkcs7->authAttribs = &good;
pkcs7->authAttribsSz = 1;
pkcs7->unauthAttribs = &bad;
pkcs7->unauthAttribsSz = 1;
}
ExpectIntEQ(wc_PKCS7_EncodeAuthEnvelopedData(pkcs7, output, sizeof(output)),
WC_NO_ERR_TRACE(BUFFER_E));
wc_PKCS7_Free(pkcs7);
#endif
return EXPECT_RESULT();
} /* END test_wc_PKCS7_EncodeAuthEnvelopedData_AttribOverflow() */
#if defined(HAVE_PKCS7) && defined(USE_CERT_BUFFERS_2048) && !defined(NO_DES3) && !defined(NO_RSA) && !defined(NO_SHA)
static void build_test_EncryptedKeyPackage(byte * out, word32 * out_size, byte * in_data, word32 in_size, size_t in_content_type, size_t test_vector)
{
+6
View File
@@ -29,6 +29,8 @@ int test_wc_PKCS7_Init(void);
int test_wc_PKCS7_InitWithCert(void);
int test_wc_PKCS7_EncodeData(void);
int test_wc_PKCS7_EncodeSignedData(void);
int test_wc_PKCS7_EncodeSignedData_AttribOverflow(void);
int test_wc_PKCS7_EncodeAuthEnvelopedData_AttribOverflow(void);
#if defined(HAVE_PKCS7) && defined(WC_RSA_PSS) && !defined(NO_RSA) && \
!defined(NO_FILESYSTEM) && !defined(NO_SHA256)
int test_wc_PKCS7_EncodeSignedData_RSA_PSS(void);
@@ -56,6 +58,7 @@ int test_wc_PKCS7_EncodeDecodeEnvelopedData(void);
int test_wc_PKCS7_SetAESKeyWrapUnwrapCb(void);
int test_wc_PKCS7_GetEnvelopedDataKariRid(void);
int test_wc_PKCS7_EncodeEncryptedData(void);
int test_wc_PKCS7_EncodeEncryptedData_AttribOverflow(void);
int test_wc_PKCS7_DecodeEncryptedKeyPackage(void);
int test_wc_PKCS7_DecodeSymmetricKeyPackage(void);
int test_wc_PKCS7_DecodeOneSymmetricKey(void);
@@ -112,6 +115,7 @@ int test_wc_PKCS7_VerifySignedData_TruncCertSetTag(void);
TEST_DECL_GROUP("pkcs7_sd", test_wc_PKCS7_InitWithCert), \
TEST_DECL_GROUP("pkcs7_sd", test_wc_PKCS7_EncodeData), \
TEST_DECL_GROUP("pkcs7_sd", test_wc_PKCS7_EncodeSignedData), \
TEST_DECL_GROUP("pkcs7_sd", test_wc_PKCS7_EncodeSignedData_AttribOverflow), \
TEST_PKCS7_RSA_PSS_SD_DECL \
TEST_DECL_GROUP("pkcs7_sd", test_wc_PKCS7_EncodeSignedData_ex), \
TEST_DECL_GROUP("pkcs7_sd", test_wc_PKCS7_VerifySignedData_RSA), \
@@ -134,6 +138,8 @@ int test_wc_PKCS7_VerifySignedData_TruncCertSetTag(void);
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_SetAESKeyWrapUnwrapCb), \
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_GetEnvelopedDataKariRid), \
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_EncodeEncryptedData), \
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_EncodeEncryptedData_AttribOverflow), \
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_EncodeAuthEnvelopedData_AttribOverflow), \
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_DecodeEncryptedKeyPackage), \
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_DecodeSymmetricKeyPackage), \
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_DecodeOneSymmetricKey), \

Some files were not shown because too many files have changed in this diff Show More