code wiki / (root) / nx_iot_local_kasa_test.nx

nx_iot_local_kasa_test.nx source

↩ module page · 147 lines · 6735 B

1// nx_iot_local_kasa_test.nx -- gate for the TP-Link Kasa LAN driver. 2// 3// SOVEREIGN proof (this is a NON-NOVEL protocol; the matching 3rd-party 4// python-kasa KAT cross-check runs in the harness later, never here): 5// - autokey hand-derived KAT: encrypt "{}" -> [0xD0, 0xAD] 6// (0x7B^0xAB=0xD0, then 0x7D^0xD0=0xAD -- derivable from the spec) 7// - autokey round-trip identity over a real command 8// - TCP frame: 4-byte BE length round-trip + decrypt recovers payload 9// - capability builders carry hue/saturation/brightness/color_temp 10// - reply classifier marker detection 11// - negative controls: BUF_TOO_SMALL + BAD_LEN 12// 13// expect_exit: 0 14// 15// license_tier: ORIGINAL 16 17import "nx_syscalls_x86_64.nx" 18import "nx_iot_local_kasa.nx" 19 20func main() -> i64 { 21 // ---- verdict validity gate ------------------------------------- 22 if nx_iot_kasa_verdict_is_valid(NX_IOT_KASA_VERDICT_OK) != 1 { return 1 } 23 if nx_iot_kasa_verdict_is_valid(NX_IOT_KASA_VERDICT_BAD_LEN) != 1 { return 2 } 24 if nx_iot_kasa_verdict_is_valid(NX_IOT_KASA_VERDICT_N) != 0 { return 3 } 25 if nx_iot_kasa_verdict_is_valid(-1) != 0 { return 4 } 26 27 let a: *u8 = sys_mmap(256) 28 let b: *u8 = sys_mmap(256) 29 let c: *u8 = sys_mmap(256) 30 let qv: *i64 = sys_mmap(8) as *i64 31 32 // ---- autokey KAT: encrypt "{}" -> [0xD0, 0xAD] ----------------- 33 nx_iot_kasa_encrypt("{}", 2, a) 34 if (a[0] as i64) != 0xD0 { return 10 } 35 if (a[1] as i64) != 0xAD { return 11 } 36 nx_iot_kasa_decrypt(a, 2, b) 37 if (b[0] as i64) != 0x7B { return 12 } 38 if (b[1] as i64) != 0x7D { return 13 } 39 nx_iot_kasa_encrypt("{", 1, a) 40 if (a[0] as i64) != 0xD0 { return 14 } 41 42 // ---- relay builder: {"system":{"set_relay_state":{"state":1}}} - 43 let rl: i64 = nx_iot_kasa_pt_relay(a, 256, 1) 44 if rl <= 0 { return 20 } 45 if (a[0] as i64) != 0x7B { return 21 } 46 if (a[rl - 1] as i64) != 0x7D { return 22 } 47 if (a[rl - 2] as i64) != 0x7D { return 23 } 48 if (a[rl - 3] as i64) != 0x7D { return 24 } 49 if (a[rl - 4] as i64) != 0x31 { return 25 } 50 if nx_iot_kasa_find(a, rl, "set_relay_state", 15) < 0 { return 26 } 51 if nx_iot_kasa_find(a, rl, "system", 6) < 0 { return 27 } 52 let rl0: i64 = nx_iot_kasa_pt_relay(b, 256, 0) 53 if (b[rl0 - 4] as i64) != 0x30 { return 28 } 54 55 // ---- relay round-trip through autokey -------------------------- 56 nx_iot_kasa_encrypt(a, rl, c) 57 nx_iot_kasa_decrypt(c, rl, b) 58 var i: i64 = 0 59 while i < rl { 60 if (b[i] as i64) != (a[i] as i64) { return 30 } 61 i = i + 1 62 } 63 64 // ---- TCP frame round-trip -------------------------------------- 65 let fl: i64 = nx_iot_kasa_frame_tcp(a, rl, c, 256, qv) 66 if qv[0] != NX_IOT_KASA_VERDICT_OK { return 40 } 67 if fl != rl + 4 { return 41 } 68 if nx_iot_kasa_get_u32_be(c, 0) != rl { return 42 } 69 let dl: i64 = nx_iot_kasa_deframe_tcp(c, fl, b, 256, qv) 70 if qv[0] != NX_IOT_KASA_VERDICT_OK { return 43 } 71 if dl != rl { return 44 } 72 var k: i64 = 0 73 while k < rl { 74 if (b[k] as i64) != (a[k] as i64) { return 45 } 75 k = k + 1 76 } 77 78 // ---- sysinfo probe builder ------------------------------------- 79 let sl: i64 = nx_iot_kasa_pt_sysinfo(a, 256) 80 if sl <= 0 { return 50 } 81 if (a[0] as i64) != 0x7B { return 51 } 82 if nx_iot_kasa_find(a, sl, "get_sysinfo", 11) < 0 { return 52 } 83 84 // ---- colour-bulb capability builder ---------------------------- 85 let ll: i64 = nx_iot_kasa_pt_light(a, 256, 1, 120, 100, 75, 0) 86 if ll <= 0 { return 60 } 87 if (a[0] as i64) != 0x7B { return 61 } 88 if (a[ll - 1] as i64) != 0x7D { return 62 } 89 if nx_iot_kasa_find(a, ll, "hue", 3) < 0 { return 63 } 90 if nx_iot_kasa_find(a, ll, "saturation", 10) < 0 { return 64 } 91 if nx_iot_kasa_find(a, ll, "brightness", 10) < 0 { return 65 } 92 if nx_iot_kasa_find(a, ll, "color_temp", 10) < 0 { return 66 } 93 if nx_iot_kasa_find(a, ll, "transition_light_state", 22) < 0 { return 67 } 94 let fl2: i64 = nx_iot_kasa_frame_tcp(a, ll, c, 256, qv) 95 if qv[0] != NX_IOT_KASA_VERDICT_OK { return 68 } 96 let dl2: i64 = nx_iot_kasa_deframe_tcp(c, fl2, b, 256, qv) 97 if dl2 != ll { return 69 } 98 99 // ---- reply classifier ------------------------------------------ 100 if nx_iot_kasa_looks_like_sysinfo("xx sw_ver yy", 12) != 1 { return 70 } 101 if nx_iot_kasa_looks_like_sysinfo("hello world!", 12) != 0 { return 71 } 102 103 // ---- negative controls ----------------------------------------- 104 if nx_iot_kasa_frame_tcp(a, rl, c, rl + 2, qv) != -1 { return 80 } 105 if qv[0] != NX_IOT_KASA_VERDICT_BUF_TOO_SMALL { return 81 } 106 if nx_iot_kasa_deframe_tcp(c, 3, b, 256, qv) != -1 { return 82 } 107 if qv[0] != NX_IOT_KASA_VERDICT_BAD_LEN { return 83 } 108 nx_iot_kasa_put_u32_be(c, 0, 9999) 109 if nx_iot_kasa_deframe_tcp(c, 8, b, 256, qv) != -1 { return 84 } 110 if qv[0] != NX_IOT_KASA_VERDICT_BAD_LEN { return 85 } 111 112 // ---- SoftAP creds-push builder (the provisioning PUSH_CREDS payload) - 113 let pl: i64 = nx_iot_kasa_pt_set_stainfo(a, 256, "HomeNet", 7, "s3cr3t", 6, 3) 114 if pl <= 0 { return 90 } 115 if (a[0] as i64) != 0x7B { return 91 } // { 116 if (a[pl - 1] as i64) != 0x7D { return 92 } // } 117 if nx_iot_kasa_find(a, pl, "set_stainfo", 11) < 0 { return 93 } 118 if nx_iot_kasa_find(a, pl, "netif", 5) < 0 { return 94 } 119 if nx_iot_kasa_find(a, pl, "HomeNet", 7) < 0 { return 95 } 120 if nx_iot_kasa_find(a, pl, "s3cr3t", 6) < 0 { return 96 } 121 if nx_iot_kasa_find(a, pl, "key_type", 8) < 0 { return 97 } 122 // round-trips through autokey + TCP frame like every other command 123 let fl3: i64 = nx_iot_kasa_frame_tcp(a, pl, c, 256, qv) 124 if qv[0] != NX_IOT_KASA_VERDICT_OK { return 98 } 125 let dl3: i64 = nx_iot_kasa_deframe_tcp(c, fl3, b, 256, qv) 126 if dl3 != pl { return 99 } 127 var z: i64 = 0 128 while z < pl { 129 if (b[z] as i64) != (a[z] as i64) { return 100 } 130 z = z + 1 131 } 132 133 // ---- JSON-escaping closes the injection hazard ----------------- 134 // ssid carries a quote, password a backslash -> both must be escaped. 135 let pe: i64 = nx_iot_kasa_pt_set_stainfo(a, 256, "ab\"cd", 5, "p\\q", 3, 3) 136 if pe <= 0 { return 101 } 137 if nx_iot_kasa_find(a, pe, "ab\\\"cd", 6) < 0 { return 102 } // a b \ " c d 138 if nx_iot_kasa_find(a, pe, "p\\\\q", 4) < 0 { return 103 } // p \ \ q 139 let fl4: i64 = nx_iot_kasa_frame_tcp(a, pe, c, 256, qv) // still framable 140 if qv[0] != NX_IOT_KASA_VERDICT_OK { return 104 } 141 142 // ---- buffer-too-small + bad-length guards ---------------------- 143 if nx_iot_kasa_pt_set_stainfo(a, 8, "HomeNet", 7, "s3cr3t", 6, 3) != -1 { return 105 } 144 if nx_iot_kasa_pt_set_stainfo(a, 256, "x", -1, "y", 1, 3) != -1 { return 106 } 145 146 return 0 147}