aboutsummaryrefslogtreecommitdiff
path: root/docs/CHAT-OPENSSL-MIGRATION.txt
blob: 17149ac14eb3e3488e2a80dc61939fc1b8a8b7ae (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.


OPENSSL BACKEND MIGRATION RECORD

    Date: 2026-10-30. Branch: feature/private-chat.
    Scope: a compatibility and dependency-security experiment, not a messenger.
    Main and production are unchanged. No real identity files are created.

DECISION AND FIXED ALGORITHMS

    Retain Sequoia OpenPGP 2.4.2 and RFC 9980 ML-KEM-1024 + X448 encryption.
    Retain ML-DSA-87 + Ed448 signatures, OpenPGP v6 keys, and AES-256 content
    encryption. Change the cryptographic backend, not the algorithms or wire
    protocol. Probe assertions reject an unexpected backend or key algorithms.

    The previous Rust backend reached cx448 0.1.1 -> crypto-bigint 0.5.5 during
    curve arithmetic. It also included rsa 0.9.10. See CHAT-SECURITY-REVIEW.txt
    for the original reachability investigation. Neither RustSec issue was
    ignored. No mathematical implementation was patched locally.

    The current manifest enables only Sequoia's crypto-openssl feature. The
    allow-experimental-crypto and allow-variable-time-crypto opt-ins are gone.
    The resolved graph has no cx448, crypto-bigint, or rsa crate. This removes
    those Rust backend dependencies; it does not prove that all side channels
    are absent from a browser or that external C dependencies have no defects.

VERSIONS AND SOURCE PROVENANCE

    Rust toolchain: 1.99.1, pinned in rust-toolchain.toml.
    Sequoia OpenPGP: 2.4.2, exact requirement and Cargo.lock.
    OpenSSL: 3.6.5, native host library and source-built static WASI libraries.
    WASI SDK: 34.0 x86_64 Linux, bundled Clang/libclang 23.1.0-wasi-sdk.
    Browser test runner: Playwright 1.64.1, Chromium 156.0.8078.4.

    SDK archive:
        https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-34/wasi-sdk-34.0-x86_64-linux.tar.gz
        SHA-256 b761e3a0721dbae9c09a0059e5fdb2bf917d1b4a8a7b430fb3b5aafb0984b2c4

    OpenSSL archive:
        https://github.com/openssl/openssl/releases/download/openssl-3.6.5/openssl-3.6.5.tar.gz
        SHA-256 a2157c2830efdec3788939b00c9b0638306d3f0bbb76dc4832ee503bb397df98

    Digests were checked against upstream GitHub release asset metadata. The
    build script verifies each archive before extraction. Hash checking pins
    these inputs; it is not a claim that upstream release signatures were
    independently verified or that output is bit-for-bit reproducible across
    hosts. Archives, SDK, libraries, and build products stay under ignored
    .tools/ and target/. The native development library is supplied by the OS.

WHY WASI

    The original Rust-backend proof used wasm32-unknown-unknown and generated
    wasm-bindgen JavaScript. The OpenSSL proof uses a wasm32-wasip1 command
    module and a small explicit browser WASI bridge. The Rust command calls
    the same compatibility_probe function used by native tests.

    The browser harness loads the new WASI binary directly, not old generated
    glue. It requires the output to identify OpenSSL 3.6.5, preventing a stale
    Rust-backend artifact from being accepted as evidence of OpenSSL support.
    Old browser-build commands are historical and must not be reused here.

BUILD CONFIGURATION AND BOUNDARIES

    infra/chat/openssl-wasi.conf adds a build target inheriting BASE_unix with
    little-endian and 32-bit bignum configuration. It changes configuration,
    not OpenSSL's cryptographic source routines. C code is compiled at -O2.
    No third-party rand.patch, unconditional entropy-success patch, or custom
    random-number generator is applied. A SHA-256 comparison of all 5889 original
    regular files against the downloaded OpenSSL archive found no changed or
    missing originals after the build; only the separate target configuration
    was added. OpenSSL 3.6.5 already supports WASI
    getentropy in providers/implementations/rands/seeding/rand_unix.c.

    Configure selects --with-rand-seed=getrandom. WASI libc's entropy request
    reaches wasi_snapshot_preview1.random_get. The browser bridge services it
    exclusively through crypto.getRandomValues, splitting requests at 65536
    bytes. There is no Math.random, fixed seed, or success-on-failure fallback.
    The negative test replaces that API with a failure and requires rejection.

    Build options disable assembly, async operations, automatic config loading,
    DSO/modules, POSIX I/O, secure-memory arenas, shared libraries, sockets,
    C stdio, thread pools, threads, and interactive console UI. They avoid
    unsupported host capabilities and use static libraries. Disabling the
    secure-memory arena means ordinary WASM linear memory is used; it does not
    establish secure erasure, locked pages, or protection from delivered JS.
    Disabling C stdio does not disable the Rust command's captured output.

    _WASI_EMULATED_GETPID and libwasi-emulated-getpid supply the SDK's process-ID
    emulation. getuid/geteuid/getgid/getegid map to getpagesize, following the
    common WASI port configuration: the browser module has no real OS user IDs
    or privilege boundary. These values are not used as randomness or identity
    credentials. This is an explicit portability assumption, not a general
    POSIX security emulation layer.

    Rust bindings use the SDK's libclang and WASI sysroot with target
    wasm32-wasip1 and -fvisibility=default. Without explicit visibility, the
    initial bindgen attempt omitted function declarations. Rust's bundled WASI
    libc search path precedes the SDK libraries: reversing that order initially
    failed to link __wasi_init_tp. The SDK library path remains available for
    the emulated-getpid archive. These failures were toolchain integration
    issues; no generated cryptographic bindings were manually edited.

BROWSER CAPABILITIES

    The WASI bridge supplies clocks, browser CSPRNG, empty arguments/environment,
    EOF on stdin, and bounded in-memory stdout/stderr for this closed test.
    It supplies no real files, preopened directories, sockets, or process launch.
    Listed filesystem/network operations return NOTCAPABLE or BADF. Unknown
    imports fail before instantiation. Standard output is capped at 65536 chars.

    Those capability denials protect against accidentally connecting the WASI
    module to host storage or networking. They do not isolate it from malicious
    JavaScript delivered by the same server. Memory, clocks, randomness, and
    imported bridge functions remain part of the trusted browser environment.
    A test deadline closes Chromium after 120 seconds if execution stalls.

VERIFICATION

    Native: the same probe passes using OpenSSL 3.6.5. It checks v6 generation,
    exact algorithm selection, protected-secret-key serialization/import,
    signed UTF-8 encryption to both participants, decryption by each, wrong
    password rejection, unexpected signer rejection, and ciphertext tampering.

    Browser: actual Chromium executes the OpenSSL WASI binary and passes the
    same checks, then repeats with a fresh module instance. One observed normal
    execution requested 1792 bytes across 72 browser CSPRNG calls. These counts
    are observations, not cryptographic requirements or entropy estimates.
    Removing secure randomness causes failure rather than a successful result.
    A modified module requesting an unknown host import is also rejected before
    instantiation. These negative tests require the expected failure reason.

    The harness also observes no external requests, cookies, localStorage,
    sessionStorage, IndexedDB databases, or service-worker registrations.
    Its HTTP responses carry Cache-Control: no-store. This establishes only
    this probe's behavior, not that browsers/OSes cannot retain memory, caches,
    crash dumps, swap, or restored state. A complete chat session does not exist.

    The native tests, WASI build, and browser test are separate checks. A native
    pass cannot stand in for browser execution. A functional pass and a clean
    vulnerability scan cannot stand in for a cryptographic or side-channel audit.

DEPENDENCY POLICY REVIEW

    The RustSec database reports no advisories for the current resolved graph.
    No advisory ignore was added. Bans on wildcards, unknown Git/registry sources,
    and unreviewed duplicate versions remain enabled. The following existing
    upstream API generations cannot be unified merely by cargo update. Duplicate
    exceptions match only the exact older version; other versions remain subject
    to the duplicate ban. All these packages still undergo advisory and license
    checks. Cargo.lock pins both sides of each pair.

        block-buffer 0.10.4 vs 0.12.1
        crypto-common 0.1.7 vs 0.2.2
        digest 0.10.7 vs 0.11.3
            Sequoia's Argon2 0.5.3 -> BLAKE2 0.10 uses the older digest API.
            Root SHA-256 and the parser generator's SHA3 use the newer API.

        cpufeatures 0.2.17 vs 0.3.1
            Argon2 uses 0.2; root SHA-256 and parser-generator SHA3 use 0.3.

        generic-array 0.14.7 vs 1.4.5
            Argon2/BLAKE2 digest uses 0.14; SHA1 collision detection uses 1.x.

        getrandom 0.2.17 vs 0.4.3
            Sequoia's unknown-unknown WASM target dependencies declare 0.2;
            the root CLI's tempfile uses 0.4. The current browser target is WASI,
            whose OpenSSL entropy source is the bridge described above. The
            all-target graph is still audited rather than excluding that edge.

        hashbrown 0.15.5 vs 0.17.1
            petgraph uses 0.15 directly and indexmap 2.14 uses 0.17. Both are
            brought in by the parser generator at build time.

        itertools 0.13.0 vs 0.15.0
        shlex 1.3.0 vs 2.0.1
            bindgen uses older APIs; lalrpop and cc require the newer ones.
            These are build dependencies, not a justification to skip auditing.

        syn 2.0.119 vs 3.0.9
            bindgen/prettyplease and Windows support use syn 2. Root derive
            macros and other dependencies use syn 3. Changing that would require
            upstream migration or unrelated dependency downgrades.

    The only new license allowance is ISC, scoped to libloading, a bindgen/clang
    dependency. GNU-compatible third-party licenses remain correctly attributed.
    cargo-about generates notices for the complete workspace. The static OpenSSL
    C library and SDK are not Rust crates; their original licenses and sources
    must accompany any distributed browser artifact as appropriate. Source
    OpenSSL LICENSE.txt is Apache-2.0. Do not treat the Rust notice page alone
    as complete documentation of external C/toolchain distribution obligations.

EXTERNAL LIBRARY MAINTENANCE

    cargo-deny does not audit the externally built OpenSSL C archive or SDK.
    Review OpenSSL's release/advisory pages separately and rebuild when needed:
        https://openssl-library.org/news/timeline/
        https://openssl-library.org/news/vulnerabilities-3.6/
    OpenSSL 3.6.5 is the tested security-patch release dated 2026-09-29. A green
    Rust audit is not a lifetime security guarantee for this pinned C version.
    Choose and document a supported update policy before production deployment.

REPRODUCE FROM THE STACK ROOT

    Native prerequisites: OpenSSL >=3.5 development headers/library, libclang,
    pkg-config, and the pinned Rust toolchain. For the cross build also provide
    a Linux x86_64 build host, Perl, make, curl, tar, and sha256sum. No root-owned
    packages or system settings are changed by the cross-build script.

        cargo test --locked -p stack-chat-crypto
        cargo run --locked -p stack-chat-crypto
        sh infra/chat/build-openssl-wasi.sh
        npm install --prefix .tools/browser --save-exact playwright@1.64.1
        PLAYWRIGHT_BROWSERS_PATH="$PWD/.tools/browsers" .tools/browser/node_modules/.bin/playwright install chromium
        PLAYWRIGHT_BROWSERS_PATH="$PWD/.tools/browsers" node crates/chat-crypto/tests/browser.mjs
        cargo stack check

    The build script pins archive versions and hashes, configures static OpenSSL,
    installs it under .tools/openssl-wasi, builds the Rust WASI command, and prints
    its SHA-256. It does not download/use an unverified precompiled OpenSSL binary.
    It may reuse already extracted sources; use a fresh ignored tools/build tree
    when independently verifying the source archive rather than trusting a
    previously modified extraction. Downloads and test artifacts are not secrets.

    Build logs and complete dependency trees are local ignored diagnostics in
    .tools/chat-openssl-*.log and .tools/chat-openssl-duplicates.txt. The native
    result and the browser result must explicitly identify the OpenSSL backend.

REMAINING WORK

    Observed WASI artifact SHA-256 on this development machine:
        7fba6b96377619ef41f056d4027c4409107372e9300b2dd69be865e72892df79
    This is a diagnostic identifier, not a cross-host reproducibility promise.

    This removes the specific Rust-backend dependency blocker and demonstrates
    the fixed algorithms in a browser. It is not a complete messaging service,
    audit of OpenSSL/WASI/JIT timing behavior, LibreJS certification, or proof
    against malicious delivery. The file format, authentication, server/database,
    quotas, hostile-input handling, pagination/counts, backup recovery, complete
    session lifecycle, and browser-state tests still need implementation.