code wiki / _hdl_build / nx_tls13_app_send_fd_gate.nx
nx_tls13_app_send_fd_gate.nx source
↩ module page · 133 lines · 6189 B
1// nx_tls13_app_send_fd_gate.nx -- ENGINEER gate for the chunked TLS app-data
2// sender. Evidence-driven, re-runnable, no network: fabricates a CONNECTED
3// Tls13ServerSession with fixed ChaCha20-Poly1305 keys, sends a 40000-byte
4// payload to a real file fd, then plays the CLIENT side -- walks the wire
5// bytes record by record, asserts every record plaintext <= 16384 (the RFC
6// 8446 ยง5.1 cap the old single-record path violated), decrypts each record
7// with the KAT'd nx_tls13_record_decrypt_v2 under the same keys, reassembles,
8// and byte-compares against the original payload. Also gates the empty-
9// payload path (one empty record) and the partner invariant: exactly
10// ceil(40000/16000) = 3 records, seq increments 0,1,2.
11// license_tier: ORIGINAL
12
13import "nx_tls13_app_send_fd.nx"
14
15func g_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
16func g_pn(v: i64) -> i64 {
17 let b: *u8 = sys_mmap(28)
18 if v == 0 { b[0]=48; sys_write(1,b,1); return 0 }
19 var d: i64=0; var x: i64=v
20 while x>0 { d=d+1; x=x/10 }
21 var i: i64=d-1; x=v
22 while i>=0 { b[i]=(48+(x%10)) as u8; x=x/10; i=i-1 }
23 sys_write(1,b,d); return 0
24}
25func g_check(name: *u8, cond: i64) -> i64 {
26 if cond==1 { g_puts(" PASS " as *u8) } else { g_puts(" FAIL " as *u8) }
27 g_puts(name); g_puts("\n" as *u8); return cond
28}
29
30func main() -> i64 {
31 g_puts("nx_tls13_app_send_fd gate\n" as *u8)
32 var pass: i64 = 0
33 var total: i64 = 0
34
35 // ---- fabricate a CONNECTED session with fixed app keys ----
36 let srand: *u8 = sys_mmap(32)
37 let spriv: *u8 = sys_mmap(32)
38 var i: i64 = 0
39 while i < 32 { srand[i] = (i) as u8; spriv[i] = (64 + i) as u8; i = i + 1 }
40 let s: *Tls13ServerSession = nx_tls13_server_session_new(srand, spriv)
41 if (s as i64) == 0 { g_puts("FAIL session_new\n" as *u8); return 1 }
42
43 let key: *u8 = sys_mmap(32)
44 let iv: *u8 = sys_mmap(12)
45 i = 0
46 while i < 32 { key[i] = (i * 3 + 1) as u8; i = i + 1 }
47 i = 0
48 while i < 12 { iv[i] = (i * 5 + 2) as u8; i = i + 1 }
49 s.state = NX_TLS13_SSTATE_CONNECTED
50 s.server_app_traffic_key = key
51 s.server_app_iv = iv
52 s.server_app_seq = 0
53
54 // ---- 40000-byte deterministic payload ----
55 let plen: i64 = 40000
56 let payload: *u8 = sys_mmap(plen)
57 i = 0
58 while i < plen { payload[i] = ((i * 7 + 13) & 0xff) as u8; i = i + 1 }
59
60 // ---- send to a real file fd via the chunked path ----
61 let rec_buf: *u8 = sys_mmap(NX_TLS13_SENDFD_REC_MIN + 512)
62 let path: *u8 = "/tmp/nx_sendfd_gate.bin" as *u8
63 let fd: i64 = sys_openat_wr(path, 0x1a4)
64 if fd < 0 { g_puts("FAIL open\n" as *u8); return 1 }
65 let sent: i64 = nx_tls13_app_send_fd(s, payload, plen, fd, rec_buf, NX_TLS13_SENDFD_REC_MIN + 512)
66 sys_close(fd)
67 pass = pass + g_check("send returns payload_len (40000)" as *u8, sent == plen); total = total + 1
68 pass = pass + g_check("session seq advanced to 3 (3 records)" as *u8, s.server_app_seq == 3); total = total + 1
69
70 // ---- client side: read wire bytes, walk + decrypt every record ----
71 let wire_len_box: *i64 = (sys_mmap(8)) as *i64
72 wire_len_box[0] = 0
73 let wire: *u8 = sys_read_file(path, wire_len_box)
74 let wn: i64 = wire_len_box[0]
75 // 3 records, each = plaintext + 5 header + 1 inner-type + 16 tag
76 pass = pass + g_check("wire length = 40000 + 3*22" as *u8, wn == plen + 66); total = total + 1
77
78 let plain_out: *u8 = sys_mmap(17000)
79 let rebuilt: *u8 = sys_mmap(plen + 64)
80 let ct_box: *i64 = (sys_mmap(8)) as *i64
81 let len_box: *i64 = (sys_mmap(8)) as *i64
82 var off: i64 = 0
83 var nrec: i64 = 0
84 var rb: i64 = 0
85 var all_caps_ok: i64 = 1
86 var all_dec_ok: i64 = 1
87 var seq: i64 = 0
88 while off + 5 <= wn {
89 let hdr: *u8 = (wire as i64 + off) as *u8
90 if (hdr[0] as i64) != 0x17 { all_dec_ok = 0; off = wn }
91 else {
92 let body_len: i64 = ((hdr[3] as i64) << 8) | (hdr[4] as i64)
93 if body_len > 16384 + 256 { all_caps_ok = 0 }
94 let ct_len: i64 = body_len - 16
95 // plaintext = ct_len - 1 (inner type byte); RFC cap check
96 if ct_len - 1 > 16384 { all_caps_ok = 0 }
97 let ct: *u8 = (wire as i64 + off + 5) as *u8
98 let tag: *u8 = (wire as i64 + off + 5 + ct_len) as *u8
99 let rv: i64 = nx_tls13_record_decrypt_v2(
100 0x1303, key, iv, seq, hdr, ct, ct_len, tag,
101 plain_out, ct_box, len_box)
102 if rv != NX_TLS13_REC_VERDICT_OK { all_dec_ok = 0 }
103 if ct_box[0] != CT_APPLICATION_DATA { all_dec_ok = 0 }
104 var k: i64 = 0
105 while k < len_box[0] { rebuilt[rb + k] = plain_out[k]; k = k + 1 }
106 rb = rb + len_box[0]
107 seq = seq + 1
108 nrec = nrec + 1
109 off = off + 5 + body_len
110 }
111 }
112 pass = pass + g_check("record count = 3 (chunked, not one giant record)" as *u8, nrec == 3); total = total + 1
113 pass = pass + g_check("every record plaintext <= 16384 (RFC 8446 5.1)" as *u8, all_caps_ok == 1); total = total + 1
114 pass = pass + g_check("every record decrypts OK under app keys" as *u8, all_dec_ok == 1); total = total + 1
115 pass = pass + g_check("reassembled length = 40000" as *u8, rb == plen); total = total + 1
116
117 var same: i64 = 1
118 i = 0
119 while i < plen { if rebuilt[i] != payload[i] { same = 0; i = plen } else { i = i + 1 } }
120 pass = pass + g_check("reassembled plaintext byte-identical" as *u8, same == 1); total = total + 1
121
122 // ---- empty payload still emits exactly one record ----
123 let fd2: i64 = sys_openat_wr("/tmp/nx_sendfd_gate0.bin" as *u8, 0x1a4)
124 let seq_before: i64 = s.server_app_seq
125 let sent0: i64 = nx_tls13_app_send_fd(s, payload, 0, fd2, rec_buf, NX_TLS13_SENDFD_REC_MIN + 512)
126 sys_close(fd2)
127 pass = pass + g_check("empty payload -> rc 0, one record" as *u8, sent0 == 0); total = total + 1
128 pass = pass + g_check("empty payload advanced seq by 1" as *u8, s.server_app_seq == seq_before + 1); total = total + 1
129
130 g_puts("gate: " as *u8); g_pn(pass); g_puts("/" as *u8); g_pn(total); g_puts("\n" as *u8)
131 if pass == total { return 0 }
132 return 1
133}