Skip to content

Commit a5e125a

Browse files
authored
feat: add compat.openssl 3.5.1 + asio SSL/TLS support (#124)
* docs: add OpenSSL + Asio SSL/TLS design spec and implementation plan * feat(pkg): add compat.openssl 3.5.1 descriptor (install()-driven build) * fix(pkg): remove xim:make dep from macosx (linux-only, macOS has system make) * fix(pkg): fix OpenSSL install() — prefix, pcall, RANLIB overrides * feat(pkg): add ssl feature to chriskohlhoff.asio (MCPP_FEATURE_SSL guard) * test: add SSL echo test with embedded PEM (const_buffer API) * fix(test): guard ssl.cpp with MCPP_FEATURE_SSL for no-op fallback Without the ssl feature active, ssl.cpp compiles to a trivially-passing no-op (int main() { return 0; }). This keeps the workspace green while compat.openssl is unpublished (xlings#374 prevents two local-path index repos for cross-namespace resolution). * fix(pkg): remove rfc2818_verification, replace verify_* using with inline constexpr rfc2818_verification does not exist in standalone asio 1.38.1. verify_none/verify_peer/verify_fail_if_no_peer_cert are const int with internal linkage — cannot be exported via 'using'. Replace with inline constexpr declarations backed by the OpenSSL SSL_VERIFY_* macros. * fix(pkg): remove unexportable verify_* constants from ssl module verify_* are const int with internal linkage — cannot be exported via using or inline constexpr (re-declaration conflicts with global module fragment). Keep only types (context, context_base, stream, verify_mode) and host_name_verification function. * fix(pkg): add stream_base to ssl module exports * fix(pkg): add verify_context and ssl::error::stream_errors to ssl module exports
1 parent 7fef5ec commit a5e125a

4 files changed

Lines changed: 564 additions & 0 deletions

File tree

Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
# Add OpenSSL package + Asio SSL support
2+
3+
> Created: 2026-07-26 · Status: design
4+
> Repo: `mcpplibs/mcpp-index` · Branch: `feat/add-openssl-asio-tls`
5+
6+
## 1. Motivation
7+
8+
The mcpp ecosystem needs TLS support. `chriskohlhoff.asio@1.38.1` (C++23
9+
module wrapper) already ships Asio's full source tree but explicitly excludes
10+
`asio/ssl/*.hpp` because SSL requires an external crypto library. This design
11+
adds `compat.openssl` as a new static library package and extends
12+
`chriskohlhoff.asio` with an opt-in `ssl` feature.
13+
14+
mbedTLS (`compat.mbedtls@3.6.1`) already exists in the index but **cannot**
15+
serve as asio's SSL dependency: asio::ssl is hard-coded against the OpenSSL C
16+
API (~95 distinct identifiers across SSL_CTX, SSL, BIO, ERR, X509, EVP, PEM,
17+
DH, RSA, CRYPTO), and mbedTLS provides no OpenSSL compatibility layer
18+
(its native API is entirely different: `mbedtls_ssl_*`, `mbedtls_x509_*`, etc.).
19+
20+
## 2. Scope
21+
22+
### In scope
23+
- New package `compat.openssl@3.5.1` (latest LTS, supported to 2030-04-08)
24+
- Opt-in `ssl` feature on `chriskohlhoff.asio@1.38.1`
25+
- Consumer test for asio SSL (TCP echo over TLS)
26+
27+
### Out of scope
28+
- TLS as an abstract capability (like `blas`) — deferred until a second TLS
29+
provider exists
30+
- wolfSSL, BoringSSL, LibreSSL packages
31+
- QUIC or TLS 1.3-only API exposure in the module wrapper
32+
- Changes to `index.toml` or `min_mcpp` version
33+
- Windows support (requires prebuilt MSVC binaries, not yet prepared)
34+
35+
## 3. Package: compat.openssl
36+
37+
### 3.1 Identity
38+
39+
| Field | Value |
40+
|---|---|
41+
| namespace | `compat` |
42+
| name | `compat.openssl` |
43+
| version | `3.5.1` |
44+
| license | `Apache-2.0` |
45+
| repo | `https://github.com/openssl/openssl` |
46+
| type | Form B (inline, install()-driven build) |
47+
48+
### 3.2 Build strategy
49+
50+
OpenSSL's build system (Perl `Configure` + GNU Make) cannot be expressed as a
51+
flat source glob. Follow the `compat.openblas` pattern: an `install()` Lua hook
52+
drives the external build and emits an anchor `.c` TU whose absence triggers
53+
mcpp to run `install()` before compilation.
54+
55+
```
56+
install() flow:
57+
1. perl Configure no-shared no-dso no-tests no-apps no-engine
58+
--prefix=<prefix> --openssldir=<prefix>/ssl
59+
2. make -j$(nproc)
60+
3. make install_sw
61+
4. Emit mcpp_openssl_anchor.c
62+
```
63+
64+
### 3.3 Platform strategy
65+
66+
| Platform | Approach | Notes |
67+
|---|---|---|
68+
| Linux | Source build via install() | Build dep `xim:make@latest`; system Perl expected at `/usr/bin/perl` |
69+
| macOS | Source build via install() | Same as Linux; static libs only (`no-shared`) |
70+
| Windows | Deferred | Prebuilt zip (follow `compat.openblas` precedent) requires preparing MSVC static builds for xlings-res; not in initial scope |
71+
72+
The `./config` convenience wrapper auto-detects the target platform (equivalent
73+
to `perl Configure <auto-detected-target>`).
74+
75+
### 3.4 Build artifacts
76+
77+
| File | Content |
78+
|---|---|
79+
| `lib/libcrypto.a` | EVP, X509, ASN1, BIO, ERR, RSA, EC, SHA, AES, RAND, ... |
80+
| `lib/libssl.a` | TLS/DTLS protocol (depends on libcrypto) |
81+
| `include/openssl/*.h` | Public API headers |
82+
83+
### 3.5 Descriptor skeleton
84+
85+
```lua
86+
package = {
87+
spec = "1", namespace = "compat", name = "compat.openssl",
88+
description = "OpenSSL — TLS/crypto library (static, install()-driven build)",
89+
licenses = {"Apache-2.0"},
90+
repo = "https://github.com/openssl/openssl",
91+
type = "package",
92+
xpm = {
93+
linux = { deps = { "xim:make@latest" }, ["3.5.1"] = { url = {...}, sha256 = "529043b15cffa5f36077a4d0af83f3de399807181d607441d734196d889b641f" } },
94+
macosx = { deps = { "xim:make@latest" }, ["3.5.1"] = { url = {...}, sha256 = "529043b15cffa5f36077a4d0af83f3de399807181d607441d734196d889b641f" } },
95+
-- windows deferred (prebuilt zip not yet prepared)
96+
},
97+
mcpp = {
98+
language = "c++23", import_std = false, c_standard = "c11",
99+
sources = { "mcpp_openssl_anchor.c" },
100+
targets = { ["openssl"] = { kind = "lib" } },
101+
include_dirs = { "include" },
102+
deps = {},
103+
linux = { ldflags = { "-Llib", "-lssl", "-lcrypto" } },
104+
macosx = { ldflags = { "-Llib", "-lssl", "-lcrypto" } },
105+
},
106+
}
107+
```
108+
109+
### 3.6 URL / mirror
110+
111+
Canonical upstream tarball:
112+
- GLOBAL: `https://github.com/openssl/openssl/releases/download/openssl-3.5.1/openssl-3.5.1.tar.gz`
113+
- CN: `https://gitcode.com/mcpp-res/openssl/releases/download/3.5.1/openssl-3.5.1.tar.gz`
114+
115+
Windows prebuilt zip — deferred (requires preparing MSVC static builds for xlings-res; not in initial scope).
116+
117+
## 4. Package: chriskohlhoff.asio (modified)
118+
119+
### 4.1 New feature: `ssl`
120+
121+
```lua
122+
features = {
123+
["default"] = { implies = { "separate-compilation" } },
124+
["separate-compilation"] = { ... unchanged ... },
125+
["ssl"] = {
126+
defines = { "MCPP_FEATURE_SSL" },
127+
deps = { ["compat.openssl"] = "3.5.1" },
128+
sources = { "*/src/asio_ssl.cpp" },
129+
},
130+
},
131+
```
132+
133+
`ssl` is NOT in the `default` feature set. Consumers opt in explicitly:
134+
```toml
135+
[dependencies.chriskohlhoff]
136+
asio = { version = "1.38.1", features = ["ssl"] }
137+
```
138+
139+
When `ssl` is active:
140+
- `MCPP_FEATURE_SSL` is defined (propagated to consumer TUs)
141+
- `compat.openssl@3.5.1` is pulled in as a dependency
142+
- `#ifdef MCPP_FEATURE_SSL` guards in `asio.cppm` activate SSL includes + exports
143+
144+
### 4.2 Feature-gated .cppm strategy
145+
146+
`generated_files` cannot be placed inside a feature block (xpkg features support
147+
`sources`, `defines`, `flags`, `implies`, `deps`, `requires`, `provides` — not
148+
`generated_files`). Instead, the single `.cppm` uses `#ifdef MCPP_FEATURE_SSL`
149+
guards. When the `ssl` feature is disabled, the preprocessor strips the SSL
150+
blocks and OpenSSL headers are never included. When enabled, `compat.openssl`
151+
provides the headers and the guards activate.
152+
153+
### 4.3 Module wrapper additions (guarded by MCPP_FEATURE_SSL)
154+
155+
Added to `asio.cppm` after the existing includes:
156+
```cpp
157+
#ifdef MCPP_FEATURE_SSL
158+
#include <asio/ssl.hpp>
159+
#include <asio/ssl/context.hpp>
160+
#include <asio/ssl/stream.hpp>
161+
#include <asio/ssl/error.hpp>
162+
#endif
163+
```
164+
165+
Added to the export block:
166+
```cpp
167+
#ifdef MCPP_FEATURE_SSL
168+
export namespace asio::ssl {
169+
using ::asio::ssl::context;
170+
using ::asio::ssl::context_base;
171+
using ::asio::ssl::stream;
172+
using ::asio::ssl::verify_mode;
173+
using ::asio::ssl::verify_none;
174+
using ::asio::ssl::verify_peer;
175+
using ::asio::ssl::verify_fail_if_no_peer_cert;
176+
using ::asio::ssl::rfc2818_verification;
177+
using ::asio::ssl::host_name_verification;
178+
}
179+
#endif
180+
```
181+
182+
## 5. Consumer test
183+
184+
New test file: `tests/examples/asio-module/tests/ssl.cpp`
185+
186+
Pattern: TCP echo over TLS — a `stream<ip::tcp::socket>` wrapped around a
187+
plain socket. PEM cert+key embedded as C++ string literals, loaded via
188+
`context::use_certificate(const_buffer, pem)` + `context::use_private_key(const_buffer, pem)`.
189+
190+
The test is feature-gated: only compiled when the `ssl` feature is active.
191+
The existing `mcpp.toml` in `tests/examples/asio-module/` adds the `ssl`
192+
feature to its dependency declaration.
193+
194+
## 6. Validation contract
195+
196+
Before PR:
197+
1. `compat.openssl` descriptor passes local Lua lint
198+
2. `compat.openssl` builds from source on macOS (GLOBAL mirror)
199+
3. `chriskohlhoff.asio` with `ssl` feature resolves and builds
200+
4. `mcpp test -p asio-module` passes all existing tests
201+
5. New `ssl.cpp` test passes (TLS echo)
202+
6. `git diff --check` clean
203+
204+
## 7. Implementation order
205+
206+
| Step | Description |
207+
|---|---|
208+
| 1 | Create `pkgs/c/compat.openssl.lua` |
209+
| 2 | Local build test of `compat.openssl` |
210+
| 3 | Modify `pkgs/c/chriskohlhoff.asio.lua` — add ssl feature |
211+
| 4 | Add `tests/examples/asio-module/tests/ssl.cpp` |
212+
| 5 | Update `tests/examples/asio-module/mcpp.toml` |
213+
| 6 | Full `mcpp test -p asio-module` verification |
214+
215+
## 8. Future: TLS capability
216+
217+
When a second TLS provider exists (e.g., `compat.wolfssl`), extract an abstract
218+
`tls` capability following the `blas` pattern:
219+
220+
```lua
221+
-- compat.openssl
222+
provides = { "tls" }
223+
224+
-- chriskohlhoff.asio ssl feature
225+
["ssl"] = { requires = { "tls" }, deps = { ... } }
226+
```
227+
228+
Consumers select via `[capabilities] tls = "compat.openssl"`. Not in scope now.

pkgs/c/chriskohlhoff.asio.lua

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,12 @@ module;
150150
#include <asio/experimental/use_promise.hpp>
151151
#include <asio/experimental/parallel_group.hpp>
152152
#include <asio/experimental/awaitable_operators.hpp>
153+
#ifdef MCPP_FEATURE_SSL
154+
#include <asio/ssl.hpp>
155+
#include <asio/ssl/context.hpp>
156+
#include <asio/ssl/stream.hpp>
157+
#include <asio/ssl/error.hpp>
158+
#endif
153159
154160
export module asio;
155161
@@ -241,6 +247,24 @@ using ::asio::this_coro::throw_if_cancelled;
241247
using ::asio::this_coro::reset_cancellation_state;
242248
}
243249
250+
#ifdef MCPP_FEATURE_SSL
251+
export namespace asio::ssl {
252+
using ::asio::ssl::context;
253+
using ::asio::ssl::context_base;
254+
using ::asio::ssl::stream;
255+
using ::asio::ssl::stream_base;
256+
using ::asio::ssl::verify_context;
257+
using ::asio::ssl::verify_mode;
258+
using ::asio::ssl::host_name_verification;
259+
}
260+
261+
export namespace asio::ssl::error {
262+
using ::asio::ssl::error::stream_errors;
263+
using ::asio::ssl::error::make_error_code;
264+
// stream_category is static const ref (internal linkage) — can't export.
265+
}
266+
#endif
267+
244268
]==],
245269
},
246270
sources = {
@@ -267,6 +291,11 @@ using ::asio::this_coro::reset_cancellation_state;
267291
"ASIO_HAS_THREADS",
268292
},
269293
},
294+
["ssl"] = {
295+
defines = { "MCPP_FEATURE_SSL" },
296+
deps = { ["compat.openssl"] = "3.5.1" },
297+
sources = { "*/src/asio_ssl.cpp" },
298+
},
270299
},
271300
deps = {},
272301
-- POSIX threading is detected by asio from unistd.h feature macros;

0 commit comments

Comments
 (0)