Skip to content

Commit 9e8601b

Browse files
committed
tools: gateway: query public keys
If provided a local root identity, attempt to query the remote public keys when a connection is made. Signed-off-by: Jordan Yates <jordan@embeint.com>
1 parent 8d89913 commit 9e8601b

1 file changed

Lines changed: 53 additions & 9 deletions

File tree

src/infuse_iot/tools/gateway.py

Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ def __init__(self, database: DeviceDatabase):
6565
self._ddb = database
6666
self._queued: dict[int, Callable | None] = {}
6767

68-
def generate(self, command: int, args: bytes, auth: Auth, cb: Callable | None):
68+
def generate(self, command: int, args: bytes, auth: Auth, cb: Callable | None) -> PacketOutputRouted:
6969
"""Generate RPC packet from arguments"""
7070
cmd_bytes = bytes(rpc.RequestHeader(self._cnt, command)) + args
7171
cmd_pkt = PacketOutputRouted(
@@ -79,6 +79,23 @@ def generate(self, command: int, args: bytes, auth: Auth, cb: Callable | None):
7979
self._cnt += 1
8080
return cmd_pkt
8181

82+
def generate_remote_bt(
83+
self, remote: int, command: int, args: bytes, auth: Auth, cb: Callable | None
84+
) -> PacketOutputRouted:
85+
"""Generate RPC packet for Bluetooth remote from arguments"""
86+
cmd_bytes = bytes(rpc.RequestHeader(self._cnt, command)) + args
87+
88+
assert self._ddb.gateway is not None
89+
serial = HopOutput(self._ddb.gateway, interface.ID.SERIAL, Auth.DEVICE)
90+
bt = HopOutput(remote, interface.ID.BT_CENTRAL, auth)
91+
self._queued[self._cnt] = cb
92+
self._cnt += 1
93+
return PacketOutputRouted(
94+
[serial, bt],
95+
InfuseType.RPC_CMD,
96+
cmd_bytes,
97+
)
98+
8299
def handle(self, pkt: PacketReceived):
83100
"""Handle received packets"""
84101
# Only care about RPC responses
@@ -149,7 +166,7 @@ def public_keys_done(pkt: PacketReceived, rc: int, response: bytes):
149166
infuse_id = pkt.route[0].infuse_id
150167
self.ddb.observe_secondary_remote_public_key(infuse_id, bytes(key.key))
151168

152-
def run_cmd_pkt(cmd: PacketOutputRouted):
169+
def run_cmd_pkt(cmd_pkt: PacketOutputRouted):
153170
encrypted = cmd_pkt.to_serial(self.ddb)
154171
# Write to serial port
155172
Console.log_tx(cmd_pkt.ptype, len(encrypted))
@@ -327,6 +344,21 @@ def _handle_epacket_send(self, req: GatewayRequestEpacketSend):
327344
Console.log_tx(routed.ptype, len(encrypted))
328345
self._common.port.write(encrypted)
329346

347+
def _connected_notification(self, infuse_id: int):
348+
rsp = ClientNotificationConnectionCreated(infuse_id, 244 - ctypes.sizeof(CtypeBtGattFrame) - 16)
349+
self._common.notification_broadcast(rsp)
350+
351+
def _pub_keys_cb(self, pkt: PacketReceived, rc: int, response: bytes):
352+
infuse_id = pkt.route[0].infuse_id
353+
if rc == 0:
354+
decoded = defs.security_public_keys.response.vla_from_buffer_copy(response)
355+
for key in decoded.public_keys:
356+
if key.id == defs.rpc_enum_key_id.SECONDARY_REMOTE_PUBLIC_KEY:
357+
self._common.ddb.observe_secondary_remote_public_key(infuse_id, bytes(key.key))
358+
359+
# Notify connection success
360+
self._connected_notification(infuse_id)
361+
330362
def _bt_connect_cb(self, pkt: PacketReceived, rc: int, response: bytes):
331363
resp = defs.bt_connect_infuse.response.from_buffer_copy(pkt.payload[ctypes.sizeof(rpc.ResponseHeader) :])
332364
if_addr = interface.Address.BluetoothLeAddr.from_rpc_struct(resp.peer)
@@ -335,16 +367,28 @@ def _bt_connect_cb(self, pkt: PacketReceived, rc: int, response: bytes):
335367
assert infuse_id is not None, "ID was required to initiate connection?"
336368
assert self._common.server is not None
337369

338-
rsp: ClientNotification
339370
if rc < 0:
340371
rsp = ClientNotificationConnectionFailed(infuse_id)
372+
self._common.notification_broadcast(rsp)
373+
return
374+
375+
if infuse_id in self._connected:
376+
self._connected[infuse_id] += 1
341377
else:
342-
if infuse_id in self._connected:
343-
self._connected[infuse_id] += 1
344-
else:
345-
self._connected[infuse_id] = 1
346-
rsp = ClientNotificationConnectionCreated(infuse_id, 244 - ctypes.sizeof(CtypeBtGattFrame) - 16)
347-
self._common.notification_broadcast(rsp)
378+
self._connected[infuse_id] = 1
379+
380+
if self._common.ddb.has_local_root:
381+
# Query public keys before running callback
382+
cmd = self._common.rpc.generate_remote_bt(
383+
infuse_id, defs.security_public_keys.COMMAND_ID, b"\x00", Auth.NETWORK, self._pub_keys_cb
384+
)
385+
encrypted = cmd.to_serial(self._common.ddb)
386+
Console.log_tx(cmd.ptype, len(encrypted))
387+
self._common.port.write(encrypted)
388+
return
389+
390+
# Notify connection success
391+
self._connected_notification(infuse_id)
348392

349393
def _handle_conn_request(self, req: GatewayRequestConnectionRequest):
350394
assert self._common.server is not None

0 commit comments

Comments
 (0)