code wiki / (root) / nx_websocket_client_upgrade_test.nx

nx_websocket_client_upgrade_test.nx source

↩ module page · 144 lines · 6252 B

1// nx_websocket_client_upgrade_test.nx -- KAT for CLIENT-side WebSocket 2// HTTP/1.1 upgrade per RFC 6455 §1.3 + §4.1 + §4.2. 3// 4// Covers: 5// T1: request-builder writes a syntactically correct GET upgrade 6// T2: validator accepts a canonical 101 response keyed by RFC's §1.3 7// worked example (key = "dGhlIHNhbXBsZSBub25jZQ=="). 8// T3: validator rejects bad status line (200 instead of 101) 9// T4: validator rejects missing Upgrade header 10// T5: validator rejects missing Connection header 11// T6: validator rejects Sec-WebSocket-Accept that does not match 12// SHA-1+Base64 of the client key + RFC GUID (i.e., a forged 13// response or a real-but-mismatched-key bug). 14// T7: include_port_in_host=1 adds ":port" to Host header 15// 16// Per Cardinal 13 (additive-only data: this test is the new gate 17// for this module + it composes the SAME SHA-1+Base64 ws_accept 18// primitive the server side uses to AVOID re-implementing the 19// reference algorithm). 20// 21// expect_exit: 0 22// license_tier: ORIGINAL 23 24import "nx_syscalls.nx" 25import "nx_websocket_client_upgrade.nx" 26import "nx_websocket_handshake.nx" 27 28// Local helper: case-sensitive substring search; -1 if not found. 29func _t_find_sub(buf: *u8, n: i64, needle: *u8, nn: i64) -> i64 { 30 var i: i64 = 0 31 while i + nn <= n { 32 var j: i64 = 0 33 var hit: i64 = 1 34 while j < nn { 35 if buf[i + j] != needle[j] { hit = 0; j = nn } 36 j = j + 1 37 } 38 if hit == 1 { return i } 39 i = i + 1 40 } 41 return 0 - 1 42} 43 44// Build a canonical 101 response keyed by the §1.3 client_key. 45// Writes into out and returns total length. 46func _t_build_canonical_101(out: *u8) -> i64 { 47 // Sec-WebSocket-Accept for "dGhlIHNhbXBsZSBub25jZQ==" is 48 // "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=" per RFC 6455 §1.3. 49 let s: *u8 = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n" as *u8 50 let n: i64 = 129 51 var i: i64 = 0 52 while i < n { out[i] = s[i]; i = i + 1 } 53 return n 54} 55 56func main() -> i64 { 57 // ---- T1: request-builder produces a syntactic GET upgrade ---- 58 let req: *u8 = sys_mmap(1024) 59 let key24: *u8 = sys_mmap(32) 60 let host: *u8 = "192.168.8.227" as *u8 61 let path: *u8 = "/signal/test-room" as *u8 62 let rn: i64 = nx_ws_client_build_request(req, 1024, 63 host, 13, 64 path, 17, 65 8445, 0, 66 key24) 67 if rn < 0 { return 1 } 68 // Must start with "GET /signal/test-room HTTP/1.1\r\n" 69 let gp: *u8 = "GET /signal/test-room HTTP/1.1\r\n" as *u8 70 var i: i64 = 0 71 while i < 32 { 72 if req[i] != gp[i] { return 2 } 73 i = i + 1 74 } 75 // Must contain Host header 76 if _t_find_sub(req, rn, "Host: 192.168.8.227\r\n" as *u8, 21) < 0 { return 3 } 77 if _t_find_sub(req, rn, "Upgrade: websocket\r\n" as *u8, 20) < 0 { return 4 } 78 if _t_find_sub(req, rn, "Connection: Upgrade\r\n" as *u8, 21) < 0 { return 5 } 79 if _t_find_sub(req, rn, "Sec-WebSocket-Version: 13\r\n" as *u8, 27) < 0 { return 6 } 80 if _t_find_sub(req, rn, "Sec-WebSocket-Key: " as *u8, 19) < 0 { return 7 } 81 // Trailer "\r\n\r\n" 82 if req[rn - 4] != 13 as u8 { return 8 } 83 if req[rn - 3] != 10 as u8 { return 9 } 84 if req[rn - 2] != 13 as u8 { return 10 } 85 if req[rn - 1] != 10 as u8 { return 11 } 86 87 // ---- T2: validator accepts canonical 101 with RFC §1.3 key ---- 88 let resp: *u8 = sys_mmap(512) 89 let rn2: i64 = _t_build_canonical_101(resp) 90 let fixed_key: *u8 = "dGhlIHNhbXBsZSBub25jZQ==" as *u8 91 let v2: i64 = nx_ws_client_validate_response(resp, rn2, fixed_key) 92 if v2 != NX_WSCU_OK { return 12 } 93 94 // ---- T3: bad status (200 instead of 101) ---- 95 let resp3: *u8 = sys_mmap(512) 96 let s3: *u8 = "HTTP/1.1 200 OK\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n" as *u8 97 var n3: i64 = 113 98 i = 0; while i < n3 { resp3[i] = s3[i]; i = i + 1 } 99 let v3: i64 = nx_ws_client_validate_response(resp3, n3, fixed_key) 100 if v3 != NX_WSCU_BAD_STATUS { return 13 } 101 102 // ---- T4: missing Upgrade header ---- 103 let resp4: *u8 = sys_mmap(512) 104 let s4: *u8 = "HTTP/1.1 101 Switching Protocols\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n" as *u8 105 var n4: i64 = 113 106 i = 0; while i < n4 { resp4[i] = s4[i]; i = i + 1 } 107 let v4: i64 = nx_ws_client_validate_response(resp4, n4, fixed_key) 108 if v4 != NX_WSCU_BAD_UPGRADE { return 14 } 109 110 // ---- T5: missing Connection header ---- 111 let resp5: *u8 = sys_mmap(512) 112 let s5: *u8 = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nSec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n" as *u8 113 var n5: i64 = 111 114 i = 0; while i < n5 { resp5[i] = s5[i]; i = i + 1 } 115 let v5: i64 = nx_ws_client_validate_response(resp5, n5, fixed_key) 116 if v5 != NX_WSCU_BAD_CONNECTION { return 15 } 117 118 // ---- T6: mismatched Sec-WebSocket-Accept ---- 119 let resp6: *u8 = sys_mmap(512) 120 let s6: *u8 = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: AAAAAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n" as *u8 121 var n6: i64 = 129 122 i = 0; while i < n6 { resp6[i] = s6[i]; i = i + 1 } 123 let v6: i64 = nx_ws_client_validate_response(resp6, n6, fixed_key) 124 if v6 != NX_WSCU_BAD_ACCEPT { return 16 } 125 126 // ---- T7: include_port_in_host=1 adds ":port" ---- 127 let req7: *u8 = sys_mmap(1024) 128 let key7: *u8 = sys_mmap(32) 129 let rn7: i64 = nx_ws_client_build_request(req7, 1024, 130 host, 13, 131 path, 17, 132 8445, 1, 133 key7) 134 if rn7 < 0 { return 17 } 135 if _t_find_sub(req7, rn7, "Host: 192.168.8.227:8445\r\n" as *u8, 26) < 0 { 136 return 18 137 } 138 139 // "PASS\n" 140 let ok: *u8 = sys_mmap(8) 141 ok[0]=80; ok[1]=65; ok[2]=83; ok[3]=83; ok[4]=10 142 sys_write(1, ok, 5) 143 return 0 144}