nx_mtls_test_daemon.nx source
↩ module page · 110 lines · 5759 B
1// nx_mtls_test_daemon.nx -- the mTLS INTEROP test daemon: proves run_ecdsa_mtls completes a real TLS 1.3
2// MUTUAL-auth handshake against a STANDARD client (openssl s_client / curl / a browser), and that run_ecdsa_mtls
3// VERIFIES the client cert that the standard client presents. This is the byte-level interop the loopback gate
4// cannot cover (the loopback proves the LOGIC against our own message construction; THIS proves the wire format
5// is correct against OpenSSL/Schannel/BoringSSL). It is the de-risk gate before the live doc-wall cutover.
6//
7// NOT a live daemon -- a throwaway harness. Adapted from nx_tls13_ed25519_test_daemon (the proven server-auth
8// interop pattern) by swapping run_ed25519 -> run_ecdsa_mtls and logging the client-auth result.
9//
10// FLOW: read ECDSA server cert+key (the demo P-256 cert) -> bind 127.0.0.1:7444 -> accept ONE conn ->
11// run_ecdsa_mtls (sends CertificateRequest; reads + verifies the client's Certificate+CertificateVerify+Finished)
12// -> LOG auth result + the verified identity -> send a tiny HTTP body -> exit.
13// COMPOSES (sovereign): nx_csprng + nx_http_server + nx_tls13_server_session_run_mtls + app_send + nx_mtls_authz.
14import "nx_syscalls.nx"
15import "nx_csprng.nx"
16import "nx_http_server.nx"
17import "nx_tls13_server_session.nx"
18import "nx_tls13_server_session_run_mtls.nx" // nx_tls13_server_session_run_ecdsa_mtls
19import "nx_tls13_server_session_app_data.nx"
20import "nx_mtls_authz.nx" // nx_mtls_cert_identity (show the verified identity)
21
22const NX_MTD_PORT: i64 = 7444
23
24const NX_MTD_HTTP_RESP: *u8 = "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nContent-Length: 8\r\nConnection: close\r\n\r\nMTLS-OK\n" as *u8
25const NX_MTD_HTTP_RESP_N: i64 = 91
26
27func mtd_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
28func mtd_log(s: *u8) -> i64 { sys_write(1, s, mtd_slen(s)); return 0 }
29// write "label<int>\n" to stdout
30func mtd_log_int(label: *u8, v: i64) -> i64 {
31 sys_write(1, label, mtd_slen(label))
32 let buf: *u8 = sys_mmap(24); var m: i64 = v; var neg: i64 = 0
33 if m < 0 { neg = 1; m = 0 - m }
34 var k: i64 = 0
35 if m == 0 { buf[0] = 48 as u8; k = 1 }
36 while m > 0 { buf[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
37 let out: *u8 = sys_mmap(26); var oi: i64 = 0
38 if neg == 1 { out[0] = 45 as u8; oi = 1 }
39 var j: i64 = 0
40 while j < k { out[oi + j] = buf[k - 1 - j]; j = j + 1 }
41 out[oi + k] = 10 as u8
42 sys_write(1, out, oi + k + 1)
43 return 0
44}
45
46func main() -> i64 {
47 // 1. ECDSA server cert + 32-byte BE priv (the demo P-256 cert from nx_cert_gen_smoke.sh)
48 let cert_path: *u8 = "/tmp/nx_cert_gen_demo_p256_cert.der" as *u8
49 let priv_path: *u8 = "/tmp/nx_cert_gen_demo_p256_priv.bin" as *u8
50 let clb: *i64 = sys_mmap(8) as *i64; clb[0] = 0
51 let cert_der: *u8 = sys_read_file(cert_path, clb)
52 if (cert_der as i64) == 0 { mtd_log("MTD-ENOENT-CERT\n" as *u8); return 1 }
53 let cert_der_len: i64 = clb[0]
54 let plb: *i64 = sys_mmap(8) as *i64; plb[0] = 0
55 let ecdsa_priv: *u8 = sys_read_file(priv_path, plb)
56 if (ecdsa_priv as i64) == 0 { mtd_log("MTD-ENOENT-PRIV\n" as *u8); return 1 }
57 if plb[0] != 32 { mtd_log("MTD-BAD-PRIV-SIZE\n" as *u8); return 2 }
58
59 // 2. fresh server randoms
60 let srv_rand: *u8 = sys_mmap(32); let srv_x: *u8 = sys_mmap(32)
61 nx_csprng_fill(srv_rand, 32); nx_csprng_fill(srv_x, 32)
62
63 // 3. bind 127.0.0.1:7444
64 let addr: *u8 = sys_mmap(16)
65 nx_http_server_addr_loopback(addr, NX_MTD_PORT)
66 let lv: *i64 = sys_mmap(8) as *i64
67 let lfd: i64 = nx_http_server_listen(addr, 4, lv)
68 if lfd < 0 { mtd_log("MTD-BIND-FAILED\n" as *u8); return 3 }
69 mtd_log("mtls-test-daemon listening 127.0.0.1:7444\n" as *u8)
70
71 // 4. accept ONE connection
72 let av: *i64 = sys_mmap(8) as *i64
73 let cfd: i64 = nx_http_server_accept_one(lfd, av)
74 if cfd < 0 { sys_close(lfd); mtd_log("MTD-ACCEPT-FAILED\n" as *u8); return 4 }
75
76 // 5. run the mTLS handshake (ECDSA server cert; requests + verifies the client cert)
77 let out_cc: *u8 = sys_mmap(8192)
78 let out_cc_len: *i64 = sys_mmap(8) as *i64
79 let out_auth: *i64 = sys_mmap(8) as *i64
80 let hs: i64 = nx_tls13_server_session_run_ecdsa_mtls(
81 cfd, srv_rand, srv_x, cert_der, cert_der_len, ecdsa_priv,
82 out_cc, 8192, out_cc_len, out_auth)
83 if hs <= 0 {
84 mtd_log_int("MTD-HS-FAILED rc=" as *u8, hs)
85 sys_close(cfd); sys_close(lfd); return 5
86 }
87 let s: *Tls13ServerSession = hs as *Tls13ServerSession
88
89 // 6. THE RESULT: did a STANDARD client present a cert + did run_ecdsa_mtls verify it?
90 mtd_log_int("MTLS-RESULT auth=" as *u8, out_auth[0]) // 1 verified, 0 no-cert, -1 verify-failed
91 mtd_log_int("MTLS-RESULT cc_len=" as *u8, out_cc_len[0])
92 if out_auth[0] == 1 {
93 let id: *u8 = sys_mmap(256)
94 let idn: i64 = nx_mtls_cert_identity(out_cc, out_cc_len[0], id, 256)
95 if idn > 0 { mtd_log("MTLS-IDENTITY " as *u8); sys_write(1, id, idn); mtd_log("\n" as *u8) }
96 else { mtd_log("MTLS-IDENTITY (cert verified but CN not extracted)\n" as *u8) }
97 mtd_log("MTLS-INTEROP-PASS (standard client presented a cert; run_ecdsa_mtls verified it)\n" as *u8)
98 } else {
99 mtd_log("MTLS-INTEROP: client presented NO cert (request-not-require fallback path)\n" as *u8)
100 }
101
102 // 7. send a tiny HTTP body so the client sees a clean reply
103 let out_rec: *u8 = sys_mmap(NX_MTD_HTTP_RESP_N + 256)
104 let out_n: i64 = nx_tls13_server_session_app_send(s, NX_MTD_HTTP_RESP, NX_MTD_HTTP_RESP_N, out_rec, NX_MTD_HTTP_RESP_N + 256)
105 if out_n > 0 { sys_write(cfd, out_rec, out_n) }
106
107 sys_close(cfd); sys_close(lfd)
108 mtd_log("mtls-test-daemon: clean exit\n" as *u8)
109 return 0
110}