nx_tls13_aead_record_tcp_test.nx source
↩ module page · 150 lines · 5084 B
1// nx_tls13_aead_record_tcp_test.nx -- send + recv ONE AEAD-protected
2// TLS 1.3 record over real TCP via fork loopback (RV64/qemu).
3//
4// Uses nx_tls13_record_encrypt/decrypt directly with hard-coded key
5// and IV. Proves the AEAD record layer works over real kernel
6// sockets on RV64 -- the missing piece needed to combine with the
7// already-passing nx_tls13_handshake_tcp test for full encrypted
8// HTTPS-class traffic.
9//
10// Keeps every function small per F6 friction-catalog discipline.
11//
12// expect_exit: 0
13// license_tier: ORIGINAL
14
15import "nx_syscalls.nx"
16import "nx_connect.nx" // bounded connect: a raw sys_connect hangs ~127s on a black-holed host
17import "nx_tls13_record.nx"
18
19const TEST_PORT: i64 = 19445
20
21func build_addr(out: *u8, port: i64) -> i64 {
22 out[0] = 2; out[1] = 0
23 out[2] = (port >> 8) & 0xff
24 out[3] = port & 0xff
25 out[4] = 127; out[5] = 0; out[6] = 0; out[7] = 1
26 var i: i64 = 8
27 while i < 16 { out[i] = 0; i = i + 1 }
28 return 16
29}
30
31func setup_key_iv(key_out: *u8, iv_out: *u8) -> i64 {
32 var i: i64 = 0
33 while i < 32 { key_out[i] = (0x40 + i) & 0xff; i = i + 1 }
34 i = 0
35 while i < 12 { iv_out[i] = (0xa0 + i) & 0xff; i = i + 1 }
36 return 0
37}
38
39// Read N bytes from fd into buf (looping on partial reads).
40func read_n(fd: i64, buf: *u8, n: i64) -> i64 {
41 var got: i64 = 0
42 while got < n {
43 let r: i64 = sys_read(fd, buf + got, n - got)
44 if r <= 0 { return 0 - 1 }
45 got = got + r
46 }
47 return got
48}
49
50// Send one encrypted handshake-type record (inner type = 22).
51func send_record(fd: i64, key: *u8, iv: *u8, seq: i64, payload: *u8, payload_len: i64) -> i64 {
52 let hdr: *u8 = sys_mmap(16)
53 let ct: *u8 = sys_mmap(payload_len + 64)
54 let tag: *u8 = sys_mmap(16)
55 let vrd: i64 = nx_tls13_record_encrypt(key, iv, seq, payload, payload_len, 22, 0, hdr, ct, tag)
56 if vrd != NX_TLS13_REC_VERDICT_OK { return 0 - 1 }
57 sys_write(fd, hdr, 5)
58 sys_write(fd, ct, payload_len + 1)
59 sys_write(fd, tag, 16)
60 return 0
61}
62
63// Recv one encrypted record, decrypt to out, return plaintext bytes.
64func recv_record(fd: i64, key: *u8, iv: *u8, seq: i64, out: *u8, out_cap: i64) -> i64 {
65 let hdr: *u8 = sys_mmap(16)
66 if read_n(fd, hdr, 5) < 0 { return 0 - 1 }
67 let total: i64 = ((hdr[3] & 0xff) << 8) | (hdr[4] & 0xff)
68 if total < 17 { return 0 - 2 }
69 let ct_len: i64 = total - 16
70 let buf: *u8 = sys_mmap(total + 16)
71 if read_n(fd, buf, total) < 0 { return 0 - 3 }
72 let tag: *u8 = sys_mmap(16)
73 var ti: i64 = 0
74 while ti < 16 { tag[ti] = buf[ct_len + ti]; ti = ti + 1 }
75 let rct: *i64 = sys_mmap(8) as *i64
76 let rln: *i64 = sys_mmap(8) as *i64
77 let vrd: i64 = nx_tls13_record_decrypt(key, iv, seq, hdr, buf, ct_len, tag, out, rct, rln)
78 if vrd != NX_TLS13_REC_VERDICT_OK { return 0 - 4 }
79 return rln[0]
80}
81
82// Child runs the encrypted send + recv roundtrip.
83func run_client(cfd: i64) -> i64 {
84 let key: *u8 = sys_mmap(32)
85 let iv: *u8 = sys_mmap(16)
86 setup_key_iv(key, iv)
87
88 let msg: *u8 = sys_mmap(16)
89 msg[0]=0x50; msg[1]=0x49; msg[2]=0x4e; msg[3]=0x47 // "PING"
90 let s: i64 = send_record(cfd, key, iv, 0, msg, 4)
91 if s != 0 { return 10 }
92
93 let reply: *u8 = sys_mmap(64)
94 let n: i64 = recv_record(cfd, key, iv, 0, reply, 64)
95 if n != 4 { return 20 + (0 - n) }
96 if (reply[0] & 0xff) != 0x50 { return 30 } // 'P'
97 if (reply[1] & 0xff) != 0x4f { return 31 } // 'O'
98 if (reply[2] & 0xff) != 0x4e { return 32 } // 'N'
99 if (reply[3] & 0xff) != 0x47 { return 33 } // 'G'
100 return 0
101}
102
103// Parent: recv encrypted PING, send encrypted PONG.
104func run_server(cfd: i64) -> i64 {
105 let key: *u8 = sys_mmap(32)
106 let iv: *u8 = sys_mmap(16)
107 setup_key_iv(key, iv)
108
109 let in_buf: *u8 = sys_mmap(64)
110 let n: i64 = recv_record(cfd, key, iv, 0, in_buf, 64)
111 if n != 4 { return 40 + (0 - n) }
112 if (in_buf[0] & 0xff) != 0x50 { return 50 } // 'P'
113 if (in_buf[3] & 0xff) != 0x47 { return 51 } // 'G' of PING
114
115 let reply: *u8 = sys_mmap(16)
116 reply[0]=0x50; reply[1]=0x4f; reply[2]=0x4e; reply[3]=0x47 // "PONG"
117 let s: i64 = send_record(cfd, key, iv, 0, reply, 4)
118 if s != 0 { return 60 }
119 return 0
120}
121
122func main() -> i64 {
123 let addr: *u8 = sys_mmap(16)
124 build_addr(addr, TEST_PORT)
125 let lfd: i64 = sys_socket(AF_INET, SOCK_STREAM, 0)
126 if lfd < 0 { return 1 }
127 if sys_bind(lfd, addr, 16) < 0 { return 2 }
128 if sys_listen(lfd, 4) < 0 { return 3 }
129
130 let pid: i64 = sys_fork()
131 if pid < 0 { return 4 }
132
133 if pid == 0 {
134 var spin: i64 = 0
135 while spin < 200000 { spin = spin + 1 }
136 let ccfd: i64 = sys_socket(AF_INET, SOCK_STREAM, 0)
137 if ccfd < 0 { return 5 }
138 if nx_connect_bounded(ccfd, addr, 16, NX_CONN_DEFAULT_MS) < 0 { return 6 }
139 return run_client(ccfd)
140 }
141
142 let scfd: i64 = sys_accept(lfd)
143 if scfd < 0 { return 7 }
144 let sr: i64 = run_server(scfd)
145 if sr != 0 { return sr }
146
147 let status: *i64 = sys_mmap(8) as *i64
148 sys_wait4(pid, status, 0)
149 return wait_exit_code(*status)
150}