nx_tls13_server_session_app_data_test.nx source
↩ module page · 203 lines · 7407 B
1// nx_tls13_server_session_app_data_test.nx -- round-trip the app
2// data layer on a CONNECTED session. Server sends payload, server
3// also "receives" a client-encrypted payload (built using the same
4// shared keys for the smoke).
5//
6// Closed-form invariants:
7// (a) Wrong state -> negative
8// (b) Drive through full handshake to CONNECTED
9// (c) app_send returns positive byte count, output starts 0x17
10// (d) server_app_seq increments
11// (e) Build a synthetic client app record + app_recv returns
12// exact plaintext (bit-for-bit match)
13// (f) client_app_seq increments
14// (g) Decrypting a tampered record -> PROTOCOL_ERR; seq NOT advanced
15//
16// expect_exit: 0
17// license_tier: ORIGINAL
18
19import "nx_syscalls.nx"
20import "nx_x25519.nx"
21import "nx_x25519_ephemeral.nx"
22import "nx_hmac.nx"
23import "nx_tls13.nx"
24import "nx_tls13_hello.nx"
25import "nx_tls13_kdf.nx"
26import "nx_tls13_record.nx"
27import "nx_tls13_transcript.nx"
28import "nx_tls13_server_session.nx"
29import "nx_tls13_server_session_recv_ch.nx"
30import "nx_tls13_server_session_emit_sh.nx"
31import "nx_tls13_server_session_derive_hs.nx"
32import "nx_tls13_server_session_derive_traffic.nx"
33import "nx_tls13_server_session_emit_ee.nx"
34import "nx_tls13_server_session_emit_sf.nx"
35import "nx_tls13_server_session_recv_cf.nx"
36import "nx_tls13_server_session_app_data.nx"
37
38func build_client_app_record(
39 cli_app_key: *u8, cli_app_iv: *u8, cli_app_seq: i64,
40 payload: *u8, payload_len: i64,
41 out: *u8, out_cap: i64
42) -> i64 {
43 let header: *u8 = sys_mmap(5)
44 let ct: *u8 = sys_mmap(payload_len + 17)
45 let tag: *u8 = sys_mmap(16)
46 let rv: i64 = nx_tls13_record_encrypt(
47 cli_app_key, cli_app_iv, cli_app_seq,
48 payload, payload_len,
49 CT_APPLICATION_DATA, 0,
50 header, ct, tag)
51 if rv != NX_TLS13_REC_VERDICT_OK { return -1 }
52
53 let total: i64 = 5 + payload_len + 1 + 16
54 if total > out_cap { return -1 }
55 var w: i64 = 0
56 var hi: i64 = 0
57 while hi < 5 { out[w + hi] = header[hi]; hi = hi + 1 }
58 w = w + 5
59 var ci: i64 = 0
60 while ci < payload_len + 1 { out[w + ci] = ct[ci]; ci = ci + 1 }
61 w = w + payload_len + 1
62 var ti: i64 = 0
63 while ti < 16 { out[w + ti] = tag[ti]; ti = ti + 1 }
64 return w + 16
65}
66
67func main() -> i64 {
68 let cli_priv: *u8 = sys_mmap(32)
69 let cli_pub: *u8 = sys_mmap(32)
70 let cli_rand: *u8 = sys_mmap(32)
71 var i: i64 = 0
72 while i < 32 {
73 cli_priv[i] = ((i + 17) & 0xff) as u8
74 cli_rand[i] = ((i + 50) & 0xff) as u8
75 i = i + 1
76 }
77 x25519_keypair_public(cli_priv, cli_pub)
78 let ch_buf: *u8 = sys_mmap(1024)
79 let ch_n: i64 = tls13_client_hello_emit(cli_rand, "nishifamily.com", 15, cli_pub, ch_buf, 1024)
80 if ch_n <= 0 { return 5 }
81
82 let srv_priv: *u8 = sys_mmap(32)
83 let srv_rand: *u8 = sys_mmap(32)
84 var k: i64 = 0
85 while k < 32 {
86 srv_priv[k] = ((k + 80) & 0xff) as u8
87 srv_rand[k] = ((k + 70) & 0xff) as u8
88 k = k + 1
89 }
90 let s: *Tls13ServerSession = nx_tls13_server_session_new(srv_rand, srv_priv)
91
92 // ===== (a) Wrong state =====
93 let bad_buf: *u8 = sys_mmap(512)
94 let r_wrong: i64 = nx_tls13_server_session_app_send(s, ch_buf, 10, bad_buf, 512)
95 let exp_bad: i64 = 0 - NX_TLS13_SSESSION_BAD_STATE
96 if r_wrong != exp_bad { return 10 }
97
98 // ===== Drive through full handshake to CONNECTED =====
99 nx_tls13_server_session_recv_ch(s, ch_buf, ch_n)
100 let sh_buf: *u8 = sys_mmap(512)
101 nx_tls13_server_session_emit_sh(s, sh_buf, 512)
102 nx_tls13_server_session_derive_hs_secrets(s)
103 nx_tls13_server_session_derive_traffic(s)
104 let ee_buf: *u8 = sys_mmap(256)
105 nx_tls13_server_session_emit_ee(s, ee_buf, 256)
106 let sf_buf: *u8 = sys_mmap(256)
107 nx_tls13_server_session_emit_sf(s, sf_buf, 256)
108
109 // Build client Finished using shared keys
110 let finished_label: *u8 = "finished"
111 let empty: *u8 = sys_mmap(1)
112 let finished_key_c: *u8 = sys_mmap(32)
113 tls13_hkdf_expand_label(s.client_hs_traffic_secret, finished_label, 8,
114 empty, 0, 32, finished_key_c)
115 let th: *u8 = sys_mmap(32)
116 nx_tls13_transcript_snapshot(s.transcript, th)
117 let verify_data: *u8 = sys_mmap(32)
118 hmac_sha256(finished_key_c, 32, th, 32, verify_data)
119 let cf_rec: *u8 = sys_mmap(256)
120
121 // Inline-build client Finished
122 let inner_len: i64 = 36
123 let inner: *u8 = sys_mmap(inner_len)
124 inner[0] = HT_FINISHED & 0xff
125 inner[1] = 0
126 inner[2] = 0
127 inner[3] = 32
128 var vi: i64 = 0
129 while vi < 32 { inner[4 + vi] = verify_data[vi]; vi = vi + 1 }
130 let cf_hdr: *u8 = sys_mmap(5)
131 let cf_ct: *u8 = sys_mmap(inner_len + 17)
132 let cf_tag: *u8 = sys_mmap(16)
133 nx_tls13_record_encrypt(
134 s.client_hs_traffic_key, s.client_hs_iv, s.client_seq,
135 inner, inner_len, CT_HANDSHAKE, 0,
136 cf_hdr, cf_ct, cf_tag)
137 var w_cf: i64 = 0
138 var c_hi: i64 = 0
139 while c_hi < 5 { cf_rec[w_cf + c_hi] = cf_hdr[c_hi]; c_hi = c_hi + 1 }
140 w_cf = w_cf + 5
141 var c_ci: i64 = 0
142 while c_ci < inner_len + 1 { cf_rec[w_cf + c_ci] = cf_ct[c_ci]; c_ci = c_ci + 1 }
143 w_cf = w_cf + inner_len + 1
144 var c_ti: i64 = 0
145 while c_ti < 16 { cf_rec[w_cf + c_ti] = cf_tag[c_ti]; c_ti = c_ti + 1 }
146 let cf_total: i64 = w_cf + 16
147
148 nx_tls13_server_session_recv_cf(s, cf_rec, cf_total)
149 if s.state != NX_TLS13_SSTATE_CONNECTED { return 20 }
150
151 // ===== (c) app_send =====
152 let payload_a: *u8 = "GET /index.html HTTP/1.1\r\nHost: nishifamily.com\r\n\r\n"
153 var pa_len: i64 = 0
154 while payload_a[pa_len] != 0 { pa_len = pa_len + 1 }
155 let send_buf: *u8 = sys_mmap(512)
156 let n_send: i64 = nx_tls13_server_session_app_send(s, payload_a, pa_len, send_buf, 512)
157 if n_send <= 0 { return 30 }
158 if send_buf[0] != 0x17 { return 31 } // app_data record header
159
160 // ===== (d) server_app_seq increments =====
161 if s.server_app_seq != 1 { return 40 }
162
163 // ===== (e) Build synthetic client app record + recv =====
164 let payload_b: *u8 = "HTTP/1.1 200 OK\r\n\r\nHello from substrate"
165 var pb_len: i64 = 0
166 while payload_b[pb_len] != 0 { pb_len = pb_len + 1 }
167 let cli_rec: *u8 = sys_mmap(256)
168 let cli_n: i64 = build_client_app_record(
169 s.client_app_traffic_key, s.client_app_iv, s.client_app_seq,
170 payload_b, pb_len, cli_rec, 256)
171 if cli_n <= 0 { return 50 }
172
173 let recv_buf: *u8 = sys_mmap(512)
174 let n_recv: i64 = nx_tls13_server_session_app_recv(s, cli_rec, cli_n, recv_buf, 512)
175 if n_recv != pb_len { return 51 }
176
177 // Bit-for-bit match
178 var bi: i64 = 0
179 var ok: i64 = 1
180 while bi < pb_len {
181 if recv_buf[bi] != payload_b[bi] { ok = 0 }
182 bi = bi + 1
183 }
184 if ok != 1 { return 52 }
185
186 // ===== (f) client_app_seq increments =====
187 if s.client_app_seq != 1 { return 60 }
188
189 // ===== (g) Tampered record -> PROTOCOL_ERR + seq NOT advanced =====
190 let bad_cli_rec: *u8 = sys_mmap(256)
191 var ti2: i64 = 0
192 while ti2 < cli_n { bad_cli_rec[ti2] = cli_rec[ti2]; ti2 = ti2 + 1 }
193 // Flip a byte in the ciphertext (not the header)
194 bad_cli_rec[10] = (bad_cli_rec[10] as i64 ^ 0xff) as u8
195
196 let save_seq: i64 = s.client_app_seq
197 let r_bad: i64 = nx_tls13_server_session_app_recv(s, bad_cli_rec, cli_n, recv_buf, 512)
198 let exp_pe: i64 = 0 - NX_TLS13_SSESSION_PROTOCOL_ERR
199 if r_bad != exp_pe { return 70 }
200 if s.client_app_seq != save_seq { return 71 }
201
202 return 0
203}