nx_tls13_client_session_recv_hs_test.nx source
↩ module page · 133 lines · 5875 B
1// nx_tls13_client_session_recv_hs_test.nx -- KAT for step 3c.3:
2// recv encrypted handshake records + dispatch loop.
3//
4// Full happy-path (synthetic encrypted record round-tripped end-to-end)
5// is queued; the underlying nx_tls13_loopback_test already exercises
6// the encrypt/decrypt round-trip + the underlying dispatcher's KAT
7// covers state-machine logic. This KAT verifies the WRAPPER's
8// contract surface:
9// - state guards (must be in WAIT_EE..WAIT_SF)
10// - record-length guards (too short = RECORD_FAIL)
11// - record-decrypt verdict propagation (wrong key/tag = RECORD_FAIL)
12// - server_seq increment on every call (even failures)
13// - sealed verdict gate
14//
15// expect_exit: 0
16// license_tier: ORIGINAL
17
18import "nx_syscalls.nx"
19import "nx_x509_trust_store.nx"
20import "nx_tls13.nx"
21import "nx_tls13_client_validate_certificate.nx"
22import "nx_tls13_client_session.nx"
23import "nx_tls13_client_session_recv_sh.nx"
24import "nx_tls13_client_session_recv_hs.nx"
25
26// Reuse build_sh from recv_sh test (inline for self-containment).
27func build_sh(out: *u8, server_random: *u8, server_pub: *u8) -> i64 {
28 out[0] = HT_SERVER_HELLO & 0xff
29 out[1] = 0; out[2] = 0; out[3] = 80
30 out[4] = 0x03; out[5] = 0x03
31 var i: i64 = 0
32 while i < 32 { out[6 + i] = server_random[i]; i = i + 1 }
33 out[38] = 0
34 out[39] = 0x13; out[40] = 0x01
35 out[41] = 0
36 out[42] = 0; out[43] = 40
37 out[44] = 0; out[45] = 0x33
38 out[46] = 0; out[47] = 36
39 out[48] = 0; out[49] = 0x1D
40 out[50] = 0; out[51] = 32
41 i = 0
42 while i < 32 { out[52 + i] = server_pub[i]; i = i + 1 }
43 return 84
44}
45
46func main() -> i64 {
47 let client_random: *u8 = sys_mmap(32)
48 var i: i64 = 0
49 while i < 32 { client_random[i] = (0xC0 + i) as u8; i = i + 1 }
50 let priv: *u8 = sys_mmap(32)
51 i = 0
52 while i < 32 { priv[i] = (0x40 + i) as u8; i = i + 1 }
53
54 let hostname: *u8 = sys_mmap(16)
55 hostname[0]=0x65; hostname[1]=0x78; hostname[2]=0x61
56 let store: *TrustStore = trust_store_alloc(4)
57 let val_ctx_raw: *u8 = sys_mmap(64)
58 let val_ctx: *TlsValidationContext = val_ctx_raw as *TlsValidationContext
59 val_ctx.store = store
60 val_ctx.sni_host = hostname
61 val_ctx.sni_host_len = 11
62 val_ctx.now_epoch = 1718452800
63
64 // ---- Test A: recv_hs from INIT state -> BAD_STATE ----
65 let s1: *Tls13ClientSession = nx_tls13_client_session_new(client_random, priv)
66 let dummy_rec: *u8 = sys_mmap(64)
67 let v_a: i64 = nx_tls13_client_session_recv_hs(s1, dummy_rec, 32, val_ctx)
68 if v_a != NX_TLS13_RECV_HS_BAD_STATE { return 1 }
69
70 // ---- Test B: recv_hs from CH_SENT state -> BAD_STATE ----
71 let sni: *u8 = sys_mmap(16)
72 sni[0]=0x65; sni[1]=0x78; sni[2]=0x61
73 sni[3]=0x6D; sni[4]=0x70; sni[5]=0x6C; sni[6]=0x65
74 let ch_buf: *u8 = sys_mmap(512)
75 nx_tls13_client_session_emit_ch(s1, sni, 7, ch_buf, 512)
76 let v_b: i64 = nx_tls13_client_session_recv_hs(s1, dummy_rec, 32, val_ctx)
77 if v_b != NX_TLS13_RECV_HS_BAD_STATE { return 2 }
78
79 // Now drive s1 into WAIT_EE via recv_sh
80 let srv_random: *u8 = sys_mmap(32)
81 i = 0
82 while i < 32 { srv_random[i] = (0x70 + i) as u8; i = i + 1 }
83 let srv_pub: *u8 = sys_mmap(32)
84 i = 0
85 while i < 32 { srv_pub[i] = (0xA0 + i) as u8; i = i + 1 }
86 let sh: *u8 = sys_mmap(128)
87 build_sh(sh, srv_random, srv_pub)
88 if nx_tls13_client_session_recv_sh(s1, sh, 84) != NX_TLS13_RECV_SH_OK { return 3 }
89 if s1.state != NX_TLS13_CSESSION_STATE_WAIT_EE { return 4 }
90
91 // ---- Test C: record too short -> RECORD_FAIL ----
92 let v_c: i64 = nx_tls13_client_session_recv_hs(s1, dummy_rec, 10, val_ctx)
93 if v_c != NX_TLS13_RECV_HS_RECORD_FAIL { return 10 }
94 // server_seq should NOT increment on length-check failure (we
95 // bailed before calling decrypt).
96 if s1.server_seq != 0 { return 11 }
97
98 // ---- Test D: garbage record with valid length -> RECORD_FAIL ----
99 // Build a 32-byte record (5 hdr + 11 ct + 16 tag = 32 bytes).
100 let garb: *u8 = sys_mmap(64)
101 garb[0] = 0x17; garb[1] = 0x03; garb[2] = 0x03 // TLSCiphertext header
102 garb[3] = 0; garb[4] = 27 // length = 11 + 16 = 27
103 // Fill the rest with garbage; decrypt will fail tag verify.
104 var gi: i64 = 5
105 while gi < 32 { garb[gi] = 0xCC as u8; gi = gi + 1 }
106 let v_d: i64 = nx_tls13_client_session_recv_hs(s1, garb, 32, val_ctx)
107 if v_d != NX_TLS13_RECV_HS_RECORD_FAIL { return 20 }
108 // server_seq MUST increment on decrypt failure (replay counter
109 // tracks delivered records to prevent attacker re-injection).
110 if s1.server_seq != 1 { return 21 }
111
112 // ---- Test E: another garbage record -> server_seq increments to 2 ----
113 let v_e: i64 = nx_tls13_client_session_recv_hs(s1, garb, 32, val_ctx)
114 if v_e != NX_TLS13_RECV_HS_RECORD_FAIL { return 30 }
115 if s1.server_seq != 2 { return 31 }
116
117 // ---- Test F: state preserved across failed recv calls ----
118 if s1.state != NX_TLS13_CSESSION_STATE_WAIT_EE { return 40 }
119
120 // ---- Test G: verdict gate ----
121 if nx_tls13_recv_hs_verdict_is_valid(NX_TLS13_RECV_HS_OK) != 1 { return 50 }
122 if nx_tls13_recv_hs_verdict_is_valid(NX_TLS13_RECV_HS_BAD_STATE) != 1 { return 51 }
123 if nx_tls13_recv_hs_verdict_is_valid(NX_TLS13_RECV_HS_RECORD_FAIL) != 1 { return 52 }
124 if nx_tls13_recv_hs_verdict_is_valid(NX_TLS13_RECV_HS_WRONG_CT) != 1 { return 53 }
125 if nx_tls13_recv_hs_verdict_is_valid(NX_TLS13_RECV_HS_MSG_TOO_SHORT) != 1 { return 54 }
126 if nx_tls13_recv_hs_verdict_is_valid(NX_TLS13_RECV_HS_DISPATCH_FAIL) != 1 { return 55 }
127 if nx_tls13_recv_hs_verdict_is_valid(NX_TLS13_RECV_HS_INTERNAL) != 1 { return 56 }
128 if nx_tls13_recv_hs_verdict_is_valid(NX_TLS13_RECV_HS_VERDICT_N) != 0 { return 57 }
129 if nx_tls13_recv_hs_verdict_is_valid(0) != 0 { return 58 }
130 if nx_tls13_recv_hs_verdict_is_valid(0 - 1) != 0 { return 59 }
131
132 return 0
133}