Skip to content

Commit

Permalink
Extended UID Support (#8)
Browse files Browse the repository at this point in the history
* Extended UID Support

---------

Co-authored-by: Edwin Heerschap <[email protected]>
  • Loading branch information
E-Heerschap and SymbiotechEdwinH authored Apr 24, 2023
1 parent 63cebdd commit 1bb2c5f
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 25 deletions.
43 changes: 37 additions & 6 deletions examples/provisioning_config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,22 @@

# Hex array must start with 0x otherwise it is treated as a string.

# If method is 3, the UID can be set either directly using 'uid' key or the individual components can be set
# using 'node_uid', 'node_uid_type', 'authenticator_uid', 'authenticator_uid_type' keys. Individual 'uid' key
# takes precedence over the individual components.

# Format is:
#
# UID : (mandatory) Ex: test_node
# method : (mandatory)(Unsecured:0 or Secured:1) Ex: 0
# method : (mandatory)(Unsecured:0, Secured:1, Extended UID:3) Ex: 0
# factory_key : (only for secured method)(32 bytes string, [0:15 Auth key][16:31 Enc Key])
# authentication_key : (mandatory)(16 bytes string) Ex: 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
# encryption_key : (mandatory)(16 bytes string) Ex: 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
# node_uid : (optional)(16 bytes string) Ex: 0x7e 0x71 0xe5 0xd7 0x22 0xef 0x0f 0x4b 0xa8 0x7d 0x44 0xd4 0xe0 0xe5 0xb5 0x7d
# node_uid_type : (optional)(1 byte string) Ex: 0x01
# node_authenticator_uid_type : (optional)(1 byte string) Ex: 0x01
# node_authenticator_uid : (optional)(16 bytes string) Ex: 0xb3 0x43 0x33 0x00 0x93 0x81 0x08 0x4a 0x8d 0xb3 0xaa 0x9e 0x53 0xd2 0x2a 0x1e
# uid : (optional)(34 bytes string) Ex: 0x01 0xb3 0x43 0x33 0x00 0x93 0x81 0x08 0x4a 0x8d 0xb3 0xaa 0x9e 0x53 0xd2 0x2a 0x1e 0x01 0x7e 0x71 0xe5 0xd7 0x22 0xef 0x0f 0x4b 0xa8 0x7d 0x44 0xd4 0xe0 0xe5 0xb5 0x7d
# network_address : (optional)(uint) Ex: 0x1012EE
# network_channel : (optional)(uint) Ex: 13
# node_id : (optional)(uint) Ex: 0x11
Expand All @@ -18,11 +27,33 @@
# 128 : 'some_string'
# 129 : 0x34

test_node :
method : 1

test_node_extended:
method : 3
node_uid: 0x7e 0x71 0xe5 0xd7 0x22 0xef 0x0f 0x4b 0xa8 0x7d 0x44 0xd4 0xe0 0xe5 0xb5 0x7d
node_uid_type: 0x01
authenticator_uid: 0xb3 0x43 0x33 0x00 0x93 0x81 0x08 0x4a 0x8d 0xb3 0xaa 0x9e 0x53 0xd2 0x2a 0x1e
authenticator_uid_type: 0x01
factory_key : 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0X09 0X0A 0X0B 0X0C 0X0D 0X0E 0X0F 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0X09 0X0A 0X0B 0X0C 0X0D 0X0E 0X0F
authentication_key : 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10
encryption_key : 0x10 0x0F 0x0E 0x0D 0x0C 0x0B 0x0A 0x09 0x08 0x07 0x06 0x05 0x04 0x03 0x02 0x01
network_address : 0x1012EE
network_channel : 2
node_id : 0x11
node_id : 0x11
authentication_key: 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10
encryption_key: 0x10 0x0F 0x0E 0x0D 0x0C 0x0B 0x0A 0x09 0x08 0x07 0x06 0x05 0x04 0x03 0x02 0x01
test_node_secure:
method: 1
uid: 0x58 0xc8 0x12 0xad 0x37 0xe8 0x36 0x4a 0xa1 0x1f 0x1c 0xbc 0x63 0x3e 0x8e 0x34
factory_key: 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0X09 0X0A 0X0B 0X0C 0X0D 0X0E 0X0F 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0X09 0X0A 0X0B 0X0C 0X0D 0X0E 0X0F
network_address: 0x1012EE
network_channel: 2
node_id: 0x11
authentication_key: 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10
encryption_key: 0x10 0x0F 0x0E 0x0D 0x0C 0x0B 0x0A 0x09 0x08 0x07 0x06 0x05 0x04 0x03 0x02 0x01
test_node_insecure:
method: 0
uid: 0x41 0xb1 0x85 0x7a 0x0f 0xb6 0xb1 0x48 0xa5 0xe4 0xb9 0xb6 0x03 0x53 0x1b 0x3b
network_address: 0x1012EE
network_channel: 2
node_id: 0x11
authentication_key: 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x10
encryption_key: 0x10 0x0F 0x0E 0x0D 0x0C 0x0B 0x0A 0x09 0x08 0x07 0x06 0x05 0x04 0x03 0x02 0x01
104 changes: 85 additions & 19 deletions wirepas_provisioning_server/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,38 @@
import yaml
import logging

from wirepas_provisioning_server.message import ProvisioningMethod


def _generate_extended_uid(authenticator_uid_type,
authenticator_uid,
node_uid_type,
node_uid) -> bytes:
"""
Generate extended UID bytes
"""

authenticator_uid_type = _convert_to_bytes(authenticator_uid_type)
authenticator_uid = _convert_to_bytes(authenticator_uid)
node_uid_type = _convert_to_bytes(node_uid_type)
node_uid = _convert_to_bytes(node_uid)

def _any_is_not_bytes(*args):
return any(not isinstance(arg, bytes) for arg in args)

if _any_is_not_bytes(authenticator_uid_type, authenticator_uid, node_uid_type, node_uid):
raise ValueError("Parameters must be convertible to bytes")

if any(len(arg) != 1 for arg in [authenticator_uid_type, node_uid_type]):
raise ValueError("UID type must be 1 byte")

return b"".join([
authenticator_uid_type,
authenticator_uid,
node_uid_type,
node_uid
])


def _convert_to_bytes(param):
if isinstance(param, str):
Expand All @@ -20,7 +52,7 @@ def _convert_to_bytes(param):
else:
param = bytes(param, "utf-8")
elif isinstance(param, int):
param.to_bytes((param.bit_length() + 7) // 8, byteorder="big")
param = param.to_bytes(max(1, (param.bit_length() + 7)) // 8, byteorder="big")

return param

Expand Down Expand Up @@ -50,46 +82,80 @@ def __init__(self, config=None):
except yaml.YAMLError:
raise ProvisioningDataException("Invalid data config file.")

for uid in cfg:
if "network_address" in cfg[uid].keys():
network_address = _convert_to_int(cfg[uid]["network_address"])
for node in cfg:

if "method" not in cfg[node].keys():
raise ProvisioningDataException("Invalid data config file. %s must include method.".format(node))

provision_methods = [e.value for e in ProvisioningMethod]
if cfg[node]["method"] not in provision_methods:
raise ProvisioningDataException("Method must be one of {}".format(provision_methods))

if "uid" in cfg[node].keys():
uid = cfg[node]["uid"]
elif cfg[node]["method"] == ProvisioningMethod.EXTENDED:
try:
uid = _generate_extended_uid(
cfg[node]["authenticator_uid_type"],
cfg[node]["authenticator_uid"],
cfg[node]["node_uid_type"],
cfg[node]["node_uid"]
)

except KeyError:
raise ProvisioningDataException("Invalid data config file. %s must include UID information."
.format(node))
else:
raise ProvisioningDataException("Invalid data config file. %s must include UID information"
.format(node))

if "network_address" in cfg[node].keys():
network_address = _convert_to_int(cfg[node]["network_address"])
else:
network_address = None

if "network_channel" in cfg[uid].keys():
network_channel = _convert_to_int(cfg[uid]["network_channel"])
if "network_channel" in cfg[node].keys():
network_channel = _convert_to_int(cfg[node]["network_channel"])
else:
network_channel = None

if "node_id" in cfg[uid].keys():
node_id = _convert_to_int(cfg[uid]["node_id"])
if "node_id" in cfg[node].keys():
node_id = _convert_to_int(cfg[node]["node_id"])
else:
node_id = None

if "node_role" in cfg[uid].keys():
node_role = _convert_to_bytes(cfg[uid]["node_role"])
if "node_role" in cfg[node].keys():
node_role = _convert_to_bytes(cfg[node]["node_role"])
else:
node_role = None

if "user_specific" in cfg[uid].keys():
if "user_specific" in cfg[node].keys():
user_specific = dict()
for k in cfg[uid]["user_specific"]:
for k in cfg[node]["user_specific"]:
if k < 128 or k > 255:
raise KeyError
user_specific[k] = cfg[uid]["user_specific"][k]
user_specific[k] = cfg[node]["user_specific"][k]
else:
user_specific = None

if "factory_key" in cfg[uid].keys():
factory_key = _convert_to_bytes(cfg[uid]["factory_key"])
if "factory_key" in cfg[node].keys():
factory_key = _convert_to_bytes(cfg[node]["factory_key"])
else:
factory_key = None

if "encryption_key" not in cfg[node].keys():
raise ProvisioningDataException("Invalid data config file. %s must include encryption_key."
.format(node))
if "authentication_key" not in cfg[node].keys():
raise ProvisioningDataException("Invalid data config file. %s must include authentication_key."
.format(node))


self.append(
_convert_to_bytes(uid),
cfg[uid]["method"],
_convert_to_bytes(cfg[uid]["encryption_key"]),
_convert_to_bytes(cfg[uid]["authentication_key"]),
cfg[node]["method"],
_convert_to_bytes(cfg[node]["encryption_key"]),
_convert_to_bytes(cfg[node]["authentication_key"]),
network_address,
network_channel,
node_id=node_id,
Expand Down Expand Up @@ -140,7 +206,7 @@ def append(
if factory_key is not None:
self[uid]["factory_key"] = factory_key

logging.info("Append new UID: %s", uid)
logging.info("Append new UID: %s", uid.hex())
logging.debug(" - method: %s", method)
logging.debug(" - factory_key: %s", factory_key)
logging.debug(" - encryption_key: %s", encryption_key)
Expand Down
1 change: 1 addition & 0 deletions wirepas_provisioning_server/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class ProvisioningMethod(IntEnum):

UNSECURED = 0
SECURED = 1
EXTENDED = 3


class ProvisioningNackReason(IntEnum):
Expand Down

0 comments on commit 1bb2c5f

Please sign in to comment.