-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathprotocol.txt
124 lines (87 loc) · 4.12 KB
/
protocol.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
Conceptual model
- Node
Something on the network (wifi, ethernet); to/fro
we can talk over MQTT: its messages protected
by a shared secret.
- Machine
Something connected to a node that is controlled
by that node.
For a simple device - node & machine are one and the same (e.g.
a node controlling just a lathe). For the doors; the rfid
reader is connected to a node; which can be different from the
node that controls the stepper motor on the door.
Protocol
Version 1 -- 2015, early 2016
- MQTT message from reader to master:
topic: PREFIX/deur/rfid
payload: bytes - translated to ASCII
in effect the tag in 'python' array format:
'[123, 1224, ---- 1234, 234]'
- MQTT reply from master to deur:
topic: PREFIX/deur/open
payload open (4 bytes, no termination)
- Or no reply on error, no access, etc, etc.
Version 2 -- mid 2016
- MQTT message from ACNode to master
topic: PREFIX/master/<node>
payload: bytes interpreted as 7-bit safe ASCII
Payload structure:
'SIG/1.00' protocol version.
<space>
hexdigest SHA256 based HMAC of topic, timestamp, secret, nodename and message.
secret and node name are tied to the source.
<space>
timestamp Nonce; ASCII; no spaces allowed; up to 128 bytes.
<space>
targetnode Target Node name; ASCII; no spaces allowed; up to 32 bytes. For
a node that is both a reader and a controller this name will be
the same name of the sending node in the topic. For the doors
it will be the name of the node that controls the door.
<space>
message bytes; until the remainder of the message
Possible message (case sensitive)
'energize' <space> <nodename> <devicename> <space> <tag-hmac>
where device name cannot contain a space; up to 32 bytes and
the tag-hmac is that of the secret, timestamp and the exact
bytes (in network/SPI order) 'as is' read from the card
without any terminating 0 or length prefix.
'open' <space> 'nodename' <space> 'devicename' <space> <tag-hmac>
Request to open the door 'devicename' connected to 'nodename'
'beat' My timestamp
'revealtag' Reveal the last tag swiped in the clear.
'announce' Sent when a node joins the network; optionally followed by
the IP addres of the node.
'ping' Alive check.
'ack' Alive response; optionalliy followed master node and local IP address.
'state' Request state
'report' Response ith machine state (integer) and human readable verson.
'event' <what> <string>
- MQTT reply from master to (relevant) Target ACNode(s)
topic: PREFIX/acnode/<node>/reply
payload: bytes interpreted as 7-bit safe ASCII
'SIG/1.00' protocol version.
<space>
hexdigest SHA256 based HMAC of reply-topic, target-device-timestamp, target-secret and message
<space>
message bytes; until the remainder of the message
Possible replies
'energize' <space> 'nodename' <space> <devicename> <space> 'approved'
'energize' <space> 'nodename' <space> <devicename> <space> 'denied'
'energize' <space> 'nodename' <space> <devicename> <space> 'error'
'open' <space> 'nodename' <space> <devicename> <space> 'approved'
'open' <space> 'nodename' <space> <devicename> <space> 'denied'
'open' <space> 'nodename' <space> <devicename> <space> 'error'
Note: As the recipient is an embedded device we worry about implementations
which are somewhat careless with state and this easily fooled by
a replay or similarly. We rely on simple timestamps to make it
slightly harder to replay/spoof.
Note: we originally used JSON as the payload; as this plays well with
browsers. Unfortunately; json serialization is non-trivial; and it
turned out to be very hard to get a stable HMAC across two
flavours of javascript and python. Even multiple runs of the
same json (de)serialization can show different key orders in dicts.
Note: The digest of the TAG means that one is relatively anonymous
on the wire; and one cannot 'track' a user that way. The downside
is that this means that the master has a 'userdb' with plaintext
tag identifiers (as opposed to tags protected by a crypt or
a PBKDF2 like finction.