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}