code wiki / _hdl_build / nx_aw_mtls_proxy.nx

nx_aw_mtls_proxy.nx source

↩ module page · 157 lines · 8481 B

1// nx_aw_mtls_proxy.nx -- SOVEREIGN mTLS-TERMINATING reverse proxy = the no-JavaScript session carrier. 2// Identical to the PROVEN nx_aw_tlsproxy (terminate TLS 1.3 + the real Let's Encrypt cert -> forward the 3// decrypted HTTP to a loopback backend -> relay back encrypted, fork-per-connection, instant DNAT-flip 4// rollback) EXCEPT it requests a CLIENT cert (mTLS via run_ecdsa_mtls) and, for a VERIFIED client cert, 5// injects the cert Subject CN as X-Nishi-Cert-Identity into the forwarded request -- stripping any client- 6// supplied copy first (the trust boundary, gated by nx_aw_mtls_inject_gate). A no-cert / bad-cert client is 7// forwarded WITHOUT an identity (request-not-require: the backend falls back to its X-Nishi-Session header 8// path = NEVER-LOCKOUT). So a top-level NAVIGATION carries identity at the TLS layer with ZERO JavaScript, 9// ZERO cookies -- the sovereign answer the operator asked for. Live cutover = point .240:443 DNAT at NX_MP_PORT. 10// argv[1] (optional) = listen port (default 9443); argv[2] (optional) = backend port (default 8443) 11// license_tier: ORIGINAL 12import "nx_syscalls.nx" 13import "nx_connect.nx" // bounded connect: a raw sys_connect hangs ~127s on a black-holed host 14import "nx_csprng.nx" 15import "nx_http_server.nx" 16import "nx_tls13_server_session.nx" 17import "nx_tls13_server_session_run.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_aw_mtls_inject.nx" // mtls_inject_identity (the gated trust boundary) 21const NX_MAGIC_100000000: i64 = 100000000 22 23const NX_MP_PORT_DEFAULT: i64 = 9443 24const NX_MP_BACKEND_DEFAULT: i64 = 8443 25const NX_MP_CERT: *u8 = "/volume1/homes/elderwesto/nishihost/certs/le_fullchain.der" as *u8 26const NX_MP_PRIV: *u8 = "/volume1/homes/elderwesto/nishihost/certs/le_ecdsa_key.bin" as *u8 27const NX_MP_MAX_CHILDREN: i64 = 64 28const NX_MP_REC: i64 = 20480 29const NX_MP_RESP: i64 = 262144 30const NX_MP_OUTCAP: i64 = 32768 31const NX_MP_CHUNK: i64 = 15000 32const NX_MP_CCCAP: i64 = 4096 // client cert DER buffer 33const NX_MP_INJCAP: i64 = 22528 // injected-request buffer (NX_MP_REC + ample header room) 34 35func mp_atoi(s: *u8) -> i64 { var v: i64=0; var i: i64=0; while s[i]!=(0 as u8){ let c: i64=s[i] as i64; if c>=48 { if c<=57 { v=v*10+(c-48) } } i=i+1 } return v } 36 37// connect 127.0.0.1:<port>, send req, read the full response (until backend closes) into resp; return n or -1. 38func mp_backend(bport: i64, req: *u8, req_n: i64, resp: *u8, cap: i64) -> i64 { 39 let bfd: i64 = sys_socket(2, 1, 0) 40 if bfd < 0 { return 0 - 1 } 41 let addr: *u8 = sys_mmap(16) 42 addr[0]=2 as u8; addr[1]=0 as u8 43 addr[2]=((bport >> 8) & 0xff) as u8; addr[3]=(bport & 0xff) as u8 44 addr[4]=127 as u8; addr[5]=0 as u8; addr[6]=0 as u8; addr[7]=1 as u8 45 var z: i64 = 8; while z < 16 { addr[z]=0 as u8; z=z+1 } 46 if nx_connect_bounded(bfd, addr, 16, NX_CONN_DEFAULT_MS) < 0 { sys_close(bfd); return 0 - 1 } 47 sys_write(bfd, req, req_n) 48 var rn: i64 = 0; var go: i64 = 1 49 while go == 1 { 50 if rn >= cap { go = 0 } else { 51 let r: i64 = sys_read(bfd, (resp + rn) as *u8, cap - rn) 52 if r > 0 { rn = rn + r } else { go = 0 } 53 } 54 } 55 sys_close(bfd) 56 return rn 57} 58 59func main(argc: i64, argv: *i64) -> i64 { 60 var port: i64 = NX_MP_PORT_DEFAULT 61 var bport: i64 = NX_MP_BACKEND_DEFAULT 62 if argc > 1 { port = mp_atoi(argv[1] as *u8) } 63 if argc > 2 { bport = mp_atoi(argv[2] as *u8) } 64 65 let cert_len_box: *i64 = (sys_mmap(8)) as *i64; cert_len_box[0] = 0 66 let cert_der: *u8 = sys_read_file(NX_MP_CERT, cert_len_box) 67 if (cert_der as i64) == 0 { sys_write(1, "MP-CERT-FAIL\n" as *u8, 13); return 2 } 68 let cert_der_len: i64 = cert_len_box[0] 69 if cert_der_len < 100 { sys_write(1, "MP-CERT-SHORT\n" as *u8, 14); return 2 } 70 let priv_len_box: *i64 = (sys_mmap(8)) as *i64; priv_len_box[0] = 0 71 let ecdsa_priv: *u8 = sys_read_file(NX_MP_PRIV, priv_len_box) 72 if (ecdsa_priv as i64) == 0 { sys_write(1, "MP-PRIV-FAIL\n" as *u8, 13); return 3 } 73 if priv_len_box[0] != 32 { sys_write(1, "MP-PRIV-LEN\n" as *u8, 12); return 3 } 74 75 let addr_buf: *u8 = sys_mmap(16) 76 nx_http_server_addr_any(addr_buf, port) 77 let lv: *i64 = (sys_mmap(8)) as *i64 78 let lfd: i64 = nx_http_server_listen(addr_buf, 16, lv) 79 if lfd < 0 { sys_write(1, "MP-LISTEN-FAIL\n" as *u8, 15); return 4 } 80 sys_write(1, "nx_aw_mtls_proxy: mTLS HTTPS -> loopback backend, up\n" as *u8, 52) 81 82 let server_random: *u8 = sys_mmap(32) 83 let server_x25519_priv: *u8 = sys_mmap(32) 84 let rec_buf: *u8 = sys_mmap(NX_MP_REC) 85 let plain: *u8 = sys_mmap(NX_MP_REC) 86 let injected: *u8 = sys_mmap(NX_MP_INJCAP) 87 let resp: *u8 = sys_mmap(NX_MP_RESP) 88 let out_rec: *u8 = sys_mmap(NX_MP_OUTCAP) 89 let cc_buf: *u8 = sys_mmap(NX_MP_CCCAP) 90 let cc_len: *i64 = (sys_mmap(8)) as *i64 91 let auth_box: *i64 = (sys_mmap(8)) as *i64 92 let sock_addr: *u8 = sys_mmap(64) 93 let sock_len: *i64 = (sys_mmap(8)) as *i64 94 let reap_status: *i64 = (sys_mmap(8)) as *i64 95 96 sys_set_socket_timeout(lfd, 5) 97 var served: i64 = 0 98 var live: i64 = 0 99 while served < NX_MAGIC_100000000 { 100 while sys_wait4(0 - 1, reap_status, 1) > 0 { live = live - 1 } 101 sock_len[0] = 16 102 let cfd: i64 = sys_accept_with_addr(lfd, sock_addr, sock_len) 103 if cfd < 0 { continue } 104 if live >= NX_MP_MAX_CHILDREN { if sys_wait4(0 - 1, reap_status, 0) > 0 { live = live - 1 } } 105 let pid: i64 = sys_fork() 106 if pid == 0 { 107 sys_close(lfd) 108 sys_set_socket_timeout(cfd, 10) 109 let nodelay: *u8 = sys_mmap(4) 110 nodelay[0] = 1 as u8; nodelay[1] = 0 as u8; nodelay[2] = 0 as u8; nodelay[3] = 0 as u8 111 sys_setsockopt(cfd, 6, 1, nodelay, 4) 112 nx_csprng_fill(server_random, 32) 113 nx_csprng_fill(server_x25519_priv, 32) 114 cc_len[0] = 0; auth_box[0] = 0 115 // mTLS handshake: requests + (if presented) verifies a client cert. auth_box: 0 none / 1 verified / -1 bad. 116 let hs_rc: i64 = nx_tls13_server_session_run_ecdsa_mtls(cfd, server_random, server_x25519_priv, cert_der, cert_der_len, ecdsa_priv, cc_buf, NX_MP_CCCAP, cc_len, auth_box) 117 if hs_rc > 0 { 118 let s: *Tls13ServerSession = hs_rc as *Tls13ServerSession 119 var keep: i64 = 1 120 var nreq: i64 = 0 121 while keep == 1 { 122 if nreq >= 32 { keep = 0 } else { 123 let rec_n: i64 = sys_read(cfd, rec_buf, NX_MP_REC) 124 if rec_n <= 0 { keep = 0 } else { 125 let plain_n: i64 = nx_tls13_server_session_app_recv(s, rec_buf, rec_n, plain, NX_MP_REC) 126 if plain_n <= 0 { keep = 0 } else { 127 // THE CARRIER: strip any spoofed identity; inject the verified CN (auth==1 only). 128 let inj_n: i64 = mtls_inject_identity(plain, plain_n, cc_buf, cc_len[0], auth_box[0], injected, NX_MP_INJCAP) 129 if inj_n < 0 { keep = 0 } else { // fail-closed: never forward an unstripped request 130 let bn: i64 = mp_backend(bport, injected, inj_n, resp, NX_MP_RESP) 131 if bn <= 0 { keep = 0 } else { 132 var off: i64 = 0 133 while off < bn { 134 var ck: i64 = bn - off 135 if ck > NX_MP_CHUNK { ck = NX_MP_CHUNK } 136 let out_n: i64 = nx_tls13_server_session_app_send(s, (resp + off) as *u8, ck, out_rec, NX_MP_OUTCAP) 137 if out_n > 0 { sys_write(cfd, out_rec, out_n) } else { off = bn; keep = 0 } 138 off = off + ck 139 } 140 nreq = nreq + 1 141 } 142 } 143 } 144 } 145 } 146 } 147 } 148 sys_close(cfd) 149 sys_exit(0) 150 } 151 sys_close(cfd) 152 if pid > 0 { live = live + 1 } 153 served = served + 1 154 } 155 sys_close(lfd) 156 return 0 157}