code wiki / bin / nx_mtls_test_daemon.nx

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}