code wiki / _hdl_build / _h2_serve_loopback_gate.nx
_h2_serve_loopback_gate.nx source
↩ module page · 359 lines · 16991 B
1// _h2_serve_loopback_gate.nx -- TUTOR-BOOTSTRAP SCAFFOLD (Claude, authored under
2// the B1 rung(3) ALPN-h2 SERVER workflow of the R4-H2 HTTP/2-transport ladder),
3// NOT credited as team self-authoring.
4//
5// THE LIVE LOOPBACK SERVE GATE: a single fork-based organ that stands up OUR
6// sovereign ALPN-h2 TLS 1.3 SERVER and drives OUR sovereign h2 CLIENT against it
7// over a real loopback socket -- both halves OUR stack, no openssl/nghttp2.
8// Modeled byte-for-byte on the GREEN fork pattern of nx_browse_text_test.nx:102-
9// 126 (socket/bind/listen/fork; child spins then connects; parent accepts).
10//
11// PRE-FORK (shared address space, inherited by both sides):
12// - generate an Ed25519 keypair + build a self-signed X.509 leaf with
13// SAN=localhost (sovereign: nx_csprng_fill + ed25519_pub_from_priv +
14// nx_x509_build_self_signed), validity window covering now.
15// - parse the cert into an X509Cert and add it as the SOLE anchor of a
16// 1-entry TrustStore (a self-signed leaf is its own root; the store is
17// subject-DN-keyed so issuer DN == subject DN finds the anchor). NO
18// permissive/insecure validation context is built (fake-green forbidden).
19// CHILD (the h2 CLIENT): spin a short busy-loop, connect, then
20// nx_tls13_client_session_run_h2 (advertises ALPN ["h2"] only, validates
21// the cert against our 1-entry store) -> h2_tls_get GET "/" -> assert it
22// recovered :status 200 + the exact body bytes OUR server sent.
23// PARENT (the ALPN-h2 SERVER): accept, then
24// nx_tls13_server_session_run_h2_ed25519 (SELECTS ALPN "h2" via emit_ee_alpn
25// + signs CV with the Ed25519 priv) -> app_recv the client's h2 open ->
26// h2_server_recv_request (assert :method GET, :path "/") -> app_send the h2
27// response (SETTINGS+ACK+HEADERS :status 200 + DATA END_STREAM via
28// h2_server_send_response). Parent exit code IS the verdict.
29//
30// HONEST verdict discipline: GREEN ONLY if the parent observes a successful
31// server handshake + a correctly-parsed GET / request AND the child observes
32// :status 200 + the exact body end-to-end. Any handshake failure, cert-validate
33// failure, or status mismatch -> a NAMED negative exit code, never a faked 200.
34// This is the one organ whose GREEN depends on the NAMED cert-self-verify risk:
35// if nx_cert_gen's self-signed Ed25519 cert does not cleanly self-verify under
36// nx_https_cert_pipeline_verify_with_store with SAN=localhost, the live half
37// fails HONESTLY here (the in-memory gate nx_h2_server.nx stays the GREEN floor).
38//
39// FOUNDED ON (composes, each imported EXACTLY ONCE, RC6 double-import avoided):
40// - nx_h2_server.nx: h2_server_recv_request / h2_server_send_response (it
41// transitively pulls h2_conformance + h2_client_over_tls -> all framing/HPACK
42// + h2_tls_get/h2_extract_status_and_body + tls13_ext, ONE import).
43// - nx_tls13_server_session_run_h2.nx: the ALPN-h2 server run (Ed25519 variant)
44// -- imported ONCE; it pulls the server stones + emit_ee_alpn.
45// - nx_tls13_server_session_app_data.nx: server app_send/app_recv.
46// - nx_tls13_client_h2run.nx: the client ALPN-["h2"]-only handshake run.
47// - nx_tls13_client_session.nx (client struct/app keys), nx_x25519_ephemeral
48// (x25519 keypair), nx_csprng (randomness), nx_ed25519_signature
49// (ed25519_pub_from_priv), hub/nx_x509_build (self-signed builder),
50// nx_x509 (x509_parse), nx_x509_trust_store (store alloc/add),
51// nx_tls13_client_validate_certificate (TlsValidationContext),
52// nx_tls13_read_record_from_fd (one record reader for the server app_recv).
53//
54// license_tier: INDEPENDENT_REDERIVE
55// genealogy_id: international-research-sources/ietf/rfc_8446 + rfc_7301 + rfc_9113 + rfc_5280
56// lineage_id: nishi_h2_serve_loopback_b1r3
57
58import "nx_syscalls.nx"
59import "nx_connect.nx" // bounded connect: a raw sys_connect hangs ~127s on a black-holed host
60import "nx_h2_server.nx"
61import "nx_tls13_server_session_run_h2.nx"
62import "nx_tls13_server_session_app_data.nx"
63import "nx_tls13_client_h2run.nx"
64import "nx_x25519_ephemeral.nx"
65import "nx_csprng.nx"
66import "nx_ed25519_signature.nx"
67import "hub/nx_x509_build.nx"
68import "nx_x509.nx"
69import "nx_x509_trust_store.nx"
70import "nx_tls13_read_record_from_fd.nx"
71
72const HSL_PORT: i64 = 0x2333 // 9011
73
74// ---- public-domain civil-date math (Howard Hinnant) -- reimplemented inline so
75// we don't import bin/nx_cert_gen.nx (which carries its own main()). ----
76func hsl_civil_from_days(days: i64, out_y: *i64, out_m: *i64, out_d: *i64) -> i64 {
77 let z: i64 = days + 719468
78 let era: i64 = if z >= 0 then z / 146097 else (z - 146096) / 146097
79 let doe: i64 = z - era * 146097
80 let yoe: i64 = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365
81 let y: i64 = yoe + era * 400
82 let doy: i64 = doe - (365 * yoe + yoe / 4 - yoe / 100)
83 let mp: i64 = (5 * doy + 2) / 153
84 let d: i64 = doy - (153 * mp + 2) / 5 + 1
85 var m: i64 = mp + 3
86 if mp < 10 { m = mp + 3 } else { m = mp - 9 }
87 var yy: i64 = y
88 if m <= 2 { yy = y + 1 }
89 out_y[0] = yy; out_m[0] = m; out_d[0] = d
90 return 0
91}
92func hsl_format_generalized_time(unix_sec: i64, out_15: *u8) -> i64 {
93 let days: i64 = unix_sec / 86400
94 let sod: i64 = unix_sec - days * 86400
95 let hh: i64 = sod / 3600
96 let mm: i64 = (sod - hh * 3600) / 60
97 let ss: i64 = sod - hh * 3600 - mm * 60
98 let yp: *i64 = sys_mmap(8) as *i64
99 let mp: *i64 = sys_mmap(8) as *i64
100 let dp: *i64 = sys_mmap(8) as *i64
101 hsl_civil_from_days(days, yp, mp, dp)
102 let y: i64 = yp[0]; let mo: i64 = mp[0]; let d: i64 = dp[0]
103 out_15[0] = ((0x30 + ((y / 1000) % 10)) & 0xff) as u8
104 out_15[1] = ((0x30 + ((y / 100) % 10)) & 0xff) as u8
105 out_15[2] = ((0x30 + ((y / 10) % 10)) & 0xff) as u8
106 out_15[3] = ((0x30 + ( y % 10)) & 0xff) as u8
107 out_15[4] = ((0x30 + (mo / 10)) & 0xff) as u8
108 out_15[5] = ((0x30 + (mo % 10)) & 0xff) as u8
109 out_15[6] = ((0x30 + (d / 10)) & 0xff) as u8
110 out_15[7] = ((0x30 + (d % 10)) & 0xff) as u8
111 out_15[8] = ((0x30 + (hh / 10)) & 0xff) as u8
112 out_15[9] = ((0x30 + (hh % 10)) & 0xff) as u8
113 out_15[10] = ((0x30 + (mm / 10)) & 0xff) as u8
114 out_15[11] = ((0x30 + (mm % 10)) & 0xff) as u8
115 out_15[12] = ((0x30 + (ss / 10)) & 0xff) as u8
116 out_15[13] = ((0x30 + (ss % 10)) & 0xff) as u8
117 out_15[14] = 0x5A as u8 // 'Z'
118 return 0
119}
120
121// Build the 16-byte sockaddr_in for 127.0.0.1:port (AF_INET=2, htons port,
122// 0x0100007f = 127.0.0.1 in network order). Mirror nx_browse_text_test bt_addr.
123func hsl_addr(out: *u8, port: i64) -> i64 {
124 out[0] = 2 as u8; out[1] = 0 as u8 // AF_INET
125 out[2] = ((port >> 8) & 0xff) as u8 // port hi (network order)
126 out[3] = (port & 0xff) as u8 // port lo
127 out[4] = 127 as u8; out[5] = 0 as u8; out[6] = 0 as u8; out[7] = 1 as u8 // 127.0.0.1
128 var i: i64 = 8
129 while i < 16 { out[i] = 0 as u8; i = i + 1 }
130 return 0
131}
132
133// Generate the shared self-signed Ed25519 leaf (SAN=localhost) + build the
134// 1-entry trust store. Returns 0 ok with *out_cert_der/*out_cert_len/*out_priv
135// set + *out_store the anchor store; negative on any failure.
136func hsl_make_cert(
137 out_cert_der: *u8, out_cert_len: *i64, out_priv: *u8, out_store_box: *i64
138) -> i64 {
139 // 1. Ed25519 keypair.
140 if nx_csprng_fill(out_priv, 32) != 0 { return 0 - 1 }
141 let pub32: *u8 = sys_mmap(32)
142 if ed25519_pub_from_priv(out_priv, pub32) != 0 { return 0 - 2 }
143
144 // 2. validity window: notBefore = now - 1 day, notAfter = now + 365 days.
145 let now: i64 = sys_now_realtime_sec()
146 let nb: *u8 = sys_mmap(16)
147 let na: *u8 = sys_mmap(16)
148 hsl_format_generalized_time(now - 86400, nb)
149 hsl_format_generalized_time(now + 365 * 86400, na)
150
151 // 3. SAN = "localhost" (parallel arrays for nx_x509_inputs_init).
152 let san_name: *u8 = sys_mmap(16); nx_str_cpy(san_name, "localhost" as *u8)
153 let san_ptrs: *i64 = sys_mmap(8) as *i64; san_ptrs[0] = san_name as i64
154 let san_lens: *i64 = sys_mmap(8) as *i64; san_lens[0] = 9
155 let domain: *u8 = sys_mmap(16); nx_str_cpy(domain, "localhost" as *u8)
156
157 // 4. inputs + build self-signed.
158 let inp: *NxX509BuildInputs = sys_mmap(256) as *NxX509BuildInputs
159 let in_rc: i64 = nx_x509_inputs_init(inp, domain, 9,
160 san_ptrs, san_lens, 1,
161 out_priv, pub32,
162 nb, na, now)
163 if in_rc != NX_X509_OK { return 0 - 3 }
164 let cdn: *i64 = sys_mmap(8) as *i64; cdn[0] = 0
165 let brc: i64 = nx_x509_build_self_signed(inp, out_cert_der, 8192, cdn)
166 if brc != NX_X509_OK { return 0 - 4 }
167 out_cert_len[0] = cdn[0]
168
169 // 5. parse + add to a 1-entry trust store (self-signed leaf = its own anchor).
170 let cert: *X509Cert = sys_mmap(512) as *X509Cert
171 if x509_parse(out_cert_der, cdn[0], cert) != 0 { return 0 - 5 }
172 let store: *TrustStore = trust_store_alloc(1)
173 if trust_store_add(store, out_cert_der, cert) != NX_TRUST_STORE_OK { return 0 - 6 }
174 out_store_box[0] = store as i64
175 return 0
176}
177
178// ---- child: the sovereign h2 CLIENT ----
179// Connect, run the ALPN-["h2"] handshake against OUR server (validating the cert
180// against the inherited 1-entry store), GET "/", assert :status 200 + exact body.
181// Returns 0 ok; a NAMED small positive code on any failure (becomes child exit).
182func hsl_run_client(addr: *u8, store: *TrustStore, exp_body: *u8, exp_len: i64) -> i64 {
183 var spin: i64 = 0
184 while spin < 400000 { spin = spin + 1 } // let the parent reach accept()
185
186 let cfd: i64 = sys_socket(AF_INET, SOCK_STREAM, 0)
187 if cfd < 0 { return 11 }
188 if nx_connect_bounded(cfd, addr, 16, NX_CONN_DEFAULT_MS) < 0 { return 12 }
189
190 // client random + x25519 ephemeral priv.
191 let crand: *u8 = sys_mmap(32)
192 if nx_csprng_fill(crand, 32) != 0 { return 13 }
193 let xpriv: *u8 = sys_mmap(32)
194 if x25519_keypair_private(xpriv) != 0 { return 14 }
195
196 // validation context: our 1-entry store, SNI=localhost, now.
197 let vctx: *TlsValidationContext = sys_mmap(64) as *TlsValidationContext
198 let sni: *u8 = sys_mmap(16); nx_str_cpy(sni, "localhost" as *u8)
199 vctx.store = store
200 vctx.sni_host = sni
201 vctx.sni_host_len = 9
202 vctx.now_epoch = sys_now_realtime_sec()
203
204 let sret: i64 = nx_tls13_client_session_run_h2(cfd, sni, 9, crand, xpriv, vctx)
205 if sret <= 0 { return 20 } // handshake/cert-validate failed -> HONEST
206 let cs: *Tls13ClientSession = sret as *Tls13ClientSession
207
208 let authority: *u8 = sys_mmap(16); nx_str_cpy(authority, "localhost" as *u8)
209 let path: *u8 = sys_mmap(8); nx_str_cpy(path, "/" as *u8)
210 let body: *u8 = sys_mmap(4096)
211 let status: *i64 = sys_mmap(8) as *i64
212 let blen: i64 = h2_tls_get(cs, cfd, authority, 9, path, 1, body, 4096, status)
213 if blen < 0 { return 30 }
214 if status[0] != 200 { return 31 }
215 if blen != exp_len { return 32 }
216 var i: i64 = 0
217 while i < exp_len { if (body[i] & 0xff) != (exp_body[i] & 0xff) { return 33 } i = i + 1 }
218 sys_close(cfd)
219 return 0 // :status 200 + exact body -> child OK
220}
221
222// ---- parent: the sovereign ALPN-h2 SERVER ----
223// Handshake (SELECT "h2"), recv the client's h2 open request (assert GET /),
224// send the h2 response. Returns 0 ok; a NAMED negative code on failure.
225func hsl_run_server(
226 scfd: i64, srand: *u8, sxpriv: *u8,
227 cert_der: *u8, cert_len: i64, ed_priv: *u8,
228 body: *u8, blen: i64
229) -> i64 {
230 let sret: i64 = nx_tls13_server_session_run_h2_ed25519(
231 scfd, srand, sxpriv, cert_der, cert_len, ed_priv)
232 if sret <= 0 { return sret } // handshake failed -> propagate honest <0
233 let ss: *Tls13ServerSession = sret as *Tls13ServerSession
234
235 // recv the client's first app-data record (its h2 open: preface+SETTINGS+HEADERS).
236 let rec: *u8 = sys_mmap(16645)
237 let rtot: i64 = nx_tls13_read_record_from_fd(scfd, rec, 16645)
238 if rtot < 0 { return 0 - 50 }
239 let openbuf: *u8 = sys_mmap(4096)
240 let on: i64 = nx_tls13_server_session_app_recv(ss, rec, rtot, openbuf, 4096)
241 if on < 0 { return 0 - 51 }
242
243 // parse the request -> assert GET /.
244 let m: *i64 = sys_mmap(8) as *i64
245 let po: *i64 = sys_mmap(8) as *i64
246 let pl: *i64 = sys_mmap(8) as *i64
247 let pbuf: *u8 = sys_mmap(64)
248 let rr: i64 = h2_server_recv_request(openbuf, on, m, po, pl, pbuf)
249 if rr < 0 { return 0 - 52 }
250 if m[0] != H2_METHOD_GET { return 0 - 53 }
251 if pl[0] != 1 { return 0 - 54 }
252 if (pbuf[0] & 0xff) != 0x2f { return 0 - 55 }
253
254 // build the h2 response + app_send it.
255 let resp: *u8 = sys_mmap(512)
256 let rn: i64 = h2_server_send_response(resp, 200, body, blen)
257 if rn < 0 { return 0 - 56 }
258 let outrec: *u8 = sys_mmap(rn + 64)
259 let sn: i64 = nx_tls13_server_session_app_send(ss, resp, rn, outrec, rn + 64)
260 if sn < 0 { return 0 - 57 }
261 var w: i64 = 0
262 while w < sn {
263 let k: i64 = sys_write(scfd, (outrec as i64 + w) as *u8, sn - w)
264 if k <= 0 { return 0 - 58 }
265 w = w + k
266 }
267 return 0
268}
269
270func hsl_log(verdict_green: i64, code: i64) -> i64 {
271 let lfd: i64 = sys_openat_append("knowledge/status/h2_nx_h2_serve_loopback.log" as *u8, 0x1a4)
272 if lfd < 0 { return 0 }
273 sys_write(lfd, "B1-R3-H2-SERVE-LOOPBACK organ=_h2_serve_loopback_gate " as *u8, 54)
274 if verdict_green == 1 {
275 sys_write(lfd, "alpn=h2 status=200 verdict=GREEN\n" as *u8, 32)
276 } else {
277 sys_write(lfd, "verdict=RED code=" as *u8, 16)
278 // small decimal of code
279 var v: i64 = code; if v < 0 { sys_write(lfd, "-" as *u8, 1); v = 0 - v }
280 let t: *u8 = sys_mmap(28); var kk: i64 = 0
281 if v == 0 { t[0] = 48 as u8; kk = 1 }
282 while v > 0 { t[kk] = (48 + (v % 10)) as u8; v = v / 10; kk = kk + 1 }
283 while kk > 0 { kk = kk - 1; sys_write(lfd, (((t as i64)+kk) as *u8), 1) }
284 sys_write(lfd, "\n" as *u8, 1)
285 }
286 sys_close(lfd)
287 return 0
288}
289
290func main() -> i64 {
291 sys_write(1, "_h2_serve_loopback_gate: OUR h2 client <-> OUR ALPN-h2 server, loopback\n" as *u8, 71)
292
293 // ---- shared body the server will serve + the client must recover ----
294 let body: *u8 = sys_mmap(64)
295 let bsrc: *u8 = "hello from nishi h2 server" as *u8
296 var blen: i64 = 0
297 while bsrc[blen] != (0 as u8) { body[blen] = bsrc[blen]; blen = blen + 1 } // 26
298
299 // ---- PRE-FORK: cert + trust store (inherited by both sides) ----
300 let cert_der: *u8 = sys_mmap(8192)
301 let cert_len: *i64 = sys_mmap(8) as *i64
302 let ed_priv: *u8 = sys_mmap(32)
303 let store_box: *i64 = sys_mmap(8) as *i64
304 let crc: i64 = hsl_make_cert(cert_der, cert_len, ed_priv, store_box)
305 if crc < 0 {
306 sys_write(1, " FAIL cert/store build\n" as *u8, 24)
307 hsl_log(0, 0 - 90)
308 sys_exit(90); return 90
309 }
310 let store: *TrustStore = store_box[0] as *TrustStore
311 sys_write(1, " cert+1-entry-store built (SAN=localhost, Ed25519 self-signed)\n" as *u8, 63)
312
313 // ---- server x25519 + random ----
314 let srand: *u8 = sys_mmap(32)
315 if nx_csprng_fill(srand, 32) != 0 { hsl_log(0, 0 - 91); sys_exit(91); return 91 }
316 let sxpriv: *u8 = sys_mmap(32)
317 if x25519_keypair_private(sxpriv) != 0 { hsl_log(0, 0 - 92); sys_exit(92); return 92 }
318
319 // ---- socket / bind / listen ----
320 let addr: *u8 = sys_mmap(16)
321 hsl_addr(addr, HSL_PORT)
322 let lfd: i64 = sys_socket(AF_INET, SOCK_STREAM, 0)
323 if lfd < 0 { hsl_log(0, 0 - 93); sys_exit(93); return 93 }
324 if sys_bind(lfd, addr, 16) < 0 { hsl_log(0, 0 - 94); sys_exit(94); return 94 }
325 if sys_listen(lfd, 4) < 0 { hsl_log(0, 0 - 95); sys_exit(95); return 95 }
326
327 // ---- fork ----
328 let pid: i64 = sys_fork()
329 if pid < 0 { hsl_log(0, 0 - 96); sys_exit(96); return 96 }
330 if pid == 0 {
331 // CHILD = h2 CLIENT.
332 let crc2: i64 = hsl_run_client(addr, store, body, blen)
333 sys_exit(crc2); return crc2
334 }
335
336 // PARENT = ALPN-h2 SERVER.
337 let scfd: i64 = sys_accept(lfd)
338 if scfd < 0 { hsl_log(0, 0 - 97); sys_exit(97); return 97 }
339 let sr: i64 = hsl_run_server(scfd, srand, sxpriv, cert_der, cert_len[0], ed_priv, body, blen)
340
341 // reap child + read its exit code.
342 let status: *i64 = sys_mmap(8) as *i64
343 sys_wait4(pid, status, 0)
344 let child_code: i64 = (status[0] >> 8) & 0xff // WEXITSTATUS
345
346 if sr == 0 {
347 if child_code == 0 {
348 sys_write(1, " PASS live loopback: server saw GET /, client saw :status 200 + exact body\n" as *u8, 75)
349 hsl_log(1, 0)
350 sys_exit(0); return 0
351 }
352 sys_write(1, " FAIL client side (exit code printed below)\n" as *u8, 45)
353 hsl_log(0, child_code)
354 sys_exit(child_code); return child_code
355 }
356 sys_write(1, " FAIL server side\n" as *u8, 19)
357 hsl_log(0, sr)
358 sys_exit(0 - sr); return 0 - sr
359}