code wiki / (root) / nx_tls13_client_session_recv_hs_test.nx

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}