nx_https_loopback_test.nx source
↩ module page · 570 lines · 20511 B
1// nx_https_loopback_test.nx -- HTTPS-class fork loopback over real
2// TCP that does the FULL TLS 1.3 handshake AND exchanges an HTTP/1.1
3// GET / 200 OK pair as AEAD-encrypted records inside the established
4// session.
5//
6// This is the "browser substrate" end-to-end smoke: every byte on
7// the wire is bit-identical to what real HTTPS produces (handshake
8// + cipher records). Only the cert chain validation is stubbed
9// (server's hand-built cert/cv blobs accepted unconditionally).
10//
11// Built per F6 friction-catalog discipline.
12//
13// expect_exit: 0
14// license_tier: ORIGINAL
15
16import "nx_syscalls.nx"
17import "nx_connect.nx" // bounded connect: a raw sys_connect hangs ~127s on a black-holed host
18import "nx_x25519.nx"
19import "nx_tls13.nx"
20import "nx_tls13_ext.nx"
21import "nx_tls13_hello.nx"
22import "nx_tls13_finished.nx"
23import "nx_tls13_transcript.nx"
24import "nx_tls13_handshake.nx"
25import "nx_tls13_schedule.nx"
26import "nx_tls13_client.nx"
27import "nx_tls13_server.nx"
28import "nx_tls13_record.nx"
29
30const HPORT: i64 = 19447
31
32// ---- low-level frame helpers (same as nx_tls13_full_tcp) ----
33
34func hbuild_addr(out: *u8, port: i64) -> i64 {
35 out[0] = 2; out[1] = 0
36 out[2] = (port >> 8) & 0xff
37 out[3] = port & 0xff
38 out[4] = 127; out[5] = 0; out[6] = 0; out[7] = 1
39 var i: i64 = 8
40 while i < 16 { out[i] = 0; i = i + 1 }
41 return 16
42}
43
44func hread_n(fd: i64, buf: *u8, n: i64) -> i64 {
45 var got: i64 = 0
46 while got < n {
47 let r: i64 = sys_read(fd, buf + got, n - got)
48 if r <= 0 { return 0 - 1 }
49 got = got + r
50 }
51 return got
52}
53
54func hsend_plain(fd: i64, buf: *u8, n: i64) -> i64 {
55 let hdr: *u8 = sys_mmap(8)
56 hdr[0] = (n >> 24) & 0xff
57 hdr[1] = (n >> 16) & 0xff
58 hdr[2] = (n >> 8) & 0xff
59 hdr[3] = n & 0xff
60 sys_write(fd, hdr, 4)
61 sys_write(fd, buf, n)
62 return n
63}
64
65func hrecv_plain(fd: i64, buf: *u8, cap: i64) -> i64 {
66 let hdr: *u8 = sys_mmap(8)
67 if hread_n(fd, hdr, 4) < 0 { return 0 - 1 }
68 let n: i64 = ((hdr[0] & 0xff) << 24) | ((hdr[1] & 0xff) << 16) | ((hdr[2] & 0xff) << 8) | (hdr[3] & 0xff)
69 if n > cap { return 0 - 2 }
70 if hread_n(fd, buf, n) < 0 { return 0 - 3 }
71 return n
72}
73
74// Send/recv AEAD app-data record (inner type=23 = application_data).
75func hsend_app(fd: i64, key: *u8, iv: *u8, seq: i64, p: *u8, plen: i64) -> i64 {
76 let hdr: *u8 = sys_mmap(16)
77 let ct: *u8 = sys_mmap(plen + 64)
78 let tag: *u8 = sys_mmap(16)
79 let vrd: i64 = nx_tls13_record_encrypt(key, iv, seq, p, plen, 23, 0, hdr, ct, tag)
80 if vrd != NX_TLS13_REC_VERDICT_OK { return 0 - 1 }
81 sys_write(fd, hdr, 5)
82 sys_write(fd, ct, plen + 1)
83 sys_write(fd, tag, 16)
84 return 0
85}
86
87func hrecv_app(fd: i64, key: *u8, iv: *u8, seq: i64, out: *u8, out_cap: i64) -> i64 {
88 let hdr: *u8 = sys_mmap(16)
89 if hread_n(fd, hdr, 5) < 0 { return 0 - 1 }
90 let total: i64 = ((hdr[3] & 0xff) << 8) | (hdr[4] & 0xff)
91 if total < 17 { return 0 - 2 }
92 let ct_len: i64 = total - 16
93 let buf: *u8 = sys_mmap(total + 16)
94 if hread_n(fd, buf, total) < 0 { return 0 - 3 }
95 let tag: *u8 = sys_mmap(16)
96 var ti: i64 = 0
97 while ti < 16 { tag[ti] = buf[ct_len + ti]; ti = ti + 1 }
98 let rct: *i64 = sys_mmap(8) as *i64
99 let rln: *i64 = sys_mmap(8) as *i64
100 let vrd: i64 = nx_tls13_record_decrypt(key, iv, seq, hdr, buf, ct_len, tag, out, rct, rln)
101 if vrd != NX_TLS13_REC_VERDICT_OK { return 0 - 4 }
102 return rln[0]
103}
104
105// Same handshake-type AEAD send/recv as full_tcp (inner type=22).
106func hsend_aead(fd: i64, key: *u8, iv: *u8, seq: i64, p: *u8, plen: i64) -> i64 {
107 let hdr: *u8 = sys_mmap(16)
108 let ct: *u8 = sys_mmap(plen + 64)
109 let tag: *u8 = sys_mmap(16)
110 let vrd: i64 = nx_tls13_record_encrypt(key, iv, seq, p, plen, 22, 0, hdr, ct, tag)
111 if vrd != NX_TLS13_REC_VERDICT_OK { return 0 - 1 }
112 sys_write(fd, hdr, 5)
113 sys_write(fd, ct, plen + 1)
114 sys_write(fd, tag, 16)
115 return 0
116}
117
118func hrecv_aead(fd: i64, key: *u8, iv: *u8, seq: i64, out: *u8, out_cap: i64) -> i64 {
119 let hdr: *u8 = sys_mmap(16)
120 if hread_n(fd, hdr, 5) < 0 { return 0 - 1 }
121 let total: i64 = ((hdr[3] & 0xff) << 8) | (hdr[4] & 0xff)
122 if total < 17 { return 0 - 2 }
123 let ct_len: i64 = total - 16
124 let buf: *u8 = sys_mmap(total + 16)
125 if hread_n(fd, buf, total) < 0 { return 0 - 3 }
126 let tag: *u8 = sys_mmap(16)
127 var ti: i64 = 0
128 while ti < 16 { tag[ti] = buf[ct_len + ti]; ti = ti + 1 }
129 let rct: *i64 = sys_mmap(8) as *i64
130 let rln: *i64 = sys_mmap(8) as *i64
131 let vrd: i64 = nx_tls13_record_decrypt(key, iv, seq, hdr, buf, ct_len, tag, out, rct, rln)
132 if vrd != NX_TLS13_REC_VERDICT_OK { return 0 - 4 }
133 return rln[0]
134}
135
136// ---- bundle + setup helpers ----
137
138func halloc_bundle() -> *u8 {
139 let bundle: *u8 = sys_mmap(64)
140 let bp: *i64 = bundle as *i64
141 var i: i64 = 0
142 while i < 7 {
143 let buf: *u8 = sys_mmap(64)
144 bp[i] = buf as i64
145 i = i + 1
146 }
147 return bundle
148}
149
150func hbundle_ptr(bundle: *u8, slot: i64) -> *u8 {
151 let bp: *i64 = bundle as *i64
152 return bp[slot] as *u8
153}
154
155func hsetup_keypair(priv: *u8, pub: *u8) -> i64 {
156 let base: *u8 = sys_mmap(64)
157 base[0] = 9
158 var bi: i64 = 1
159 while bi < 32 { base[bi] = 0; bi = bi + 1 }
160 x25519(priv, base, pub)
161 return 0
162}
163
164// Deterministic 32-byte fill from base byte; X25519 private keys use
165// the upper 5 bits cleared / bit 254 set RFC 7748 clamp, applied by
166// the X25519 layer -- any 32 bytes are valid input.
167func hfill_priv(out: *u8, base: i64) -> i64 {
168 var i: i64 = 0
169 while i < 32 { out[i] = (base + i * 3) & 0xff; i = i + 1 }
170 return 32
171}
172
173func hfill_empty_hash(out: *u8) -> i64 {
174 out[0]=0xe3; out[1]=0xb0; out[2]=0xc4; out[3]=0x42
175 out[4]=0x98; out[5]=0xfc; out[6]=0x1c; out[7]=0x14
176 out[8]=0x9a; out[9]=0xfb; out[10]=0xf4; out[11]=0xc8
177 out[12]=0x99; out[13]=0x6f; out[14]=0xb9; out[15]=0x24
178 out[16]=0x27; out[17]=0xae; out[18]=0x41; out[19]=0xe4
179 out[20]=0x64; out[21]=0x9b; out[22]=0x93; out[23]=0x4c
180 out[24]=0xa4; out[25]=0x95; out[26]=0x99; out[27]=0x1b
181 out[28]=0x78; out[29]=0x52; out[30]=0xb8; out[31]=0x55
182 return 32
183}
184
185func hfill_random(out: *u8, base: i64) -> i64 {
186 var i: i64 = 0
187 while i < 32 { out[i] = (base + i) & 0xff; i = i + 1 }
188 return 32
189}
190
191func hderive_keys(my_priv: *u8, peer_pub: *u8, th: *u8, eh: *u8, bundle: *u8) -> i64 {
192 let hs: *u8 = hbundle_ptr(bundle, 0)
193 let chts: *u8 = hbundle_ptr(bundle, 1)
194 let shts: *u8 = hbundle_ptr(bundle, 2)
195 let ck: *u8 = hbundle_ptr(bundle, 3)
196 let civ: *u8 = hbundle_ptr(bundle, 4)
197 let sk: *u8 = hbundle_ptr(bundle, 5)
198 let siv: *u8 = hbundle_ptr(bundle, 6)
199 tls13_handshake_compute_handshake_keys(my_priv, peer_pub, th, eh, hs, chts, shts, ck, civ, sk, siv)
200 return 0
201}
202
203func hemit_send_ch(fd: i64, c_pub: *u8, ch_out: *u8, ch_cap: i64) -> i64 {
204 let c_random: *u8 = sys_mmap(64)
205 hfill_random(c_random, 0xc0)
206 let sni: *u8 = sys_mmap(16)
207 sni[0]=0x65; sni[1]=0x78; sni[2]=0x61; sni[3]=0x6d
208 sni[4]=0x70; sni[5]=0x6c; sni[6]=0x65; sni[7]=0x2e
209 sni[8]=0x63; sni[9]=0x6f; sni[10]=0x6d
210 let n: i64 = tls13_client_hello_emit(c_random, sni, 11, c_pub, ch_out, ch_cap)
211 if n < 0 { return n }
212 hsend_plain(fd, ch_out, n)
213 return n
214}
215
216func hparse_sh_get_pub(sh: *u8, sh_len: i64, pub_out: *i64) -> i64 {
217 let p_lv: *i64 = sys_mmap(16) as *i64
218 let p_ro: *i64 = sys_mmap(16) as *i64
219 let p_cs: *i64 = sys_mmap(16) as *i64
220 let p_eo: *i64 = sys_mmap(16) as *i64
221 let p_el: *i64 = sys_mmap(16) as *i64
222 let pv: i64 = tls13_server_hello_parse(sh, sh_len, p_lv, p_ro, p_cs, p_eo, p_el)
223 if pv != NX_TLS13_HELLO_VERDICT_OK { return pv }
224 let ks_off: *i64 = sys_mmap(16) as *i64
225 let ks_len: *i64 = sys_mmap(16) as *i64
226 let fv: i64 = tls13_ext_find(sh + p_eo[0], p_el[0], EXT_KEY_SHARE, ks_off, ks_len)
227 if fv != NX_TLS13_HELLO_VERDICT_OK { return fv }
228 pub_out[0] = ((sh as i64) + p_eo[0] + ks_off[0] + 4)
229 return 0
230}
231
232func hparse_ch_get_pub(ch: *u8, ch_len: i64, sid_o: *i64, sid_l: *i64, pub_out: *i64) -> i64 {
233 let p_ro: *i64 = sys_mmap(16) as *i64
234 let p_eo: *i64 = sys_mmap(16) as *i64
235 let p_el: *i64 = sys_mmap(16) as *i64
236 let pv: i64 = tls13_server_parse_client_hello(ch, ch_len, p_ro, sid_o, sid_l, p_eo, p_el)
237 if pv != NX_TLS13_SERVER_VERDICT_OK { return pv }
238 let ks_off: *i64 = sys_mmap(16) as *i64
239 let ks_len: *i64 = sys_mmap(16) as *i64
240 let fv: i64 = tls13_ext_find(ch + p_eo[0], p_el[0], EXT_KEY_SHARE, ks_off, ks_len)
241 if fv != NX_TLS13_HELLO_VERDICT_OK { return fv }
242 pub_out[0] = ((ch as i64) + p_eo[0] + ks_off[0] + 6)
243 return 0
244}
245
246func hbuild_th(ch: *u8, ch_len: i64, sh: *u8, sh_len: i64, th_out: *u8, tx_out: *i64) -> i64 {
247 let tx: *u8 = nx_tls13_transcript_new()
248 nx_tls13_transcript_update(tx, ch, ch_len)
249 nx_tls13_transcript_update(tx, sh, sh_len)
250 nx_tls13_transcript_snapshot(tx, th_out)
251 tx_out[0] = tx as i64
252 return 0
253}
254
255func haead_dispatch(fd: i64, key: *u8, iv: *u8, seq: i64, st: i64, shts: *u8, tx: *u8) -> i64 {
256 let buf: *u8 = sys_mmap(1024)
257 let n: i64 = hrecv_aead(fd, key, iv, seq, buf, 1024)
258 if n < 0 { return n }
259 let c_out: *i64 = sys_mmap(16) as *i64
260 let vrd: i64 = tls13_client_dispatch_handshake_message(st, buf, n, shts, tx, c_out)
261 if vrd != NX_TLS13_CLIENT_VERDICT_OK { return 0 - 100 }
262 return c_out[0]
263}
264
265// ---- canned EE/Cert/CV + SF compute (same as full_tcp) ----
266
267func hbuild_canned(ee: *u8, cert: *u8, cv: *u8) -> i64 {
268 ee[0] = HT_ENCRYPTED_EXTENSIONS & 0xff
269 ee[1]=0; ee[2]=0; ee[3]=2; ee[4]=0; ee[5]=0
270
271 cert[0] = HT_CERTIFICATE & 0xff
272 cert[1]=0; cert[2]=0; cert[3]=19
273 cert[4]=0; cert[5]=0; cert[6]=0; cert[7]=15
274 cert[8]=0; cert[9]=0; cert[10]=10
275 var i: i64 = 0
276 while i < 10 { cert[11+i] = 0x30+i; i = i + 1 }
277 cert[21]=0; cert[22]=0
278
279 cv[0] = HT_CERTIFICATE_VERIFY & 0xff
280 cv[1]=0; cv[2]=0; cv[3]=68
281 cv[4]=0x08; cv[5]=0x07
282 cv[6]=0; cv[7]=64
283 var j: i64 = 0
284 while j < 64 { cv[8+j] = 0x90 + (j & 0x0f); j = j + 1 }
285 return 0
286}
287
288func hcompute_sf(tx: *u8, shts: *u8, sf_out: *u8) -> i64 {
289 let pre: *u8 = sys_mmap(64)
290 nx_tls13_transcript_snapshot(tx, pre)
291 let fk: *u8 = sys_mmap(64)
292 tls13_finished_key(shts, 32, fk)
293 let mac: *u8 = sys_mmap(64)
294 nx_tls13_finished_compute(fk, 32, pre, 32, mac)
295 sf_out[0] = HT_FINISHED & 0xff
296 sf_out[1]=0; sf_out[2]=0; sf_out[3]=32
297 var i: i64 = 0
298 while i < 32 { sf_out[4+i] = mac[i]; i = i + 1 }
299 return 36
300}
301
302func hserver_send_flight(fd: i64, bundle: *u8, tx: *u8) -> i64 {
303 let sk: *u8 = hbundle_ptr(bundle, 5)
304 let siv: *u8 = hbundle_ptr(bundle, 6)
305 let shts: *u8 = hbundle_ptr(bundle, 2)
306
307 let ee: *u8 = sys_mmap(64)
308 let cert: *u8 = sys_mmap(64)
309 let cv: *u8 = sys_mmap(128)
310 hbuild_canned(ee, cert, cv)
311 nx_tls13_transcript_update(tx, ee, 6)
312 nx_tls13_transcript_update(tx, cert, 23)
313 nx_tls13_transcript_update(tx, cv, 72)
314
315 let sf: *u8 = sys_mmap(64)
316 let sf_len: i64 = hcompute_sf(tx, shts, sf)
317 nx_tls13_transcript_update(tx, sf, sf_len)
318
319 if hsend_aead(fd, sk, siv, 0, ee, 6) != 0 { return 80 }
320 if hsend_aead(fd, sk, siv, 1, cert, 23) != 0 { return 81 }
321 if hsend_aead(fd, sk, siv, 2, cv, 72) != 0 { return 82 }
322 if hsend_aead(fd, sk, siv, 3, sf, 36) != 0 { return 83 }
323 return 0
324}
325
326func hserver_recv_cf(fd: i64, bundle: *u8, tx: *u8) -> i64 {
327 let ck: *u8 = hbundle_ptr(bundle, 3)
328 let civ: *u8 = hbundle_ptr(bundle, 4)
329 let chts: *u8 = hbundle_ptr(bundle, 1)
330 let cf: *u8 = sys_mmap(64)
331 let n: i64 = hrecv_aead(fd, ck, civ, 0, cf, 64)
332 if n != 36 { return 90 }
333 let s_out: *i64 = sys_mmap(16) as *i64
334 let vrd: i64 = tls13_server_dispatch_client_finished(cf, n, chts, tx, s_out)
335 if vrd != NX_TLS13_SERVER_VERDICT_OK { return 91 }
336 if s_out[0] != NX_TLS13_SSTATE_CONNECTED { return 92 }
337 return 0
338}
339
340// ---- HTTP exchange after handshake ----
341
342func hbuild_http_get(out: *u8) -> i64 {
343 out[0]=0x47; out[1]=0x45; out[2]=0x54; out[3]=0x20 // GET
344 out[4]=0x2f; out[5]=0x20 // /
345 out[6]=0x48; out[7]=0x54; out[8]=0x54; out[9]=0x50 // HTTP
346 out[10]=0x2f; out[11]=0x31; out[12]=0x2e; out[13]=0x31 // /1.1
347 out[14]=0x0d; out[15]=0x0a // \r\n
348 out[16]=0x48; out[17]=0x6f; out[18]=0x73; out[19]=0x74 // Host
349 out[20]=0x3a; out[21]=0x20 // :
350 out[22]=0x6c; out[23]=0x6f; out[24]=0x63; out[25]=0x61 // loca
351 out[26]=0x6c; out[27]=0x68; out[28]=0x6f; out[29]=0x73 // lhos
352 out[30]=0x74 // t
353 out[31]=0x0d; out[32]=0x0a; out[33]=0x0d; out[34]=0x0a // \r\n\r\n
354 return 35
355}
356
357func hbuild_http_200(out: *u8) -> i64 {
358 out[0]=0x48; out[1]=0x54; out[2]=0x54; out[3]=0x50
359 out[4]=0x2f; out[5]=0x31; out[6]=0x2e; out[7]=0x31
360 out[8]=0x20; out[9]=0x32; out[10]=0x30; out[11]=0x30
361 out[12]=0x20; out[13]=0x4f; out[14]=0x4b
362 out[15]=0x0d; out[16]=0x0a
363 out[17]=0x43; out[18]=0x6f; out[19]=0x6e; out[20]=0x74
364 out[21]=0x65; out[22]=0x6e; out[23]=0x74; out[24]=0x2d
365 out[25]=0x4c; out[26]=0x65; out[27]=0x6e; out[28]=0x67
366 out[29]=0x74; out[30]=0x68; out[31]=0x3a; out[32]=0x20
367 out[33]=0x35
368 out[34]=0x0d; out[35]=0x0a
369 out[36]=0x0d; out[37]=0x0a
370 out[38]=0x68; out[39]=0x65; out[40]=0x6c; out[41]=0x6c
371 out[42]=0x6f
372 return 43
373}
374
375// Client setup: produce private key + ephemeral pub key.
376func hclient_setup(out_pub: *u8) -> *u8 {
377 let c_priv: *u8 = sys_mmap(64)
378 hfill_priv(c_priv, 0x40)
379 hsetup_keypair(c_priv, out_pub)
380 return c_priv
381}
382
383// Client exchange CH/SH, return server-pub via slot, ch_len/sh_len via slots.
384func hclient_xchg_hello(cfd: i64, c_pub: *u8, ch: *u8, sh: *u8, lens: *i64, pub_slot: *i64) -> i64 {
385 let ch_len: i64 = hemit_send_ch(cfd, c_pub, ch, 1024)
386 if ch_len < 0 { return 12 }
387 let sh_len: i64 = hrecv_plain(cfd, sh, 1024)
388 if sh_len < 0 { return 13 }
389 if hparse_sh_get_pub(sh, sh_len, pub_slot) != 0 { return 14 }
390 lens[0] = ch_len; lens[1] = sh_len
391 return 0
392}
393
394func run_client_http(cfd: i64, ck: *u8, civ: *u8, sk: *u8, siv: *u8) -> i64 {
395 // Client sends encrypted HTTP GET with client-key seq=1
396 // (seq 0 already used for the encrypted CF).
397 let req: *u8 = sys_mmap(64)
398 let req_len: i64 = hbuild_http_get(req)
399 if hsend_app(cfd, ck, civ, 1, req, req_len) != 0 { return 70 }
400
401 // Client recvs encrypted HTTP response with server-key seq=4
402 // (seq 0..3 used for the encrypted EE/Cert/CV/SF).
403 let resp: *u8 = sys_mmap(4096)
404 let n: i64 = hrecv_app(cfd, sk, siv, 4, resp, 4096)
405 if n < 12 { return 71 }
406 if (resp[0] & 0xff) != 0x48 { return 72 } // 'H'
407 if (resp[9] & 0xff) != 0x32 { return 73 } // '2'
408 if (resp[10] & 0xff) != 0x30 { return 74 } // '0'
409 if (resp[11] & 0xff) != 0x30 { return 75 } // '0'
410 return 0
411}
412
413func run_client_after_keys(cfd: i64, bundle: *u8, tx: *u8) -> i64 {
414 let sk: *u8 = hbundle_ptr(bundle, 5)
415 let siv: *u8 = hbundle_ptr(bundle, 6)
416 let ck: *u8 = hbundle_ptr(bundle, 3)
417 let civ: *u8 = hbundle_ptr(bundle, 4)
418 let chts: *u8 = hbundle_ptr(bundle, 1)
419 let shts: *u8 = hbundle_ptr(bundle, 2)
420
421 let s1: i64 = haead_dispatch(cfd, sk, siv, 0, NX_TLS13_CSTATE_WAIT_EE, shts, tx)
422 if s1 < 0 { return 20 }
423 let s2: i64 = haead_dispatch(cfd, sk, siv, 1, s1, shts, tx)
424 if s2 < 0 { return 30 }
425 let s3: i64 = haead_dispatch(cfd, sk, siv, 2, s2, shts, tx)
426 if s3 < 0 { return 40 }
427 let s4: i64 = haead_dispatch(cfd, sk, siv, 3, s3, shts, tx)
428 if s4 < 0 { return 50 }
429 if s4 != NX_TLS13_CSTATE_CONNECTED { return 60 }
430
431 let cf: *u8 = sys_mmap(64)
432 let cf_len: i64 = tls13_client_emit_finished(chts, tx, cf)
433 if cf_len != 36 { return 61 }
434 if hsend_aead(cfd, ck, civ, 0, cf, cf_len) != 0 { return 62 }
435
436 return run_client_http(cfd, ck, civ, sk, siv)
437}
438
439// Client side: full handshake then encrypted HTTP exchange.
440func run_https_client(cfd: i64) -> i64 {
441 let c_pub: *u8 = sys_mmap(64)
442 let c_priv: *u8 = hclient_setup(c_pub)
443 let ch: *u8 = sys_mmap(1024)
444 let sh: *u8 = sys_mmap(1024)
445 let lens: *i64 = sys_mmap(16) as *i64
446 let pub_slot: *i64 = sys_mmap(8) as *i64
447 let rc: i64 = hclient_xchg_hello(cfd, c_pub, ch, sh, lens, pub_slot)
448 if rc != 0 { return rc }
449 let th: *u8 = sys_mmap(64)
450 let tx_slot: *i64 = sys_mmap(8) as *i64
451 hbuild_th(ch, lens[0], sh, lens[1], th, tx_slot)
452 let eh: *u8 = sys_mmap(64)
453 hfill_empty_hash(eh)
454 let bundle: *u8 = halloc_bundle()
455 let s_pub: *u8 = pub_slot[0] as *u8
456 let tx: *u8 = tx_slot[0] as *u8
457 hderive_keys(c_priv, s_pub, th, eh, bundle)
458 return run_client_after_keys(cfd, bundle, tx)
459}
460
461// Server side: full handshake then encrypted HTTP exchange.
462// Compose key derivation + flight + recv + http into one step,
463// taking a pre-built ServerContext blob. Each helper stays small.
464//
465// ServerCtx layout (8 ptrs): 0=s_priv, 1=c_pub, 2=tx, 3=bundle.
466
467func run_server_http(cfd: i64, bundle: *u8) -> i64 {
468 let sk: *u8 = hbundle_ptr(bundle, 5)
469 let siv: *u8 = hbundle_ptr(bundle, 6)
470 let ck: *u8 = hbundle_ptr(bundle, 3)
471 let civ: *u8 = hbundle_ptr(bundle, 4)
472
473 // Server recvs encrypted HTTP request with client-key seq=1.
474 let req: *u8 = sys_mmap(4096)
475 let n: i64 = hrecv_app(cfd, ck, civ, 1, req, 4096)
476 if n < 14 { return 110 }
477 if (req[0] & 0xff) != 0x47 { return 111 } // 'G'
478 if (req[6] & 0xff) != 0x48 { return 112 } // 'H'
479
480 // Server sends encrypted HTTP 200 with server-key seq=4.
481 let resp: *u8 = sys_mmap(64)
482 let resp_len: i64 = hbuild_http_200(resp)
483 if hsend_app(cfd, sk, siv, 4, resp, resp_len) != 0 { return 113 }
484 return 0
485}
486
487func run_server_after_sh(cfd: i64, ctx: *i64) -> i64 {
488 let s_priv: *u8 = ctx[0] as *u8
489 let c_pub: *u8 = ctx[1] as *u8
490 let tx: *u8 = ctx[2] as *u8
491 let bundle: *u8 = ctx[3] as *u8
492
493 let eh: *u8 = sys_mmap(64)
494 hfill_empty_hash(eh)
495 let th: *u8 = sys_mmap(64)
496 nx_tls13_transcript_snapshot(tx, th)
497 hderive_keys(s_priv, c_pub, th, eh, bundle)
498
499 let fr: i64 = hserver_send_flight(cfd, bundle, tx)
500 if fr != 0 { return fr }
501 let cr: i64 = hserver_recv_cf(cfd, bundle, tx)
502 if cr != 0 { return cr }
503 return run_server_http(cfd, bundle)
504}
505
506func run_https_server(cfd: i64) -> i64 {
507 let s_priv: *u8 = sys_mmap(64)
508 hfill_priv(s_priv, 0x80)
509 let s_pub: *u8 = sys_mmap(64)
510 hsetup_keypair(s_priv, s_pub)
511
512 let ch: *u8 = sys_mmap(1024)
513 let ch_len: i64 = hrecv_plain(cfd, ch, 1024)
514 if ch_len < 0 { return 100 }
515
516 let sid_o: *i64 = sys_mmap(16) as *i64
517 let sid_l: *i64 = sys_mmap(16) as *i64
518 let cpub_slot: *i64 = sys_mmap(8) as *i64
519 if hparse_ch_get_pub(ch, ch_len, sid_o, sid_l, cpub_slot) != 0 { return 101 }
520 let c_pub: *u8 = cpub_slot[0] as *u8
521
522 let s_random: *u8 = sys_mmap(64)
523 hfill_random(s_random, 0x70)
524 let sh: *u8 = sys_mmap(512)
525 let sh_len: i64 = tls13_server_emit_server_hello(s_random, ch + sid_o[0], sid_l[0], s_pub, sh, 512)
526 if sh_len < 0 { return 103 }
527 hsend_plain(cfd, sh, sh_len)
528
529 let th: *u8 = sys_mmap(64)
530 let tx_slot: *i64 = sys_mmap(8) as *i64
531 hbuild_th(ch, ch_len, sh, sh_len, th, tx_slot)
532
533 let bundle: *u8 = halloc_bundle()
534 let ctx: *i64 = sys_mmap(64) as *i64
535 ctx[0] = s_priv as i64
536 ctx[1] = c_pub as i64
537 ctx[2] = tx_slot[0]
538 ctx[3] = bundle as i64
539 return run_server_after_sh(cfd, ctx)
540}
541
542func main() -> i64 {
543 let addr: *u8 = sys_mmap(16)
544 hbuild_addr(addr, HPORT)
545 let lfd: i64 = sys_socket(AF_INET, SOCK_STREAM, 0)
546 if lfd < 0 { return 1 }
547 if sys_bind(lfd, addr, 16) < 0 { return 2 }
548 if sys_listen(lfd, 4) < 0 { return 3 }
549
550 let pid: i64 = sys_fork()
551 if pid < 0 { return 4 }
552
553 if pid == 0 {
554 var spin: i64 = 0
555 while spin < 200000 { spin = spin + 1 }
556 let ccfd: i64 = sys_socket(AF_INET, SOCK_STREAM, 0)
557 if ccfd < 0 { return 5 }
558 if nx_connect_bounded(ccfd, addr, 16, NX_CONN_DEFAULT_MS) < 0 { return 6 }
559 return run_https_client(ccfd)
560 }
561
562 let scfd: i64 = sys_accept(lfd)
563 if scfd < 0 { return 7 }
564 let sr: i64 = run_https_server(scfd)
565 if sr != 0 { return sr }
566
567 let status: *i64 = sys_mmap(8) as *i64
568 sys_wait4(pid, status, 0)
569 return wait_exit_code(*status)
570}