nx_tls13_read_record_from_fd_loopback_test.nx source
↩ module page · 125 lines · 4597 B
1// nx_tls13_read_record_from_fd_loopback_test.nx -- REAL happy-
2// path KAT for nx_tls13_read_record_from_fd over real TCP loopback.
3//
4// The existing nx_tls13_read_record_from_fd_test.nx preamble
5// explicitly documents that sys_pipe2 is unreliable in qemu so
6// the original test only exercises bounds-check + read-failure
7// paths. That left the primitive's HAPPY PATH (read a real
8// 5-byte TLS record header + body from a real bidirectional
9// socket) UNVERIFIED.
10//
11// This file closes that gap using the same fork+child socket
12// loopback pattern as nx_https_loopback_test (which has been
13// verified to work in qemu-riscv64-static), exercising ONLY the
14// record-reader primitive in isolation.
15//
16// Test shape:
17// 1. parent: socket + bind + listen on loopback port
18// 2. fork
19// 3. child: socket + connect; build a real TLS record bytes
20// (type=22 handshake, version 0x0303, payload "ABCDE");
21// sys_write the 10-byte record + close.
22// 4. parent: accept; call nx_tls13_read_record_from_fd(accepted_fd,
23// out_buf, out_cap); verify
24// (a) return value == 10 (5 header + 5 payload)
25// (b) header bytes are correct (0x16 0x03 0x03 0x00 0x05)
26// (c) payload bytes are "ABCDE"
27// 5. parent waits for child + returns child's exit code OR a
28// verdict-specific code if anything mismatched
29//
30// expect_exit: 0
31// license_tier: ORIGINAL
32
33import "nx_syscalls.nx"
34import "nx_connect.nx" // bounded connect: a raw sys_connect hangs ~127s on a black-holed host
35import "nx_tls13.nx"
36import "nx_tls13_read_record_from_fd.nx"
37
38const TEST_PORT: i64 = 19453
39
40func build_addr(out: *u8, port: i64) -> i64 {
41 out[0] = 2; out[1] = 0
42 out[2] = (port >> 8) & 0xff
43 out[3] = port & 0xff
44 out[4] = 127; out[5] = 0; out[6] = 0; out[7] = 1
45 var i: i64 = 8
46 while i < 16 { out[i] = 0; i = i + 1 }
47 return 16
48}
49
50// Child: connect to the loopback port + write a real TLS record.
51// Record = 5-byte header (type=22, version 0x0303, length=5) +
52// 5-byte payload "ABCDE" = 0x41 0x42 0x43 0x44 0x45.
53func child_send_record(addr: *u8) -> i64 {
54 var spin: i64 = 0
55 while spin < 200000 { spin = spin + 1 }
56 let cfd: i64 = sys_socket(AF_INET, SOCK_STREAM, 0)
57 if cfd < 0 { return 11 }
58 if nx_connect_bounded(cfd, addr, 16, NX_CONN_DEFAULT_MS) < 0 { return 12 }
59
60 let rec: *u8 = sys_mmap(16)
61 rec[0] = 0x16 // type=22 handshake
62 rec[1] = 0x03 // version high
63 rec[2] = 0x03 // version low
64 rec[3] = 0x00 // length high
65 rec[4] = 0x05 // length low
66 rec[5] = 0x41 // 'A'
67 rec[6] = 0x42 // 'B'
68 rec[7] = 0x43 // 'C'
69 rec[8] = 0x44 // 'D'
70 rec[9] = 0x45 // 'E'
71 let wn: i64 = sys_write(cfd, rec, 10)
72 if wn != 10 { return 13 }
73 sys_close(cfd)
74 return 0
75}
76
77// Parent: accept + call nx_tls13_read_record_from_fd + verify.
78func parent_read_and_verify(lfd: i64) -> i64 {
79 let scfd: i64 = sys_accept(lfd)
80 if scfd < 0 { return 21 }
81
82 let out: *u8 = sys_mmap(64)
83 let total: i64 = nx_tls13_read_record_from_fd(scfd, out, 64)
84 if total != 10 { return 22 } // 5 + 5
85
86 // Header verification
87 if (out[0] & 0xff) != 0x16 { return 23 }
88 if (out[1] & 0xff) != 0x03 { return 24 }
89 if (out[2] & 0xff) != 0x03 { return 25 }
90 if (out[3] & 0xff) != 0x00 { return 26 }
91 if (out[4] & 0xff) != 0x05 { return 27 }
92
93 // Payload verification
94 if (out[5] & 0xff) != 0x41 { return 28 } // 'A'
95 if (out[6] & 0xff) != 0x42 { return 29 }
96 if (out[7] & 0xff) != 0x43 { return 30 }
97 if (out[8] & 0xff) != 0x44 { return 31 }
98 if (out[9] & 0xff) != 0x45 { return 32 } // 'E'
99
100 sys_close(scfd)
101 return 0
102}
103
104func main() -> i64 {
105 let addr: *u8 = sys_mmap(16)
106 build_addr(addr, TEST_PORT)
107 let lfd: i64 = sys_socket(AF_INET, SOCK_STREAM, 0)
108 if lfd < 0 { return 1 }
109 if sys_bind(lfd, addr, 16) < 0 { return 2 }
110 if sys_listen(lfd, 4) < 0 { return 3 }
111
112 let pid: i64 = sys_fork()
113 if pid < 0 { return 4 }
114
115 if pid == 0 {
116 return child_send_record(addr)
117 }
118
119 let r: i64 = parent_read_and_verify(lfd)
120 if r != 0 { return r }
121
122 let status: *i64 = sys_mmap(8) as *i64
123 sys_wait4(pid, status, 0)
124 return wait_exit_code(*status)
125}