mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-10-27 08:37:58 +03:00
Enable TLS 1.3 and resumable TLS sessions in both TLS backends
Enable TLS 1.3 alongside TLS 1.2 in Mbed TLS 3.6.7. It runs on PSA crypto, now initialized in MbedTLSSocket::init() and freed in end(); PSA key storage, PSA config, LMS and MBEDTLS_USE_PSA_CRYPTO stay off, so TLS 1.2 and libssh2 keep their classic implementations. Mbed TLS requires MBEDTLS_THREADING_C for TLS 1.3 in multithreaded programs, since threads share PSA's key store. Use pthread mutexes on POSIX, and add MBEDTLS_THREADING_WIN32 for Windows, where Mbed TLS has no implementation: small local patches to check_config.h, threading.h and threading.c with statically initialized SRWLOCK mutexes, so nothing has to run before the library is first used. Make TLS sessions resumable on TLS 1.3, which FTPS data connections need against servers requiring session reuse. TLS 1.3 resumes only from NewSessionTicket messages sent after the handshake: - MbedTLSSocket asks to be signalled about tickets and keeps the latest session. receive() processes a buffered ticket immediately instead of returning NotReady on a blocking socket. - OpenSSLSocket never restored sessions on any TLS version; it now keeps each session through a client session-cache callback and offers the latest with SSL_set_session(). - Both keep a socket's session after its connection closes, releasing it on reconnect or destruction; restoring sockets copy it under a mutex. Extend tls_security_tests.cpp to run against TLS 1.2-only and TLS 1.3-only s_server instances, checking the negotiated version and that a restored session resumes on both. Also fix the OpenSSL build, which did not link libcrypto where libssh2 needs it; the Haiku build, where premake's os.getnumcpus() returns nil; and two duplicate command-line flags that args 6.6.1 rejects at startup (eepp-http-request --data-raw, eepp-texturepacker -h). Record the TLS 1.3 work and an Android SDL2 assessment in the security audit.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# Third-party security audit
|
||||
|
||||
Last reviewed: **2026-10-26**. This document and its inventory are maintained over time; update
|
||||
Last reviewed: **2026-10-27**. This document and its inventory are maintained over time; update
|
||||
both whenever a dependency changes or is re-reviewed.
|
||||
|
||||
Initial audit: **2026-10-24**, baseline `dfc1a1941` (Brotli 1.2.1 upgrade included).
|
||||
@@ -25,7 +25,7 @@ release has not been established.
|
||||
| libpng | 1.6.37 | **1.6.59** | Imported upstream library sources, architecture implementations and the release's prebuilt configuration without source patches. |
|
||||
| NanoSVG | Modified FLTK-derived snapshot | Same snapshot plus manual security fixes | Patched the reported arc conversion, fixed-point conversion/advancement and stroke tessellation issues while retaining local style/currentColor behavior. 2026-10-26: fixed a single-stop gradient heap over-read, unbounded dashing, and NaN-to-int conversions in the rasterizer. |
|
||||
| libzip | 0.10 plus local hardening | **1.12.1** | Replaced the fork with the upstream release; only an include-path patch remains. `Zip` uses the current API. ZIP browsing limits were removed. |
|
||||
| Mbed TLS | 3.6.0 | **3.6.7** (LTS) | Library and headers match the release; eepp's `mbedtls_config.h` block is retained (PSA crypto, TLS 1.3 and weak algorithms remain disabled). |
|
||||
| Mbed TLS | 3.6.0 | **3.6.7** (LTS) | Library and headers match the release apart from three small threading patches; eepp's `mbedtls_config.h` block is retained. TLS 1.3 and PSA crypto enabled on 2026-10-27; weak algorithms remain disabled. |
|
||||
| libvorbis | 1.3.6 | **1.3.7** | Includes the CVE-2018-10393 encoder bounds fix and the channel validation changes; all imported files match the release. |
|
||||
| Monocypher | 4.0.2 | **4.0.3** | Fixes the compiler-dependent Ed25519 signing timing leak; imported sources match the release. |
|
||||
| simdutf | 9.2.0 | **9.2.1** | Regenerated amalgamation with the same UTF-8/UTF-32-only feature set; Base64 stays disabled. |
|
||||
@@ -72,7 +72,7 @@ malformed-input vulnerabilities.
|
||||
|
||||
| Order | Component | Current source | Action | Reason and qualification |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 1 | Bundled SDL2 source | 2.0.12 | Reconcile Android source with the newer SDL2 pin | Old source has high-severity surface/blit issues; an application exploit path was not established. |
|
||||
| 1 | Bundled SDL2 source | 2.0.12 | Remove the vendored copy; download the pinned SDL release before the Android build, as the MinGW and MSVC builds do, and port Android to SDL3 (recommended) | Old source has high-severity surface/blit issues; an application exploit path was not established. Its local changes are assessed below. |
|
||||
|
||||
Orders indicate engineering priority for this repository, not a new CVSS score.
|
||||
Targets are releases verified during the initial audit; check upstream again before
|
||||
@@ -256,22 +256,16 @@ Updated from 3.6.0 to the [3.6.7 LTS release](https://github.com/Mbed-TLS/mbedtl
|
||||
(`mbedtls-3.6.7.tar.bz2`, SHA-256
|
||||
`a7e8bcbec0e6f761b4af24f25677626b35f762f68eef79c08677a363212d11f6`), avoiding a simultaneous
|
||||
4.x migration. Every imported library source and header matches the release except
|
||||
`include/mbedtls/mbedtls_config.h`, whose trailing eepp block is retained: weak key exchanges,
|
||||
DES and DHM disabled, deprecated APIs removed, AESCE limited to AArch64 Linux, and
|
||||
`MBEDTLS_PSA_CRYPTO_C`, `MBEDTLS_SSL_PROTO_TLS1_3` and LMS disabled. The release's PSA
|
||||
sources are present again (3.6.0's import had deleted them as unused); with PSA disabled they
|
||||
compile to empty objects. They are kept deliberately: TLS 1.3 in Mbed TLS 3.6 requires PSA, and
|
||||
enabling it is planned as a separate migration. The libssh2 classic-API adapter is unchanged.
|
||||
|
||||
The default TLS backend is selected in `premake5.lua`; OpenSSL is optional and was not
|
||||
built in this validation. [`tls_security_tests.cpp`](../../src/tests/unit_tests/tls_security_tests.cpp)
|
||||
connects to a loopback OpenSSL `s_server` (TLS 1.2), and checks that a trusted certificate is
|
||||
accepted while a wrong host name and an untrusted certificate are rejected.
|
||||
`include/mbedtls/mbedtls_config.h`, whose trailing eepp block is retained (weak key exchanges,
|
||||
DES and DHM disabled, deprecated APIs removed, AESCE limited to AArch64 Linux), and the threading
|
||||
patches described under "TLS 1.3" below. The release's PSA sources are present again (3.6.0's
|
||||
import had deleted them as unused) and are used since TLS 1.3 was enabled. The libssh2
|
||||
classic-API adapter is unchanged.
|
||||
|
||||
The ordinary [`MbedTLSSocket`](../../src/eepp/network/ssl/backend/mbedtls/mbedtlssocket.cpp)
|
||||
is a stream TLS client. It sets the hostname, uses certificate verification when
|
||||
requested, and disables session tickets. This excludes several high findings from
|
||||
its usual configuration. The following is a triage of high upstream or high NVD
|
||||
is a stream TLS client. It sets the hostname and uses certificate verification when requested;
|
||||
it disables TLS 1.2 session tickets and, for TLS 1.3, only receives tickets to resume its own
|
||||
sessions. Its client role excludes several high findings. The following is a triage of high upstream or high NVD
|
||||
matches, not a claim they all affect that client:
|
||||
|
||||
| Advisory | Assessment of current callers/configuration |
|
||||
@@ -292,12 +286,6 @@ matches, not a claim they all affect that client:
|
||||
| CVE-2026-50579 | Reused PKCS7 context; no PKCS7 caller found. |
|
||||
| CVE-2026-50713 | Introduced in 3.6.3, after the old 3.6.0, and fixed in 3.6.7 (DTLS renegotiation with `badmac_limit`). DTLS also differs from the eepp stream TLS path. |
|
||||
|
||||
Advisory definitions and fixes: [official security index](https://mbed-tls.readthedocs.io/en/latest/security-advisories/).
|
||||
The individual documents were read from the official `Mbed-TLS/mbedtls-docs`
|
||||
source archive, including issues whose NVD descriptions omit configuration details.
|
||||
The [AESNI advisory](https://mbed-tls.readthedocs.io/en/latest/security-advisories/mbedtls-security-advisory-2025-06-1/)
|
||||
is particularly useful when assessing x86 distribution builds.
|
||||
|
||||
Advisory definitions and fixes: [official security index](https://mbed-tls.readthedocs.io/en/latest/security-advisories/).
|
||||
The individual documents were read from the official `Mbed-TLS/mbedtls-docs`
|
||||
source archive, including issues whose NVD descriptions omit configuration details.
|
||||
@@ -305,6 +293,56 @@ The [AESNI advisory](https://mbed-tls.readthedocs.io/en/latest/security-advisori
|
||||
is particularly useful when assessing x86 distribution builds. 3.6.7 also clears the low and
|
||||
medium fixes accumulated since 3.6.0.
|
||||
|
||||
#### TLS 1.3 — 2026-10-27
|
||||
|
||||
Both TLS backends now negotiate TLS 1.3, keeping TLS 1.2. In Mbed TLS 3.6, TLS 1.3 runs on PSA
|
||||
crypto: `MBEDTLS_PSA_CRYPTO_C` and `MBEDTLS_SSL_PROTO_TLS1_3` are no longer undefined, while
|
||||
`MBEDTLS_PSA_CRYPTO_CONFIG`, persistent key storage (`MBEDTLS_PSA_CRYPTO_STORAGE_C`,
|
||||
`MBEDTLS_PSA_ITS_FILE_C`), LMS and `MBEDTLS_USE_PSA_CRYPTO` stay off, so TLS 1.2 and libssh2 keep
|
||||
their classic implementations. `MbedTLSSocket::init()` calls `psa_crypto_init()` and `end()` calls
|
||||
`mbedtls_psa_crypto_free()`; `SSLSocket` defers `end()` until no socket is alive.
|
||||
|
||||
Mbed TLS requires `MBEDTLS_THREADING_C` for TLS 1.3 in multithreaded programs, because threads
|
||||
with separate TLS contexts still share PSA's key store. POSIX builds use
|
||||
`MBEDTLS_THREADING_PTHREAD`. Mbed TLS has no Windows implementation, so eepp adds
|
||||
`MBEDTLS_THREADING_WIN32`, small local patches that keep every caller unchanged:
|
||||
|
||||
| File | Local change |
|
||||
| --- | --- |
|
||||
| `include/mbedtls/check_config.h` | Accepts `MBEDTLS_THREADING_WIN32` as the single threading implementation (Windows only) |
|
||||
| `include/mbedtls/threading.h` | Mutex type holding an `SRWLOCK` as `void *`, so the public header does not include `<windows.h>` |
|
||||
| `library/threading.c` | `SRWLOCK` init/lock/unlock and statically initialized global mutexes (`MUTEX_INIT = { NULL, 1 }`), like the pthread path, so nothing must run before the library is first used |
|
||||
|
||||
Session resumption, which FTPS data connections rely on (`SSLSocket`'s restore-session
|
||||
constructor; servers such as vsftpd with `require_ssl_reuse` reject data connections that do not
|
||||
resume), is implemented for TLS 1.3 in both backends. TLS 1.3 resumes only from NewSessionTicket
|
||||
messages, sent after the handshake:
|
||||
|
||||
- `MbedTLSSocket` enables `mbedtls_ssl_conf_tls13_enable_signal_new_session_tickets` and keeps the
|
||||
latest session whenever a ticket arrives. A ticket is first reported as `WANT_READ` while Mbed
|
||||
TLS holds it buffered, so `receive()` processes it at once (`mbedtls_ssl_check_pending()`)
|
||||
instead of returning `NotReady`.
|
||||
- `OpenSSLSocket` never restored sessions, for any TLS version; FTPS against servers requiring
|
||||
reuse could not work with it. It now keeps every session OpenSSL issues through a client
|
||||
session-cache callback and offers the latest with `SSL_set_session()`.
|
||||
- In both backends a socket keeps its session after its connection closes, and releases it when
|
||||
it reconnects or is destroyed; restoring sockets copy it under a mutex.
|
||||
|
||||
[`tls_security_tests.cpp`](../../src/tests/unit_tests/tls_security_tests.cpp) runs loopback
|
||||
OpenSSL `s_server` instances restricted to TLS 1.2 and to TLS 1.3. It checks the negotiated
|
||||
version, accepts a trusted certificate, and rejects a wrong host name and an untrusted
|
||||
certificate; it also checks that a restored session is reported as resumed (`Reused, TLSv1.x`)
|
||||
on both versions.
|
||||
|
||||
Validation: macOS ARM64 with Mbed TLS, full suite (2,134 passed, 2 audio tests skipped); Linux
|
||||
ARM64 (Docker) with Mbed TLS, full suite (2,146 passed, one font test skipped) including the 35
|
||||
SFTP tests required; Linux ARM64 with the OpenSSL backend (OpenSSL 3.0.13), the TLS tests; MinGW-w64
|
||||
builds Mbed TLS and libssh2 with the `SRWLOCK` mutexes. eepp's HTTP client fetched google.com,
|
||||
github.com and cloudflare.com. MSVC is left to CI.
|
||||
|
||||
Building with `--with-openssl` also needed `libcrypto` linked wherever libssh2 is, since libssh2's
|
||||
OpenSSL backend calls it directly; the unit tests did not link before.
|
||||
|
||||
### libvorbis
|
||||
|
||||
Updated from 1.3.6 to [1.3.7](https://github.com/xiph/vorbis/blob/v1.3.7/CHANGES)
|
||||
@@ -498,6 +536,36 @@ Updating the actual Android source is still preferable to carrying a 2.0.12 fork
|
||||
changing only a Premake download version does not update it.
|
||||
Source: [SDL surface-allocation fix](https://github.com/libsdl-org/SDL/commit/8c91cf7dba5193f5ce12d06db1336515851c9ee9).
|
||||
|
||||
#### Android SDL2 local changes — assessed 2026-10-26
|
||||
|
||||
Compared with the `SDL2-2.0.12.tar.gz` release (SHA-256
|
||||
`349268f695c02efbc9b9148a70b85e58cefbbf704abd3e91be654db7f1e2c863`), 900 of the 901 files in
|
||||
`src/thirdparty/SDL2` are identical. The Android build's SDL pieces carry three local changes:
|
||||
|
||||
| Where | Local change | In SDL2 2.32.10 | In SDL3 3.4.10 |
|
||||
| --- | --- | --- | --- |
|
||||
| `src/thirdparty/SDL2/src/sensor/android/SDL_androidsensor.c` | `ALooper_pollAll` → `ALooper_pollOnce`; newer NDKs reject `pollAll` | Upstream | Upstream |
|
||||
| `projects/android-project/.../org/libsdl/app/HIDDeviceManager.java` | `PendingIntent.FLAG_MUTABLE` on Android 12+ | Upstream | Upstream |
|
||||
| `projects/android-project/.../org/libsdl/app/SDLActivity.java` | `getLibraries()` loads `BuildConfig.SO_NAME` instead of `"main"`, so each app flavor loads its own library | Still needed | Still needed |
|
||||
|
||||
The SDL2 module in `projects/android-project/app/jni/eepp.mk` is 2.0.12's `Android.mk` unchanged
|
||||
apart from `LOCAL_PATH := $(SDL_PATH)`. 2.32.10's `Android.mk` adds `audio/aaudio`,
|
||||
`joystick/dummy`, `joystick/virtual`, `locale`, `misc` and their Android sources, builds hidapi
|
||||
into SDL2 (no separate `libhidapi` module) and adds `SDLSurface.java`. SDL3 3.4.10
|
||||
(`SDL3-3.4.10.zip`, SHA-256 `be8dafef3ecc956e736cfd1c242c10737f3ad589a866f25ba437b7f2f6d5ced2`)
|
||||
still ships an `Android.mk` (module `SDL3`) and its Java classes; its sample project uses
|
||||
`minSdkVersion 21` and `compileSdkVersion 35` (eepp: `minSdk 27`, `compileSdk 34`).
|
||||
|
||||
Plan: remove `src/thirdparty/SDL2`. A Gradle `preBuild` task downloads the pinned SDL release into
|
||||
`src/thirdparty/SDL3-<version>`, the directory premake already uses and `.gitignore` already
|
||||
excludes, taking the version from the Premake pin. `eepp.mk` includes SDL's own `Android.mk`
|
||||
instead of a copy and builds the SDL3 backend and mojoAL-SDL3; SDL3's main is header-only, so the
|
||||
`src/main/android/*.c` entry goes. The library-name change moves into a small `SDLActivity`
|
||||
subclass so SDL's Java classes stay unmodified. Porting directly to SDL3 is recommended over SDL2
|
||||
2.32.10 first: the desktop default backend is already SDL3 and the SDL3 backend already has the
|
||||
same Android branches as SDL2's, so an SDL2 step would redo the Java, build-file and device-testing
|
||||
work. eepp on SDL3 has not run on Android yet, so input, text input and lifecycle need device testing.
|
||||
|
||||
## Important exclusions and already-fixed issues
|
||||
|
||||
| Match | Reason it is not an outstanding high-CVE upgrade finding here |
|
||||
@@ -657,12 +725,14 @@ Coverage gaps that remain explicit:
|
||||
|
||||
## Remaining implementation batches
|
||||
|
||||
1. **Platform maintenance:** reconcile the Android SDL2 source with the newer SDL2 pin.
|
||||
1. **Android SDL:** remove the vendored SDL2 2.0.12 copy, download the pinned SDL release before
|
||||
the Android build, and port Android to SDL3 (recommended; see "Android SDL2 local changes").
|
||||
2. Replace the libssh2 development snapshot with a security-fixed stable release
|
||||
when one is available, retaining the recorded integration patches.
|
||||
3. **TLS 1.3:** enable PSA crypto and TLS 1.3 in eepp's Mbed TLS configuration and port
|
||||
`MbedTLSSocket`. The PSA sources are already vendored for this, and Mbed TLS 4.x drops
|
||||
the classic API that `MbedTLSSocket` and the libssh2 adapter use.
|
||||
3. **Mbed TLS 4.x:** migrate from the 3.6 LTS. 4.x removes the classic crypto APIs (entropy,
|
||||
`ctr_drbg`, `pk`/`md` contexts) that `MbedTLSSocket` and libssh2's Mbed TLS adapter use, in
|
||||
favour of PSA, which now runs in production for TLS 1.3. Drop the local
|
||||
`MBEDTLS_THREADING_WIN32` patches if 4.x provides Windows threading.
|
||||
|
||||
For subsequent updates, record the upstream release/commit and retained patches
|
||||
next to the dependency, and regenerate the inventory after each batch. An automated
|
||||
|
||||
@@ -389,14 +389,17 @@
|
||||
"version_evidence": "src/thirdparty/mbedtls/include/mbedtls/build_info.h",
|
||||
"upstream": "https://github.com/Mbed-TLS/mbedtls",
|
||||
"assessment": "fixed",
|
||||
"notes": "Library sources and headers match the 3.6.7 LTS release except include/mbedtls/mbedtls_config.h, whose eepp block is retained (PSA crypto, TLS 1.3, LMS and weak key exchanges disabled). Restored PSA sources compile to empty objects. TLS client trust/hostname test added.",
|
||||
"notes": "Library sources and headers match the 3.6.7 LTS release except include/mbedtls/mbedtls_config.h (eepp block: weak key exchanges, DES, DHM and deprecated APIs disabled) and three threading patches adding MBEDTLS_THREADING_WIN32 (check_config.h, threading.h, threading.c: statically initialized SRWLOCK mutexes). Since 2026-10-27 TLS 1.3 and PSA crypto are enabled, with MBEDTLS_THREADING_C (pthread on POSIX, WIN32 on Windows); PSA storage, PSA config, LMS and MBEDTLS_USE_PSA_CRYPTO stay off. TLS tests cover TLS 1.2 and 1.3 negotiation, trust and hostname checks, and session resumption.",
|
||||
"source_revision": "1576fa7eb1c1664135326850c0fcf9f4d694d0b9",
|
||||
"source_revision_kind": "last eepp commit touching directory",
|
||||
"source_fingerprint_sha256": "54c9b453ec73b73dfd413a07a457e0383c1ced78d20919f2e0f0d5ff51d4ca14",
|
||||
"source_fingerprint_sha256": "210e4d975b4d54885f8fa20d1e748bfc2a6d7065e546bf54200113e663de039d",
|
||||
"baseline_source_fingerprint_sha256": "d4ef114cebeaf7a0ebada30fc7cfb6469cb3b32fdee3bff1f064d20141aab764",
|
||||
"upstream_tag": "mbedtls-3.6.7",
|
||||
"retained_patches": [
|
||||
"include/mbedtls/mbedtls_config.h",
|
||||
"include/mbedtls/check_config.h",
|
||||
"include/mbedtls/threading.h",
|
||||
"library/threading.c",
|
||||
".clang-format"
|
||||
],
|
||||
"resolved_advisories": [
|
||||
@@ -418,7 +421,7 @@
|
||||
"CVE-2026-50580"
|
||||
],
|
||||
"working_tree_modified": true,
|
||||
"updated_at": "2026-10-25",
|
||||
"updated_at": "2026-10-27",
|
||||
"upstream_archive_sha256": "a7e8bcbec0e6f761b4af24f25677626b35f762f68eef79c08677a363212d11f6"
|
||||
},
|
||||
{
|
||||
@@ -1052,7 +1055,7 @@
|
||||
"url": "https://services.nvd.nist.gov/rest/json/cves/2.0?keywordSearch=zlib&resultsPerPage=2000"
|
||||
}
|
||||
],
|
||||
"last_updated": "2026-10-26",
|
||||
"last_updated": "2026-10-27",
|
||||
"remediation_base_commit": "49f5e179d6a89cf6713b3729a0fa59e3658748c9",
|
||||
"fingerprint_method": "SHA256 over sorted repository-relative paths, NUL, file bytes, NUL; tracked plus non-ignored untracked files, excluding deleted files. Submodule paths are relative to the submodule as in the initial inventory.",
|
||||
"remediation_validation": {
|
||||
|
||||
+10
-4
@@ -240,12 +240,13 @@ function os.is_real( os_name )
|
||||
return os.get_real() == os_name
|
||||
end
|
||||
|
||||
-- premake4 has no os.getnumcpus(); returns 1 when the count is unavailable.
|
||||
-- premake4 has no os.getnumcpus(). Returns 1 whenever the count cannot be read (no nproc or
|
||||
-- sysctl, as on Haiku, or no io.popen), which selects the single-unit HarfBuzz build.
|
||||
function num_cpus()
|
||||
local count = tonumber( os.getenv( "NUMBER_OF_PROCESSORS" ) or "" )
|
||||
if not count then
|
||||
local handle = io.popen( "nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null" )
|
||||
if handle then
|
||||
if not count and io.popen then
|
||||
local ok, handle = pcall( io.popen, "nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null" )
|
||||
if ok and handle then
|
||||
count = tonumber( handle:read( "*l" ) or "" )
|
||||
handle:close()
|
||||
end
|
||||
@@ -1125,6 +1126,11 @@ function eepp_module_vfs_dependencies()
|
||||
links { "mbedtls-static" }
|
||||
end
|
||||
end
|
||||
if _OPTIONS["with-openssl"] then
|
||||
-- libssh2's OpenSSL backend calls libcrypto directly.
|
||||
local windows = os.is_real("windows") or os.is_real("mingw32") or os.is_real("mingw64")
|
||||
links { get_backend_link_name( windows and "libcrypto" or "crypto" ) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
+7
-2
@@ -1033,6 +1033,9 @@ function eepp_module_vfs_dependencies()
|
||||
filter "system:windows"
|
||||
links { "mbedtls-static" }
|
||||
filter {}
|
||||
else
|
||||
-- libssh2's OpenSSL backend calls libcrypto directly.
|
||||
links { get_backend_link_name( os.istarget("windows") and "libcrypto" or "crypto" ) }
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1563,8 +1566,10 @@ workspace "eepp"
|
||||
defines { "HAVE_CONFIG_H" }
|
||||
-- harfbuzz.cc is upstream's single-unit build and includes every other source. It does
|
||||
-- about a quarter of the total work, so it is faster on machines with few cores; with 8+
|
||||
-- threads the separate sources compile in parallel and finish sooner.
|
||||
if os.getnumcpus() >= 8 then
|
||||
-- threads the separate sources compile in parallel and finish sooner. os.getnumcpus()
|
||||
-- returns nil where premake cannot count CPUs (Haiku); use the single unit there.
|
||||
local cpus = os.getnumcpus and os.getnumcpus() or nil
|
||||
if cpus ~= nil and cpus >= 8 then
|
||||
files { "src/thirdparty/harfbuzz/**.cc" }
|
||||
excludes { "src/thirdparty/harfbuzz/harfbuzz.cc" }
|
||||
else
|
||||
|
||||
@@ -6,15 +6,22 @@
|
||||
|
||||
#include <eepp/system/clock.hpp>
|
||||
#include <eepp/system/filesystem.hpp>
|
||||
#include <eepp/system/lock.hpp>
|
||||
#include <eepp/system/log.hpp>
|
||||
#include <eepp/system/packregistry.hpp>
|
||||
#include <mbedtls/error.h>
|
||||
#include <psa/crypto.h>
|
||||
|
||||
namespace EE { namespace Network { namespace SSL {
|
||||
|
||||
mbedtls_x509_crt MbedTLSSocket::sCACert;
|
||||
|
||||
bool MbedTLSSocket::init() {
|
||||
// TLS 1.3 handshakes run on PSA crypto, which must be initialized first.
|
||||
psa_status_t psaStatus = psa_crypto_init();
|
||||
if ( psaStatus != PSA_SUCCESS )
|
||||
Log::error( "psa_crypto_init failed: %d. TLS 1.3 connections will fail.", (int)psaStatus );
|
||||
|
||||
mbedtls_x509_crt_init( &sCACert );
|
||||
|
||||
//! Load the certificates and config
|
||||
@@ -55,10 +62,42 @@ bool MbedTLSSocket::init() {
|
||||
|
||||
bool MbedTLSSocket::end() {
|
||||
mbedtls_x509_crt_free( &sCACert );
|
||||
// SSLSocket defers end() until no socket is alive, so no handshake still uses PSA.
|
||||
mbedtls_psa_crypto_free();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MbedTLSSocket::saveSession() {
|
||||
mbedtls_ssl_session* session = (mbedtls_ssl_session*)eeMalloc( sizeof( mbedtls_ssl_session ) );
|
||||
if ( !session )
|
||||
return;
|
||||
|
||||
mbedtls_ssl_session_init( session );
|
||||
if ( mbedtls_ssl_get_session( &mSSLContext, session ) != 0 ) {
|
||||
mbedtls_ssl_session_free( session );
|
||||
eeFree( session );
|
||||
return;
|
||||
}
|
||||
|
||||
Lock l( mSessionMutex );
|
||||
if ( mSessionOwner && NULL != mSSLSession ) {
|
||||
mbedtls_ssl_session_free( mSSLSession );
|
||||
eeFree( mSSLSession );
|
||||
}
|
||||
mSSLSession = session;
|
||||
mSessionOwner = true;
|
||||
}
|
||||
|
||||
void MbedTLSSocket::releaseSession() {
|
||||
Lock l( mSessionMutex );
|
||||
if ( mSessionOwner && NULL != mSSLSession ) {
|
||||
mbedtls_ssl_session_free( mSSLSession );
|
||||
eeSAFE_FREE( mSSLSession );
|
||||
}
|
||||
mSessionOwner = false;
|
||||
}
|
||||
|
||||
MbedTLSSocket::MbedTLSSocket( SSLSocket* socket ) :
|
||||
SSLSocketImpl( socket ),
|
||||
mInitialized( false ),
|
||||
@@ -71,6 +110,7 @@ MbedTLSSocket::MbedTLSSocket( SSLSocket* socket ) :
|
||||
|
||||
MbedTLSSocket::~MbedTLSSocket() {
|
||||
disconnect();
|
||||
releaseSession();
|
||||
}
|
||||
|
||||
int MbedTLSSocket::bio_send( void* ctx, const unsigned char* buf, size_t len ) {
|
||||
@@ -116,8 +156,9 @@ int MbedTLSSocket::bio_recv( void* ctx, unsigned char* buf, size_t len ) {
|
||||
Socket::Status MbedTLSSocket::connect( const IpAddress& /*remoteAddress*/,
|
||||
unsigned short /*remotePort*/, Time timeout ) {
|
||||
// A previous handshake may have initialized TLS state without ever reaching Connected.
|
||||
// Always release it before starting a new handshake.
|
||||
// Always release it, and the previous connection's session, before a new handshake.
|
||||
disconnect();
|
||||
releaseSession();
|
||||
|
||||
bool isBlocking = mSSLSocket->isBlocking();
|
||||
if ( isBlocking && timeout != Time::Zero ) {
|
||||
@@ -151,14 +192,24 @@ Socket::Status MbedTLSSocket::connect( const IpAddress& /*remoteAddress*/,
|
||||
mbedtls_ssl_conf_authmode( &mSSLConfig, authmode );
|
||||
mbedtls_ssl_conf_ca_chain( &mSSLConfig, &sCACert, NULL );
|
||||
mbedtls_ssl_conf_rng( &mSSLConfig, mbedtls_ctr_drbg_random, &mCtrDrbg );
|
||||
// TLS 1.2 resumes by session ID; TLS 1.3 can only resume from a NewSessionTicket, which the
|
||||
// server sends after the handshake. Ask to be told about tickets so saveSession() can keep the
|
||||
// latest one for sockets that restore this session (FTPS data connections).
|
||||
mbedtls_ssl_conf_session_tickets( &mSSLConfig, MBEDTLS_SSL_SESSION_TICKETS_DISABLED );
|
||||
#if defined( MBEDTLS_SSL_PROTO_TLS1_3 ) && defined( MBEDTLS_SSL_SESSION_TICKETS )
|
||||
mbedtls_ssl_conf_tls13_enable_signal_new_session_tickets(
|
||||
&mSSLConfig, MBEDTLS_SSL_TLS1_3_SIGNAL_NEW_SESSION_TICKETS_ENABLED );
|
||||
#endif
|
||||
mbedtls_ssl_setup( &mSSLContext, &mSSLConfig );
|
||||
mbedtls_ssl_set_hostname( &mSSLContext, mSSLSocket->mHostName.c_str() );
|
||||
mbedtls_ssl_set_bio( &mSSLContext, this, bio_send, bio_recv, NULL );
|
||||
mbedtls_ssl_conf_session_tickets( &mSSLConfig, MBEDTLS_SSL_SESSION_TICKETS_DISABLED );
|
||||
|
||||
if ( mSSLSocket->mRestoreSession == NULL ) {
|
||||
while ( ( ret = mbedtls_ssl_handshake( &mSSLContext ) ) != 0 ) {
|
||||
if ( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE ) {
|
||||
if ( ret == MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET ) {
|
||||
saveSession();
|
||||
continue;
|
||||
} else if ( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE ) {
|
||||
mStatus = Socket::Error;
|
||||
break;
|
||||
} else if ( timeout != Time::Zero && clock.getElapsedTime() >= timeout ) {
|
||||
@@ -181,21 +232,16 @@ Socket::Status MbedTLSSocket::connect( const IpAddress& /*remoteAddress*/,
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
mSSLSession = (mbedtls_ssl_session*)eeMalloc( sizeof( mbedtls_ssl_session ) );
|
||||
if ( mSSLSession ) {
|
||||
mbedtls_ssl_session_init( mSSLSession );
|
||||
ret = mbedtls_ssl_get_session( &mSSLContext, mSSLSession );
|
||||
if ( ret ) {
|
||||
mbedtls_ssl_session_free( mSSLSession );
|
||||
eeSAFE_FREE( mSSLSession );
|
||||
} else {
|
||||
mSessionOwner = true;
|
||||
}
|
||||
}
|
||||
// A TLS 1.2 session is resumable now; a TLS 1.3 one is replaced once a ticket arrives.
|
||||
saveSession();
|
||||
} else {
|
||||
MbedTLSSocket* oldSocket =
|
||||
reinterpret_cast<MbedTLSSocket*>( mSSLSocket->mRestoreSession->mImpl );
|
||||
mbedtls_ssl_set_session( &mSSLContext, oldSocket->mSSLSession );
|
||||
// set_session copies the session, so the old socket may replace it afterwards. The
|
||||
// handshake runs on the first send or receive.
|
||||
Lock l( oldSocket->mSessionMutex );
|
||||
if ( NULL != oldSocket->mSSLSession )
|
||||
mbedtls_ssl_set_session( &mSSLContext, oldSocket->mSSLSession );
|
||||
}
|
||||
|
||||
mConnected = true;
|
||||
@@ -213,13 +259,7 @@ void MbedTLSSocket::disconnect() {
|
||||
mInitialized = false;
|
||||
}
|
||||
|
||||
if ( mSessionOwner && NULL != mSSLSession ) {
|
||||
mbedtls_ssl_session_free( mSSLSession );
|
||||
eeSAFE_FREE( mSSLSession );
|
||||
}
|
||||
|
||||
mConnected = false;
|
||||
mSessionOwner = false;
|
||||
mStatus = Socket::Disconnected;
|
||||
}
|
||||
|
||||
@@ -248,7 +288,10 @@ Socket::Status MbedTLSSocket::send( const void* data, std::size_t size, std::siz
|
||||
if ( size == 0 )
|
||||
return Socket::Done;
|
||||
|
||||
int ret = mbedtls_ssl_write( &mSSLContext, (const unsigned char*)data, size );
|
||||
int ret;
|
||||
while ( ( ret = mbedtls_ssl_write( &mSSLContext, (const unsigned char*)data, size ) ) ==
|
||||
MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET )
|
||||
saveSession();
|
||||
|
||||
if ( ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE ) {
|
||||
ret = 0; // non blocking io
|
||||
@@ -264,7 +307,20 @@ Socket::Status MbedTLSSocket::send( const void* data, std::size_t size, std::siz
|
||||
Socket::Status MbedTLSSocket::receive( void* data, std::size_t size, std::size_t& received ) {
|
||||
received = 0;
|
||||
|
||||
int ret = mbedtls_ssl_read( &mSSLContext, (unsigned char*)data, size );
|
||||
int ret;
|
||||
for ( ;; ) {
|
||||
ret = mbedtls_ssl_read( &mSSLContext, (unsigned char*)data, size );
|
||||
if ( ret == MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET ) {
|
||||
saveSession();
|
||||
continue;
|
||||
}
|
||||
// A TLS 1.3 NewSessionTicket is first reported as WANT_READ while Mbed TLS keeps the
|
||||
// record buffered; nothing is left on the socket to wait for, so process it now.
|
||||
if ( ret == MBEDTLS_ERR_SSL_WANT_READ && mbedtls_ssl_check_pending( &mSSLContext ) )
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE ) {
|
||||
return Socket::NotReady;
|
||||
} else if ( ret <= 0 ) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define EE_NETWORKCMBEDTLSSOCKET_HPP
|
||||
|
||||
#include <eepp/network/ssl/sslsocketimpl.hpp>
|
||||
#include <eepp/system/mutex.hpp>
|
||||
|
||||
#ifdef EE_MBEDTLS
|
||||
|
||||
@@ -13,6 +14,8 @@
|
||||
|
||||
namespace EE { namespace Network { namespace SSL {
|
||||
|
||||
using namespace EE::System;
|
||||
|
||||
class EE_API MbedTLSSocket : public SSLSocketImpl {
|
||||
public:
|
||||
static bool init();
|
||||
@@ -44,7 +47,14 @@ class EE_API MbedTLSSocket : public SSLSocketImpl {
|
||||
bool mConnected;
|
||||
bool mSessionOwner;
|
||||
Socket::Status mStatus;
|
||||
// The latest resumable session. TLS 1.3 delivers it in NewSessionTicket messages after the
|
||||
// handshake, so it is replaced while the connection is read; sockets restoring this session
|
||||
// copy it under mSessionMutex. It outlives the connection (disconnect() keeps it) and is
|
||||
// released when this socket reconnects or is destroyed.
|
||||
mbedtls_ssl_session* mSSLSession;
|
||||
Mutex mSessionMutex;
|
||||
void saveSession();
|
||||
void releaseSession();
|
||||
static int bio_send( void* ctx, const unsigned char* buf, size_t len );
|
||||
static int bio_recv( void* ctx, unsigned char* buf, size_t len );
|
||||
};
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <eepp/network/packet.hpp>
|
||||
#include <eepp/network/ssl/backend/openssl/curl_hostcheck.h>
|
||||
#include <eepp/system/filesystem.hpp>
|
||||
#include <eepp/system/lock.hpp>
|
||||
#include <eepp/system/log.hpp>
|
||||
#include <eepp/system/packregistry.hpp>
|
||||
|
||||
@@ -210,18 +211,41 @@ OpenSSLSocket::OpenSSLSocket( SSLSocket* socket ) :
|
||||
mBIO( NULL ),
|
||||
mConnected( false ),
|
||||
mStatus( Socket::Disconnected ),
|
||||
mMaxCertChainDepth( 9 ) {
|
||||
mMaxCertChainDepth( 9 ),
|
||||
mSession( NULL ) {
|
||||
mSSLSocket = socket;
|
||||
}
|
||||
|
||||
OpenSSLSocket::~OpenSSLSocket() {
|
||||
disconnect();
|
||||
releaseSession();
|
||||
}
|
||||
|
||||
int OpenSSLSocket::newSessionCb( ::SSL* ssl, SSL_SESSION* session ) {
|
||||
OpenSSLSocket* socket = static_cast<OpenSSLSocket*>( SSL_get_app_data( ssl ) );
|
||||
if ( !socket )
|
||||
return 0;
|
||||
Lock l( socket->mSessionMutex );
|
||||
if ( socket->mSession )
|
||||
SSL_SESSION_free( socket->mSession );
|
||||
socket->mSession = session;
|
||||
return 1; // We keep the reference OpenSSL passed in.
|
||||
}
|
||||
|
||||
void OpenSSLSocket::releaseSession() {
|
||||
Lock l( mSessionMutex );
|
||||
if ( mSession ) {
|
||||
SSL_SESSION_free( mSession );
|
||||
mSession = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Socket::Status OpenSSLSocket::connect( const IpAddress& /*remoteAddress*/,
|
||||
unsigned short /*remotePort*/, Time /*timeout*/ ) {
|
||||
// A failed handshake can own TLS state without having reached Connected.
|
||||
// A failed handshake can own TLS state without having reached Connected. The previous
|
||||
// connection's session is dropped too; a new one arrives with this handshake.
|
||||
disconnect();
|
||||
releaseSession();
|
||||
|
||||
// Set up a SSL_CTX object, which will tell our BIO object how to do its work
|
||||
mCTX = SSL_CTX_new( SSLv23_client_method() );
|
||||
@@ -229,6 +253,10 @@ Socket::Status OpenSSLSocket::connect( const IpAddress& /*remoteAddress*/,
|
||||
return mStatus = Socket::Error;
|
||||
|
||||
SSL_CTX_set_options( mCTX, SSL_OP_NO_TICKET );
|
||||
// Hand every resumable session to newSessionCb, for TLS 1.2 and for each TLS 1.3 ticket,
|
||||
// so sockets restoring this one (FTPS data connections) can resume it.
|
||||
SSL_CTX_set_session_cache_mode( mCTX, SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL_STORE );
|
||||
SSL_CTX_sess_set_new_cb( mCTX, newSessionCb );
|
||||
|
||||
if ( mSSLSocket->mValidateCertificate ) {
|
||||
if ( !sCerts.empty() ) {
|
||||
@@ -277,6 +305,16 @@ Socket::Status OpenSSLSocket::connect( const IpAddress& /*remoteAddress*/,
|
||||
}
|
||||
|
||||
SSL_set_fd( mSSL, (int)mSSLSocket->mSocket );
|
||||
SSL_set_app_data( mSSL, this );
|
||||
|
||||
if ( mSSLSocket->mRestoreSession ) {
|
||||
OpenSSLSocket* oldSocket =
|
||||
reinterpret_cast<OpenSSLSocket*>( mSSLSocket->mRestoreSession->mImpl );
|
||||
// SSL_set_session takes its own reference, so the old socket may replace it afterwards.
|
||||
Lock l( oldSocket->mSessionMutex );
|
||||
if ( oldSocket->mSession )
|
||||
SSL_set_session( mSSL, oldSocket->mSession );
|
||||
}
|
||||
|
||||
// Set the SSL to automatically retry on failure.
|
||||
SSL_set_mode( mSSL, SSL_MODE_AUTO_RETRY );
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define EE_NETWORKCOPENLSSLSOCKET_HPP
|
||||
|
||||
#include <eepp/network/ssl/sslsocketimpl.hpp>
|
||||
#include <eepp/system/mutex.hpp>
|
||||
|
||||
#ifdef EE_OPENSSL
|
||||
|
||||
@@ -23,6 +24,8 @@ extern "C" {
|
||||
|
||||
namespace EE { namespace Network { namespace SSL {
|
||||
|
||||
using namespace EE::System;
|
||||
|
||||
class OpenSSLSocket : public SSLSocketImpl {
|
||||
public:
|
||||
static bool init();
|
||||
@@ -50,8 +53,17 @@ class OpenSSLSocket : public SSLSocketImpl {
|
||||
bool mConnected;
|
||||
Socket::Status mStatus;
|
||||
int mMaxCertChainDepth;
|
||||
// The latest resumable session, delivered by newSessionCb: at the handshake for TLS 1.2, and
|
||||
// in NewSessionTicket messages after it for TLS 1.3. Sockets restoring this session read it
|
||||
// under mSessionMutex. It outlives the connection and is released on reconnect or destruction.
|
||||
SSL_SESSION* mSession;
|
||||
Mutex mSessionMutex;
|
||||
|
||||
void releaseSession();
|
||||
|
||||
private:
|
||||
static int newSessionCb( ::SSL* ssl, SSL_SESSION* session );
|
||||
|
||||
static int certVerifyCb( X509_STORE_CTX* x509_ctx, void* arg );
|
||||
|
||||
static bool matchHostname( const char* name, const char* hostname );
|
||||
|
||||
@@ -25,7 +25,7 @@ EE_MAIN_FUNC int main( int argc, char* argv[] ) {
|
||||
{ 'c', "continue" } );
|
||||
args::Flag compressed( parser, "compressed", "Request compressed response", { "compressed" } );
|
||||
args::ValueFlagList<std::string> postData( parser, "data", "HTTP POST data",
|
||||
{ 'd', "data", "data-raw" } );
|
||||
{ 'd', "data" } );
|
||||
args::ValueFlagList<std::string> postDataRaw( parser, "data-raw", "HTTP POST data RAW",
|
||||
{ "data-raw" } );
|
||||
args::ValueFlagList<std::string> postUrlEncode(
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <cstring>
|
||||
#include <eepp/network/ssl/sslsocket.hpp>
|
||||
#include <eepp/network/tcplistener.hpp>
|
||||
#include <eepp/system/clock.hpp>
|
||||
#include <eepp/system/process.hpp>
|
||||
#include <eepp/system/sys.hpp>
|
||||
#include <thread>
|
||||
@@ -14,9 +15,11 @@ using namespace EE::System;
|
||||
|
||||
namespace {
|
||||
|
||||
// openssl s_server restricted to one protocol ("-tls1_2" or "-tls1_3"). Its -www status page
|
||||
// reports "New, TLSv1.x, ..." for a full handshake and "Reused, TLSv1.x, ..." for a resumption.
|
||||
class LocalTLSServer {
|
||||
public:
|
||||
LocalTLSServer() {
|
||||
explicit LocalTLSServer( const std::string& protocol ) {
|
||||
const std::string openssl = Sys::which( "openssl" );
|
||||
if ( openssl.empty() )
|
||||
return;
|
||||
@@ -33,7 +36,7 @@ class LocalTLSServer {
|
||||
reservation.close();
|
||||
if ( !mProcess.create(
|
||||
openssl, { "s_server", "-accept", "127.0.0.1:" + String::toString( mPort ),
|
||||
"-cert", mCertificate, "-key", key, "-www", "-quiet", "-tls1_2" } ) )
|
||||
"-cert", mCertificate, "-key", key, "-www", "-quiet", protocol } ) )
|
||||
return;
|
||||
for ( int attempt = 0; attempt < 100; ++attempt ) {
|
||||
TcpSocket probe;
|
||||
@@ -98,39 +101,102 @@ class TLSCertificateScope {
|
||||
std::string mOriginal;
|
||||
};
|
||||
|
||||
// Sends a status-page request and returns its "New, ..." or "Reused, ..." line. It stops reading
|
||||
// there: a socket that sees the server close discards its session.
|
||||
std::string requestStatusLine( SSL::SSLSocket& socket ) {
|
||||
// connect() clears its timeouts, and a restored session's handshake runs inside send().
|
||||
socket.setSendTimeout( Seconds( 5 ) );
|
||||
socket.setReceiveTimeout( Seconds( 5 ) );
|
||||
const char request[] = "GET / HTTP/1.0\r\nHost: localhost\r\n\r\n";
|
||||
if ( socket.send( request, sizeof( request ) - 1 ) != Socket::Done )
|
||||
return {};
|
||||
std::string response;
|
||||
char buffer[1024];
|
||||
Clock clock;
|
||||
while ( response.size() < 65536 && clock.getElapsedTime() < Seconds( 5 ) ) {
|
||||
size_t received = 0;
|
||||
// Blocking reads must not surface TLS 1.3 NewSessionTicket processing as NotReady.
|
||||
if ( socket.receive( buffer, sizeof( buffer ), received ) != Socket::Done )
|
||||
break;
|
||||
response.append( buffer, received );
|
||||
size_t start = response.find( "\nNew, " );
|
||||
if ( start == std::string::npos )
|
||||
start = response.find( "\nReused, " );
|
||||
size_t end = start == std::string::npos ? start : response.find( '\n', start + 1 );
|
||||
if ( end != std::string::npos )
|
||||
return response.substr( start + 1, end - start - 1 );
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
bool requireServer( const LocalTLSServer& server ) {
|
||||
if ( server.available() )
|
||||
return true;
|
||||
const char* required = std::getenv( "EEPP_REQUIRE_TLS_TESTS" );
|
||||
return !( required && std::strcmp( required, "1" ) == 0 );
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
UTEST( TLSSecurity, HTTPSAcceptsTrustedPeerAndRejectsWrongHostAndUntrustedCertificate ) {
|
||||
if ( !SSL::SSLSocket::isSupported() )
|
||||
UTEST_SKIP( "TLS backend disabled" );
|
||||
LocalTLSServer server;
|
||||
if ( !server.available() ) {
|
||||
const char* required = std::getenv( "EEPP_REQUIRE_TLS_TESTS" );
|
||||
ASSERT_FALSE_MSG( required && std::strcmp( required, "1" ) == 0,
|
||||
"Could not start the required loopback OpenSSL TLS server" );
|
||||
UTEST_SKIP( "OpenSSL CLI with req -addext and s_server is required" );
|
||||
}
|
||||
TLSCertificateScope trust;
|
||||
{
|
||||
auto socket = TLSCertificateScope::socket( server.certificate(), "localhost" );
|
||||
ASSERT_EQ( socket->connect( IpAddress::LocalHost, server.port(), Seconds( 5 ) ),
|
||||
Socket::Done );
|
||||
const char request[] = "GET / HTTP/1.0\r\nHost: localhost\r\n\r\n";
|
||||
ASSERT_EQ( socket->send( request, sizeof( request ) - 1 ), Socket::Done );
|
||||
char response[1024];
|
||||
size_t received = 0;
|
||||
ASSERT_EQ( socket->receive( response, sizeof( response ), received ), Socket::Done );
|
||||
ASSERT_GE( received, 5u );
|
||||
EXPECT_EQ( std::memcmp( response, "HTTP/", 5 ), 0 );
|
||||
}
|
||||
{
|
||||
auto socket = TLSCertificateScope::socket( server.certificate(), "wrong.invalid" );
|
||||
EXPECT_NE( socket->connect( IpAddress::LocalHost, server.port(), Seconds( 5 ) ),
|
||||
Socket::Done );
|
||||
}
|
||||
{
|
||||
auto socket = TLSCertificateScope::socket( server.otherCertificate(), "localhost" );
|
||||
EXPECT_NE( socket->connect( IpAddress::LocalHost, server.port(), Seconds( 5 ) ),
|
||||
Socket::Done );
|
||||
for ( const char* protocol : { "-tls1_2", "-tls1_3" } ) {
|
||||
LocalTLSServer server( protocol );
|
||||
ASSERT_TRUE_MSG( requireServer( server ),
|
||||
"Could not start the required loopback OpenSSL TLS server" );
|
||||
if ( !server.available() )
|
||||
UTEST_SKIP( "OpenSSL CLI with req -addext and s_server is required" );
|
||||
const std::string version = protocol[6] == '2' ? "TLSv1.2" : "TLSv1.3";
|
||||
TLSCertificateScope trust;
|
||||
{
|
||||
auto socket = TLSCertificateScope::socket( server.certificate(), "localhost" );
|
||||
ASSERT_EQ( socket->connect( IpAddress::LocalHost, server.port(), Seconds( 5 ) ),
|
||||
Socket::Done );
|
||||
// The server accepts only `version`, and reports what was negotiated.
|
||||
EXPECT_STDSTREQ( requestStatusLine( *socket ).substr( 0, 12 ),
|
||||
"New, " + version );
|
||||
}
|
||||
{
|
||||
auto socket = TLSCertificateScope::socket( server.certificate(), "wrong.invalid" );
|
||||
EXPECT_NE( socket->connect( IpAddress::LocalHost, server.port(), Seconds( 5 ) ),
|
||||
Socket::Done );
|
||||
}
|
||||
{
|
||||
auto socket = TLSCertificateScope::socket( server.otherCertificate(), "localhost" );
|
||||
EXPECT_NE( socket->connect( IpAddress::LocalHost, server.port(), Seconds( 5 ) ),
|
||||
Socket::Done );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UTEST( TLSSecurity, RestoredSessionsResumeOnTLS12AndTLS13 ) {
|
||||
// FTPS data connections restore the control connection's session, and servers such as
|
||||
// vsftpd (require_ssl_reuse) reject data connections that do not resume it. TLS 1.3 can
|
||||
// only resume from a NewSessionTicket, which arrives after the handshake.
|
||||
if ( !SSL::SSLSocket::isSupported() )
|
||||
UTEST_SKIP( "TLS backend disabled" );
|
||||
for ( const char* protocol : { "-tls1_2", "-tls1_3" } ) {
|
||||
LocalTLSServer server( protocol );
|
||||
ASSERT_TRUE_MSG( requireServer( server ),
|
||||
"Could not start the required loopback OpenSSL TLS server" );
|
||||
if ( !server.available() )
|
||||
UTEST_SKIP( "OpenSSL CLI with req -addext and s_server is required" );
|
||||
const std::string version = protocol[6] == '2' ? "TLSv1.2" : "TLSv1.3";
|
||||
TLSCertificateScope trust;
|
||||
auto control = TLSCertificateScope::socket( server.certificate(), "localhost" );
|
||||
ASSERT_EQ( control->connect( IpAddress::LocalHost, server.port(), Seconds( 5 ) ),
|
||||
Socket::Done );
|
||||
EXPECT_STDSTREQ( requestStatusLine( *control ).substr( 0, 12 ),
|
||||
"New, " + version );
|
||||
// s_server handles one connection at a time, so close this one; the socket keeps its
|
||||
// session for the restoring socket, as an FTPS control socket does.
|
||||
control->disconnect();
|
||||
std::unique_ptr<SSL::SSLSocket> data(
|
||||
SSL::SSLSocket::New( "localhost", true, true, control.get() ) );
|
||||
ASSERT_EQ( data->connect( IpAddress::LocalHost, server.port(), Seconds( 5 ) ),
|
||||
Socket::Done );
|
||||
EXPECT_STDSTREQ( requestStatusLine( *data ).substr( 0, 15 ),
|
||||
"Reused, " + version );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1004,6 +1004,13 @@
|
||||
#endif
|
||||
#define MBEDTLS_THREADING_IMPL // undef at the end of this paragraph
|
||||
#endif
|
||||
/* eepp: Win32 SRWLOCK mutexes, see threading.c. */
|
||||
#if defined(MBEDTLS_THREADING_WIN32)
|
||||
#if !defined(MBEDTLS_THREADING_C) || defined(MBEDTLS_THREADING_IMPL) || !defined(_WIN32)
|
||||
#error "MBEDTLS_THREADING_WIN32 defined, but not all prerequisites"
|
||||
#endif
|
||||
#define MBEDTLS_THREADING_IMPL // undef at the end of this paragraph
|
||||
#endif
|
||||
#if defined(MBEDTLS_THREADING_C) && !defined(MBEDTLS_THREADING_IMPL)
|
||||
#error "MBEDTLS_THREADING_C defined, single threading implementation required"
|
||||
#endif
|
||||
|
||||
+15
-7
@@ -4462,14 +4462,22 @@
|
||||
// Disable deprecated
|
||||
#define MBEDTLS_DEPRECATED_REMOVED
|
||||
|
||||
// mbedTLS 3.6 finally enabled TLSv1.3 by default, but it requires some mobule
|
||||
// changes, and to enable PSA crypto (new "standard" API specification).
|
||||
// Disable it for now.
|
||||
#undef MBEDTLS_SSL_PROTO_TLS1_3
|
||||
|
||||
// Disable PSA Crypto.
|
||||
// TLS 1.2 and 1.3 are both enabled (upstream defaults). TLS 1.3 uses PSA crypto, which
|
||||
// MbedTLSSocket initializes with psa_crypto_init(). Mechanisms come from this legacy config
|
||||
// (no MBEDTLS_PSA_CRYPTO_CONFIG), and the classic APIs keep their own implementations
|
||||
// (no MBEDTLS_USE_PSA_CRYPTO), so TLS 1.2 and libssh2 do not depend on PSA.
|
||||
#undef MBEDTLS_PSA_CRYPTO_CONFIG
|
||||
#undef MBEDTLS_PSA_CRYPTO_C
|
||||
// No persistent PSA keys: nothing is written to disk.
|
||||
#undef MBEDTLS_PSA_CRYPTO_STORAGE_C
|
||||
#undef MBEDTLS_PSA_ITS_FILE_C
|
||||
#undef MBEDTLS_LMS_C
|
||||
|
||||
// With TLS 1.3, threads that each use their own TLS context still share PSA's global key
|
||||
// store, so a multithreaded program must enable MBEDTLS_THREADING_C. MBEDTLS_THREADING_WIN32 is
|
||||
// an eepp addition (threading.c) with statically initialized SRWLOCK mutexes.
|
||||
#define MBEDTLS_THREADING_C
|
||||
#if defined(_WIN32)
|
||||
#define MBEDTLS_THREADING_WIN32
|
||||
#else
|
||||
#define MBEDTLS_THREADING_PTHREAD
|
||||
#endif
|
||||
|
||||
@@ -39,6 +39,15 @@ typedef struct mbedtls_threading_mutex_t {
|
||||
} mbedtls_threading_mutex_t;
|
||||
#endif
|
||||
|
||||
/* eepp: Win32 mutexes. The lock is an SRWLOCK, which is pointer-sized and valid when zeroed;
|
||||
* it is stored as void * so this header does not include <windows.h>. */
|
||||
#if defined(MBEDTLS_THREADING_WIN32)
|
||||
typedef struct mbedtls_threading_mutex_t {
|
||||
void *MBEDTLS_PRIVATE(lock);
|
||||
char MBEDTLS_PRIVATE(state);
|
||||
} mbedtls_threading_mutex_t;
|
||||
#endif
|
||||
|
||||
#if defined(MBEDTLS_THREADING_ALT)
|
||||
/* You should define the mbedtls_threading_mutex_t type in your header */
|
||||
#include "threading_alt.h"
|
||||
|
||||
+59
@@ -110,6 +110,65 @@ int (*mbedtls_mutex_unlock)(mbedtls_threading_mutex_t *) = threading_mutex_unloc
|
||||
|
||||
#endif /* MBEDTLS_THREADING_PTHREAD */
|
||||
|
||||
/* eepp: Win32 SRWLOCK mutexes. Like the pthread implementation, the global mutexes are
|
||||
* initialized statically (a zeroed SRWLOCK is unlocked), so no setup call is needed before
|
||||
* the library is used. Mbed TLS mutexes are not recursive, matching SRWLOCK. */
|
||||
#if defined(MBEDTLS_THREADING_WIN32)
|
||||
#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600
|
||||
#undef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0600 /* SRWLOCK requires Windows Vista */
|
||||
#endif
|
||||
#include <windows.h>
|
||||
|
||||
static void threading_mutex_init_win32(mbedtls_threading_mutex_t *mutex)
|
||||
{
|
||||
if (mutex == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
InitializeSRWLock((PSRWLOCK) &mutex->MBEDTLS_PRIVATE(lock));
|
||||
mutex->MBEDTLS_PRIVATE(state) = 1;
|
||||
}
|
||||
|
||||
static void threading_mutex_free_win32(mbedtls_threading_mutex_t *mutex)
|
||||
{
|
||||
if (mutex == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* An SRWLOCK owns no resources. */
|
||||
mutex->MBEDTLS_PRIVATE(state) = 0;
|
||||
}
|
||||
|
||||
static int threading_mutex_lock_win32(mbedtls_threading_mutex_t *mutex)
|
||||
{
|
||||
if (mutex == NULL) {
|
||||
return MBEDTLS_ERR_THREADING_BAD_INPUT_DATA;
|
||||
}
|
||||
|
||||
AcquireSRWLockExclusive((PSRWLOCK) &mutex->MBEDTLS_PRIVATE(lock));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int threading_mutex_unlock_win32(mbedtls_threading_mutex_t *mutex)
|
||||
{
|
||||
if (mutex == NULL) {
|
||||
return MBEDTLS_ERR_THREADING_BAD_INPUT_DATA;
|
||||
}
|
||||
|
||||
ReleaseSRWLockExclusive((PSRWLOCK) &mutex->MBEDTLS_PRIVATE(lock));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void (*mbedtls_mutex_init)(mbedtls_threading_mutex_t *) = threading_mutex_init_win32;
|
||||
void (*mbedtls_mutex_free)(mbedtls_threading_mutex_t *) = threading_mutex_free_win32;
|
||||
int (*mbedtls_mutex_lock)(mbedtls_threading_mutex_t *) = threading_mutex_lock_win32;
|
||||
int (*mbedtls_mutex_unlock)(mbedtls_threading_mutex_t *) = threading_mutex_unlock_win32;
|
||||
|
||||
#define MUTEX_INIT = { NULL, 1 }
|
||||
|
||||
#endif /* MBEDTLS_THREADING_WIN32 */
|
||||
|
||||
#if defined(MBEDTLS_THREADING_ALT)
|
||||
static int threading_mutex_fail(mbedtls_threading_mutex_t *mutex)
|
||||
{
|
||||
|
||||
@@ -52,8 +52,9 @@ EE_MAIN_FUNC int main( int argc, char* argv[] ) {
|
||||
"When enabled in the case of an atlas not having enough space in the image to fit all the "
|
||||
"source input images it will create new child atlas images to save them.",
|
||||
{ "allow-children" } );
|
||||
args::ValueFlag<Uint32> height( parser, "max-width", "Texture Atlas maximum allowed height.",
|
||||
{ 'h', "max-height" }, 4096, args::Options::Single );
|
||||
// -h is --help; args rejects duplicate flag names.
|
||||
args::ValueFlag<Uint32> height( parser, "max-height", "Texture Atlas maximum allowed height.",
|
||||
{ "max-height" }, 4096, args::Options::Single );
|
||||
args::ValueFlag<Uint32> width( parser, "max-width", "Texture Atlas maximum allowed width.",
|
||||
{ 'w', "max-width" }, 4096, args::Options::Single );
|
||||
args::ValueFlag<Uint32> pixelsBorder(
|
||||
|
||||
Reference in New Issue
Block a user