nx_tls13_full_tcp_test.nx source
↩ module page · 479 lines · 16614 B
1// nx_tls13_full_tcp_test.nx -- full TLS 1.3 handshake over real TCP
2// with AEAD-protected EE/Cert/CV/SF/CF records using the
3// handshake-derived traffic keys.
4//
5// Wire bytes (from ServerHello onward) bit-identical to real TLS 1.3.
6//
7// Built per F6 friction-catalog discipline: every function <10 lets
8// + <6 params + single-line call args, no monolithic run_client.
9//
10// expect_exit: 0
11// license_tier: ORIGINAL
12
13import "nx_syscalls.nx"
14import "nx_connect.nx" // bounded connect: a raw sys_connect hangs ~127s on a black-holed host
15import "nx_x25519.nx"
16import "nx_tls13.nx"
17import "nx_tls13_ext.nx"
18import "nx_tls13_hello.nx"
19import "nx_tls13_finished.nx"
20import "nx_tls13_transcript.nx"
21import "nx_tls13_handshake.nx"
22import "nx_tls13_schedule.nx"
23import "nx_tls13_client.nx"
24import "nx_tls13_server.nx"
25import "nx_tls13_record.nx"
26
27const TEST_PORT: i64 = 19446
28
29// ---- low-level frame helpers ----
30
31func build_addr(out: *u8, port: i64) -> i64 {
32 out[0] = 2; out[1] = 0
33 out[2] = (port >> 8) & 0xff
34 out[3] = port & 0xff
35 out[4] = 127; out[5] = 0; out[6] = 0; out[7] = 1
36 var i: i64 = 8
37 while i < 16 { out[i] = 0; i = i + 1 }
38 return 16
39}
40
41func read_n(fd: i64, buf: *u8, n: i64) -> i64 {
42 var got: i64 = 0
43 while got < n {
44 let r: i64 = sys_read(fd, buf + got, n - got)
45 if r <= 0 { return 0 - 1 }
46 got = got + r
47 }
48 return got
49}
50
51func send_plain(fd: i64, buf: *u8, n: i64) -> i64 {
52 let hdr: *u8 = sys_mmap(8)
53 hdr[0] = (n >> 24) & 0xff
54 hdr[1] = (n >> 16) & 0xff
55 hdr[2] = (n >> 8) & 0xff
56 hdr[3] = n & 0xff
57 sys_write(fd, hdr, 4)
58 sys_write(fd, buf, n)
59 return n
60}
61
62func recv_plain(fd: i64, buf: *u8, cap: i64) -> i64 {
63 let hdr: *u8 = sys_mmap(8)
64 if read_n(fd, hdr, 4) < 0 { return 0 - 1 }
65 let n: i64 = ((hdr[0] & 0xff) << 24) | ((hdr[1] & 0xff) << 16) | ((hdr[2] & 0xff) << 8) | (hdr[3] & 0xff)
66 if n > cap { return 0 - 2 }
67 if read_n(fd, buf, n) < 0 { return 0 - 3 }
68 return n
69}
70
71// ---- AEAD record helpers ----
72
73func send_aead(fd: i64, key: *u8, iv: *u8, seq: i64, payload: *u8, payload_len: i64) -> i64 {
74 let hdr: *u8 = sys_mmap(16)
75 let ct: *u8 = sys_mmap(payload_len + 64)
76 let tag: *u8 = sys_mmap(16)
77 let vrd: i64 = nx_tls13_record_encrypt(key, iv, seq, payload, payload_len, 22, 0, hdr, ct, tag)
78 if vrd != NX_TLS13_REC_VERDICT_OK { return 0 - 1 }
79 sys_write(fd, hdr, 5)
80 sys_write(fd, ct, payload_len + 1)
81 sys_write(fd, tag, 16)
82 return 0
83}
84
85func recv_aead(fd: i64, key: *u8, iv: *u8, seq: i64, out: *u8, out_cap: i64) -> i64 {
86 let hdr: *u8 = sys_mmap(16)
87 if read_n(fd, hdr, 5) < 0 { return 0 - 1 }
88 let total: i64 = ((hdr[3] & 0xff) << 8) | (hdr[4] & 0xff)
89 if total < 17 { return 0 - 2 }
90 let ct_len: i64 = total - 16
91 let buf: *u8 = sys_mmap(total + 16)
92 if read_n(fd, buf, total) < 0 { return 0 - 3 }
93 let tag: *u8 = sys_mmap(16)
94 var ti: i64 = 0
95 while ti < 16 { tag[ti] = buf[ct_len + ti]; ti = ti + 1 }
96 let rct: *i64 = sys_mmap(8) as *i64
97 let rln: *i64 = sys_mmap(8) as *i64
98 let vrd: i64 = nx_tls13_record_decrypt(key, iv, seq, hdr, buf, ct_len, tag, out, rct, rln)
99 if vrd != NX_TLS13_REC_VERDICT_OK { return 0 - 4 }
100 return rln[0]
101}
102
103// ---- handshake helpers ----
104
105func setup_keypair(priv: *u8, pub: *u8) -> i64 {
106 let base: *u8 = sys_mmap(64)
107 base[0] = 9
108 var bi: i64 = 1
109 while bi < 32 { base[bi] = 0; bi = bi + 1 }
110 x25519(priv, base, pub)
111 return 0
112}
113
114func fill_client_priv(out: *u8) -> i64 {
115 out[0]=0x49; out[1]=0xaf; out[2]=0x42; out[3]=0xba
116 out[4]=0x7f; out[5]=0x99; out[6]=0x94; out[7]=0x85
117 out[8]=0x2d; out[9]=0x71; out[10]=0x3e; out[11]=0xf2
118 out[12]=0x78; out[13]=0x4b; out[14]=0xcb; out[15]=0xca
119 out[16]=0xa7; out[17]=0x91; out[18]=0x1d; out[19]=0xe2
120 out[20]=0x6a; out[21]=0xdc; out[22]=0x56; out[23]=0x42
121 out[24]=0xcb; out[25]=0x63; out[26]=0x45; out[27]=0x40
122 out[28]=0xe7; out[29]=0xea; out[30]=0x50; out[31]=0x05
123 return 32
124}
125
126func fill_server_priv(out: *u8) -> i64 {
127 out[0]=0xb1; out[1]=0x58; out[2]=0x0e; out[3]=0xea
128 out[4]=0xdf; out[5]=0x6d; out[6]=0xd5; out[7]=0x89
129 out[8]=0xb8; out[9]=0xef; out[10]=0x4f; out[11]=0x2d
130 out[12]=0x56; out[13]=0x52; out[14]=0x57; out[15]=0x8c
131 out[16]=0xc8; out[17]=0x10; out[18]=0xe9; out[19]=0x98
132 out[20]=0x01; out[21]=0x91; out[22]=0xec; out[23]=0x8d
133 out[24]=0x05; out[25]=0x83; out[26]=0x08; out[27]=0xce
134 out[28]=0xa2; out[29]=0x16; out[30]=0xa2; out[31]=0x1e
135 return 32
136}
137
138func fill_empty_hash(out: *u8) -> i64 {
139 out[0]=0xe3; out[1]=0xb0; out[2]=0xc4; out[3]=0x42
140 out[4]=0x98; out[5]=0xfc; out[6]=0x1c; out[7]=0x14
141 out[8]=0x9a; out[9]=0xfb; out[10]=0xf4; out[11]=0xc8
142 out[12]=0x99; out[13]=0x6f; out[14]=0xb9; out[15]=0x24
143 out[16]=0x27; out[17]=0xae; out[18]=0x41; out[19]=0xe4
144 out[20]=0x64; out[21]=0x9b; out[22]=0x93; out[23]=0x4c
145 out[24]=0xa4; out[25]=0x95; out[26]=0x99; out[27]=0x1b
146 out[28]=0x78; out[29]=0x52; out[30]=0xb8; out[31]=0x55
147 return 32
148}
149
150func fill_client_random(out: *u8) -> i64 {
151 var i: i64 = 0
152 while i < 32 { out[i] = 0xc0 + i; i = i + 1 }
153 return 32
154}
155
156func fill_server_random(out: *u8) -> i64 {
157 var i: i64 = 0
158 while i < 32 { out[i] = 0x70 + i; i = i + 1 }
159 return 32
160}
161
162func fill_sni_example_com(out: *u8) -> i64 {
163 out[0]=0x65; out[1]=0x78; out[2]=0x61; out[3]=0x6d
164 out[4]=0x70; out[5]=0x6c; out[6]=0x65; out[7]=0x2e
165 out[8]=0x63; out[9]=0x6f; out[10]=0x6d
166 return 11
167}
168
169// Allocate a KeyBundle = 7 ptrs * 8 bytes; each ptr points at a
170// caller-owned 64-byte buffer. Index 0..6 = hs, chts, shts, c_key,
171// c_iv, s_key, s_iv.
172func alloc_key_bundle() -> *u8 {
173 let bundle: *u8 = sys_mmap(64)
174 let bp: *i64 = bundle as *i64
175 var i: i64 = 0
176 while i < 7 {
177 let buf: *u8 = sys_mmap(64)
178 bp[i] = buf as i64
179 i = i + 1
180 }
181 return bundle
182}
183
184func bundle_ptr(bundle: *u8, slot: i64) -> *u8 {
185 let bp: *i64 = bundle as *i64
186 return bp[slot] as *u8
187}
188
189// Derive all handshake keys via the orchestrator, store into bundle.
190func derive_handshake_keys(my_priv: *u8, peer_pub: *u8, th: *u8, eh: *u8, bundle: *u8) -> i64 {
191 let hs: *u8 = bundle_ptr(bundle, 0)
192 let chts: *u8 = bundle_ptr(bundle, 1)
193 let shts: *u8 = bundle_ptr(bundle, 2)
194 let ck: *u8 = bundle_ptr(bundle, 3)
195 let civ: *u8 = bundle_ptr(bundle, 4)
196 let sk: *u8 = bundle_ptr(bundle, 5)
197 let siv: *u8 = bundle_ptr(bundle, 6)
198 tls13_handshake_compute_handshake_keys(my_priv, peer_pub, th, eh, hs, chts, shts, ck, civ, sk, siv)
199 return 0
200}
201
202// Build, send ClientHello. Returns ch_len or negative.
203func emit_and_send_ch(fd: i64, c_pub: *u8, ch_out: *u8, ch_cap: i64) -> i64 {
204 let c_random: *u8 = sys_mmap(64)
205 fill_client_random(c_random)
206 let sni: *u8 = sys_mmap(16)
207 fill_sni_example_com(sni)
208 let n: i64 = tls13_client_hello_emit(c_random, sni, 11, c_pub, ch_out, ch_cap)
209 if n < 0 { return n }
210 send_plain(fd, ch_out, n)
211 return n
212}
213
214// Parse SH bytes already received; returns *u8 ptr to server's pubkey
215// (a pointer INTO sh, valid until sh is freed).
216func parse_sh_recover_pub(sh: *u8, sh_len: i64, pub_out_slot: *i64) -> i64 {
217 let p_lv: *i64 = sys_mmap(16) as *i64
218 let p_ro: *i64 = sys_mmap(16) as *i64
219 let p_cs: *i64 = sys_mmap(16) as *i64
220 let p_eo: *i64 = sys_mmap(16) as *i64
221 let p_el: *i64 = sys_mmap(16) as *i64
222 let pv: i64 = tls13_server_hello_parse(sh, sh_len, p_lv, p_ro, p_cs, p_eo, p_el)
223 if pv != NX_TLS13_HELLO_VERDICT_OK { return pv }
224 let ks_off: *i64 = sys_mmap(16) as *i64
225 let ks_len: *i64 = sys_mmap(16) as *i64
226 let fv: i64 = tls13_ext_find(sh + p_eo[0], p_el[0], EXT_KEY_SHARE, ks_off, ks_len)
227 if fv != NX_TLS13_HELLO_VERDICT_OK { return fv }
228 pub_out_slot[0] = ((sh as i64) + p_eo[0] + ks_off[0] + 4)
229 return 0
230}
231
232// Build transcript over CH + SH and snapshot.
233func build_transcript_th(ch: *u8, ch_len: i64, sh: *u8, sh_len: i64, th_out: *u8, tx_out_slot: *i64) -> i64 {
234 let tx: *u8 = nx_tls13_transcript_new()
235 nx_tls13_transcript_update(tx, ch, ch_len)
236 nx_tls13_transcript_update(tx, sh, sh_len)
237 nx_tls13_transcript_snapshot(tx, th_out)
238 tx_out_slot[0] = tx as i64
239 return 0
240}
241
242// Dispatch ONE encrypted handshake record; returns new state or negative.
243func aead_dispatch(fd: i64, key: *u8, iv: *u8, seq: i64, st: i64, shts: *u8, tx: *u8) -> i64 {
244 let buf: *u8 = sys_mmap(1024)
245 let n: i64 = recv_aead(fd, key, iv, seq, buf, 1024)
246 if n < 0 { return n }
247 let c_out: *i64 = sys_mmap(16) as *i64
248 let vrd: i64 = tls13_client_dispatch_handshake_message(st, buf, n, shts, tx, c_out)
249 if vrd != NX_TLS13_CLIENT_VERDICT_OK { return 0 - 100 }
250 return c_out[0]
251}
252
253// Client side: dispatch the 4 encrypted records (EE,Cert,CV,SF),
254// emit + send encrypted CF, read ACK. Returns 0 or error code.
255func run_client_finish(fd: i64, bundle: *u8, tx: *u8) -> i64 {
256 let sk: *u8 = bundle_ptr(bundle, 5)
257 let siv: *u8 = bundle_ptr(bundle, 6)
258 let ck: *u8 = bundle_ptr(bundle, 3)
259 let civ: *u8 = bundle_ptr(bundle, 4)
260 let chts: *u8 = bundle_ptr(bundle, 1)
261 let shts: *u8 = bundle_ptr(bundle, 2)
262
263 let s1: i64 = aead_dispatch(fd, sk, siv, 0, NX_TLS13_CSTATE_WAIT_EE, shts, tx)
264 if s1 < 0 { return 20 }
265 let s2: i64 = aead_dispatch(fd, sk, siv, 1, s1, shts, tx)
266 if s2 < 0 { return 30 }
267 let s3: i64 = aead_dispatch(fd, sk, siv, 2, s2, shts, tx)
268 if s3 < 0 { return 40 }
269 let s4: i64 = aead_dispatch(fd, sk, siv, 3, s3, shts, tx)
270 if s4 < 0 { return 50 }
271 if s4 != NX_TLS13_CSTATE_CONNECTED { return 60 }
272
273 let cf: *u8 = sys_mmap(64)
274 let cf_len: i64 = tls13_client_emit_finished(chts, tx, cf)
275 if cf_len != 36 { return 61 }
276 if send_aead(fd, ck, civ, 0, cf, cf_len) != 0 { return 62 }
277
278 let ack: *u8 = sys_mmap(8)
279 if read_n(fd, ack, 1) < 0 { return 63 }
280 if (ack[0] & 0xff) != 0x00 { return 64 }
281 return 0
282}
283
284// Client side: do all setup, then call run_client_finish.
285func run_client(cfd: i64) -> i64 {
286 let c_priv: *u8 = sys_mmap(64)
287 fill_client_priv(c_priv)
288 let c_pub: *u8 = sys_mmap(64)
289 setup_keypair(c_priv, c_pub)
290
291 let ch: *u8 = sys_mmap(1024)
292 let ch_len: i64 = emit_and_send_ch(cfd, c_pub, ch, 1024)
293 if ch_len < 0 { return 12 }
294
295 let sh: *u8 = sys_mmap(1024)
296 let sh_len: i64 = recv_plain(cfd, sh, 1024)
297 if sh_len < 0 { return 13 }
298
299 let pub_slot: *i64 = sys_mmap(8) as *i64
300 if parse_sh_recover_pub(sh, sh_len, pub_slot) != 0 { return 14 }
301 let s_pub: *u8 = pub_slot[0] as *u8
302
303 let th: *u8 = sys_mmap(64)
304 let tx_slot: *i64 = sys_mmap(8) as *i64
305 build_transcript_th(ch, ch_len, sh, sh_len, th, tx_slot)
306 let tx: *u8 = tx_slot[0] as *u8
307
308 let eh: *u8 = sys_mmap(64)
309 fill_empty_hash(eh)
310 let bundle: *u8 = alloc_key_bundle()
311 derive_handshake_keys(c_priv, s_pub, th, eh, bundle)
312
313 return run_client_finish(cfd, bundle, tx)
314}
315
316// ---- server-side helpers ----
317
318func parse_ch_recover_pub(ch: *u8, ch_len: i64, sid_off_out: *i64, sid_len_out: *i64, pub_out_slot: *i64) -> i64 {
319 let p_ro: *i64 = sys_mmap(16) as *i64
320 let p_eo: *i64 = sys_mmap(16) as *i64
321 let p_el: *i64 = sys_mmap(16) as *i64
322 let pv: i64 = tls13_server_parse_client_hello(ch, ch_len, p_ro, sid_off_out, sid_len_out, p_eo, p_el)
323 if pv != NX_TLS13_SERVER_VERDICT_OK { return pv }
324 let ks_off: *i64 = sys_mmap(16) as *i64
325 let ks_len: *i64 = sys_mmap(16) as *i64
326 let fv: i64 = tls13_ext_find(ch + p_eo[0], p_el[0], EXT_KEY_SHARE, ks_off, ks_len)
327 if fv != NX_TLS13_HELLO_VERDICT_OK { return fv }
328 pub_out_slot[0] = ((ch as i64) + p_eo[0] + ks_off[0] + 6)
329 return 0
330}
331
332// Build canned EE/Cert/CV/SF and feed CH..CV into transcript; emit SF.
333// Each output buffer is caller-owned. Returns 0.
334func build_canned_payloads(ee: *u8, cert: *u8, cv: *u8) -> i64 {
335 ee[0] = HT_ENCRYPTED_EXTENSIONS & 0xff
336 ee[1]=0; ee[2]=0; ee[3]=2
337 ee[4]=0; ee[5]=0
338
339 cert[0] = HT_CERTIFICATE & 0xff
340 cert[1]=0; cert[2]=0; cert[3]=19
341 cert[4]=0
342 cert[5]=0; cert[6]=0; cert[7]=15
343 cert[8]=0; cert[9]=0; cert[10]=10
344 var i: i64 = 0
345 while i < 10 { cert[11+i] = 0x30+i; i = i + 1 }
346 cert[21]=0; cert[22]=0
347
348 cv[0] = HT_CERTIFICATE_VERIFY & 0xff
349 cv[1]=0; cv[2]=0; cv[3]=68
350 cv[4]=0x08; cv[5]=0x07
351 cv[6]=0; cv[7]=64
352 var j: i64 = 0
353 while j < 64 { cv[8+j] = 0x90 + (j & 0x0f); j = j + 1 }
354 return 0
355}
356
357func compute_sf(s_tx: *u8, shts: *u8, sf_out: *u8) -> i64 {
358 let pre: *u8 = sys_mmap(64)
359 nx_tls13_transcript_snapshot(s_tx, pre)
360 let fk: *u8 = sys_mmap(64)
361 tls13_finished_key(shts, 32, fk)
362 let mac: *u8 = sys_mmap(64)
363 nx_tls13_finished_compute(fk, 32, pre, 32, mac)
364 sf_out[0] = HT_FINISHED & 0xff
365 sf_out[1]=0; sf_out[2]=0; sf_out[3]=32
366 var i: i64 = 0
367 while i < 32 { sf_out[4+i] = mac[i]; i = i + 1 }
368 return 36
369}
370
371func server_send_encrypted_flight(fd: i64, bundle: *u8, s_tx: *u8) -> i64 {
372 let sk: *u8 = bundle_ptr(bundle, 5)
373 let siv: *u8 = bundle_ptr(bundle, 6)
374 let shts: *u8 = bundle_ptr(bundle, 2)
375
376 let ee: *u8 = sys_mmap(64)
377 let cert: *u8 = sys_mmap(64)
378 let cv: *u8 = sys_mmap(128)
379 build_canned_payloads(ee, cert, cv)
380 nx_tls13_transcript_update(s_tx, ee, 6)
381 nx_tls13_transcript_update(s_tx, cert, 23)
382 nx_tls13_transcript_update(s_tx, cv, 72)
383
384 let sf: *u8 = sys_mmap(64)
385 let sf_len: i64 = compute_sf(s_tx, shts, sf)
386 nx_tls13_transcript_update(s_tx, sf, sf_len)
387
388 if send_aead(fd, sk, siv, 0, ee, 6) != 0 { return 80 }
389 if send_aead(fd, sk, siv, 1, cert, 23) != 0 { return 81 }
390 if send_aead(fd, sk, siv, 2, cv, 72) != 0 { return 82 }
391 if send_aead(fd, sk, siv, 3, sf, 36) != 0 { return 83 }
392 return 0
393}
394
395func server_recv_cf_and_ack(fd: i64, bundle: *u8, s_tx: *u8) -> i64 {
396 let ck: *u8 = bundle_ptr(bundle, 3)
397 let civ: *u8 = bundle_ptr(bundle, 4)
398 let chts: *u8 = bundle_ptr(bundle, 1)
399
400 let cf: *u8 = sys_mmap(64)
401 let n: i64 = recv_aead(fd, ck, civ, 0, cf, 64)
402 if n != 36 { return 90 }
403 let s_out: *i64 = sys_mmap(16) as *i64
404 let vrd: i64 = tls13_server_dispatch_client_finished(cf, n, chts, s_tx, s_out)
405 if vrd != NX_TLS13_SERVER_VERDICT_OK { return 91 }
406 if s_out[0] != NX_TLS13_SSTATE_CONNECTED { return 92 }
407 let ack: *u8 = sys_mmap(8)
408 ack[0] = 0
409 sys_write(fd, ack, 1)
410 return 0
411}
412
413func run_server(cfd: i64) -> i64 {
414 let s_priv: *u8 = sys_mmap(64)
415 fill_server_priv(s_priv)
416 let s_pub: *u8 = sys_mmap(64)
417 setup_keypair(s_priv, s_pub)
418
419 let ch: *u8 = sys_mmap(1024)
420 let ch_len: i64 = recv_plain(cfd, ch, 1024)
421 if ch_len < 0 { return 70 }
422
423 let sid_o: *i64 = sys_mmap(16) as *i64
424 let sid_l: *i64 = sys_mmap(16) as *i64
425 let cpub_slot: *i64 = sys_mmap(8) as *i64
426 if parse_ch_recover_pub(ch, ch_len, sid_o, sid_l, cpub_slot) != 0 { return 71 }
427 let c_pub: *u8 = cpub_slot[0] as *u8
428
429 let s_random: *u8 = sys_mmap(64)
430 fill_server_random(s_random)
431 let sh: *u8 = sys_mmap(512)
432 let sh_len: i64 = tls13_server_emit_server_hello(s_random, ch + sid_o[0], sid_l[0], s_pub, sh, 512)
433 if sh_len < 0 { return 73 }
434 send_plain(cfd, sh, sh_len)
435
436 let th: *u8 = sys_mmap(64)
437 let tx_slot: *i64 = sys_mmap(8) as *i64
438 build_transcript_th(ch, ch_len, sh, sh_len, th, tx_slot)
439 let s_tx: *u8 = tx_slot[0] as *u8
440
441 let eh: *u8 = sys_mmap(64)
442 fill_empty_hash(eh)
443 let bundle: *u8 = alloc_key_bundle()
444 derive_handshake_keys(s_priv, c_pub, th, eh, bundle)
445
446 let fr: i64 = server_send_encrypted_flight(cfd, bundle, s_tx)
447 if fr != 0 { return fr }
448 return server_recv_cf_and_ack(cfd, bundle, s_tx)
449}
450
451func main() -> i64 {
452 let addr: *u8 = sys_mmap(16)
453 build_addr(addr, TEST_PORT)
454 let lfd: i64 = sys_socket(AF_INET, SOCK_STREAM, 0)
455 if lfd < 0 { return 1 }
456 if sys_bind(lfd, addr, 16) < 0 { return 2 }
457 if sys_listen(lfd, 4) < 0 { return 3 }
458
459 let pid: i64 = sys_fork()
460 if pid < 0 { return 4 }
461
462 if pid == 0 {
463 var spin: i64 = 0
464 while spin < 200000 { spin = spin + 1 }
465 let ccfd: i64 = sys_socket(AF_INET, SOCK_STREAM, 0)
466 if ccfd < 0 { return 5 }
467 if nx_connect_bounded(ccfd, addr, 16, NX_CONN_DEFAULT_MS) < 0 { return 6 }
468 return run_client(ccfd)
469 }
470
471 let scfd: i64 = sys_accept(lfd)
472 if scfd < 0 { return 7 }
473 let sr: i64 = run_server(scfd)
474 if sr != 0 { return sr }
475
476 let status: *i64 = sys_mmap(8) as *i64
477 sys_wait4(pid, status, 0)
478 return wait_exit_code(*status)
479}