nx_tls13_mtls_loopback_test.nx
buildroot/runtime/nx_tls13_mtls_loopback_test.nx
about
nx_tls13_mtls_loopback_test.nx -- SOVEREIGN end-to-end MUTUAL-AUTH proof: the capstone of the no-cookie carrier.
nx_tls13_loopback_test proves a server-auth-only handshake reaches CONNECTED with both sides agreeing on keys.
The R3 client-auth gate proves the CertificateVerify CRYPTO -- but over an ARBITRARY transcript hash. NEITHER
proves the load-bearing mTLS property: that a REAL client signature, over the REAL mutually-agreed handshake
transcript (INCLUDING the server's CertificateRequest), is verified by the server END-TO-END.
This gate closes that last gap. One main() drives BOTH halves of an mTLS 1.3 handshake message-by-message,
maintaining two INDEPENDENT transcripts (client + server) exactly as the wire would, then proves:
T1 both transcripts AGREE through the client's Certificate (the snapshot the client signs over),
T2 the client's REAL Ed25519 CertificateVerify over that snapshot VERIFIES on the server + recovers identity,
T3 a downgrade-MITM that STRIPS the CertificateRequest diverges the transcript -> verify FAILS,
T4 a single flipped transcript byte -> verify FAILS (bound to THIS handshake),
T5 another identity's cert cannot ride the signature (no impersonation),
T6 a tampered signature -> verify FAILS.
Real R2 CertificateRequest bytes + real R4 minted client cert + real Ed25519 signature + real R3 server verify,
bound over a real (sha256) transcript both sides compute independently. No socket, no browser, no external
anything -- the codebase's canonical loopback hand-builds its flight the same way. This is the in-process proof
that the run loop's mutual-auth LOGIC is correct; the live browser then only tests INTEROP (does Chrome present
the cert), not correctness -- the one thing no Nishi component can stand in for.
expect_exit: 0 license_tier: ORIGINAL
dependencies 5 imports · 0 importers
imports: nx_syscalls.nxnx_tls13.nxnx_tls13_transcript.nxnx_tls13_emit_certificate_request.nxnx_tls13_server_clientauth.nx
imported by: nobody (leaf or entry point)
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| none |
functions
| 29 | func ml_w(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } |
| 30 | func ml_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } called by 1: main |
| 31 | func ml_row(name: *u8, ok: i64) -> i64 { if ok == 1 { ml_w(" PASS " as *u8) } else { ml_w(" FAIL " as *u8) } ml_w(name); ml_w("\n" as *u8); return ok } |
| 32 | func ml_u24(b: *u8, o: i64, v: i64) -> i64 { b[o] = ((v >> 16) & 0xff) as u8; b[o+1] = ((v >> 8) & 0xff) as u8; b[o+2] = (v & 0xff) as u8; return o + 3 } |
| 35 | func ml_filler_msg(buf: *u8, htype: i64, body_len: i64, tag: i64) -> i64 |
| 44 | func ml_client_cert_msg(buf: *u8, leaf: *u8, leaf_len: i64) -> i64 |
| 59 | func main() -> i64 |