Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 39 additions & 8 deletions src/infuse_iot/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,44 @@ class UnknownNetworkError(NoKeyError):
class DeviceUnknownDeviceKey(NoKeyError):
"""Device key is not known for requested device"""

def __init__(self, infuse_id: int, interface: bytes, key_id: int | None):
self.infuse_id = infuse_id
self.interface = interface
self.key_id = key_id

def __str__(self):
interface_str = self.interface.decode("utf-8")
return f"{self.infuse_id:016x}: {interface_str} {self.key_id}"


class DeviceUnknownNetworkKey(NoKeyError):
"""Network key is not known for requested device"""

def __init__(self, infuse_id: int, interface: bytes):
self.infuse_id = infuse_id
self.interface = interface

def __str__(self):
interface_str = self.interface.decode("utf-8")
return f"{self.infuse_id:016x}: {interface_str}"


class DeviceKeyChangedError(KeyError):
"""Device key for the requested device has changed"""


class DeviceKeyQueryFailed(Exception):
"""Querying a device key from the cloud failed"""

def __init__(self, infuse_id: int, status_code: int, content: str):
self.infuse_id = infuse_id
self.status_code = status_code
self.content = content

def __str__(self):
return f"{self.infuse_id:016x}: <{self.status_code}> {self.content}"


class DeviceDatabase:
"""Database of current device state"""

Expand Down Expand Up @@ -191,9 +220,11 @@ def observe_security_state(
base64.b64encode(challenge_resp).decode("utf-8"),
)
body = GetDeviceSharedSecretBody(f"{infuse_id:016x}", security_state)
response = get_device_shared_secret.sync(client=client, body=body)
if response is not None:
key = base64.b64decode(response.key)
response = get_device_shared_secret.sync_detailed(client=client, body=body)
if response.parsed is None:
raise DeviceKeyQueryFailed(infuse_id, response.status_code, response.content.decode("utf-8"))
else:
key = base64.b64decode(response.parsed.key)
self.devices[infuse_id].shared_key = key
self._update_cache(infuse_id, device_pub_key, key)

Expand Down Expand Up @@ -242,17 +273,17 @@ def infuse_id_from_bluetooth(self, bt_addr: InterfaceAddress.BluetoothLeAddr) ->

def _get_network_key(self, infuse_id: int, name: bytes, gps_time: int) -> bytes:
if infuse_id not in self.devices:
raise DeviceUnknownNetworkKey
raise DeviceUnknownNetworkKey(infuse_id, name)
network_id = self.devices[infuse_id].network_id
if network_id is None:
raise DeviceUnknownNetworkKey
raise DeviceUnknownNetworkKey(infuse_id, name)
return self._network_key(network_id, name, gps_time)

def _get_device_key(
self, infuse_id: int, name: bytes, gps_time: int, key_id: int | None = None
) -> tuple[int, bytes]:
if infuse_id not in self.devices:
raise DeviceUnknownDeviceKey
raise DeviceUnknownDeviceKey(infuse_id, name, key_id)
d = self.devices[infuse_id]
if key_id is None:
if d.secondary_device_key_id:
Expand All @@ -266,9 +297,9 @@ def _get_device_key(
elif key_id == d.secondary_device_key_id:
base = d.local_shared_key
else:
raise DeviceUnknownDeviceKey
raise DeviceUnknownDeviceKey(infuse_id, name, key_id)
if base is None:
raise DeviceUnknownDeviceKey
raise DeviceUnknownDeviceKey(infuse_id, name, key_id)
assert key_id is not None
time_idx = gps_time // (60 * 60 * 24)
return key_id, hkdf_derive(base, time_idx.to_bytes(4, "little"), name)
Expand Down
23 changes: 14 additions & 9 deletions src/infuse_iot/tools/gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from infuse_iot.common import InfuseID, InfuseType
from infuse_iot.database import (
DeviceDatabase,
DeviceKeyQueryFailed,
NoKeyError,
)
from infuse_iot.epacket.packet import (
Expand Down Expand Up @@ -80,15 +81,19 @@ def query_device_key(self, infuse_id: int, cb_event: threading.Event | None = No

def security_state_done(pkt: PacketReceived, _rc: int, response: bytes, challenge):
decoded = defs.security_state.response.vla_from_buffer_copy(response)
self.ddb.observe_security_state(
infuse_id,
bytes(decoded.cloud_public_key),
bytes(decoded.device_public_key),
decoded.network_id,
challenge,
decoded.challenge_response_type,
bytes(decoded.challenge_response),
)
try:
self.ddb.observe_security_state(
infuse_id,
bytes(decoded.cloud_public_key),
bytes(decoded.device_public_key),
decoded.network_id,
challenge,
decoded.challenge_response_type,
bytes(decoded.challenge_response),
)
except DeviceKeyQueryFailed as e:
Console.log_error(f"Failed to query key for {e.infuse_id:016x}: {e.content}")
return
if cb_event is not None:
cb_event.set()

Expand Down
Loading