knx
ETS configurable knx-stack
security_interface_object.cpp
Go to the documentation of this file.
1 #include "config.h"
2 #ifdef USE_DATASECURE
3 
4 #include <cstring>
7 #include "bits.h"
8 #include "data_property.h"
9 #include "callback_property.h"
10 #include "function_property.h"
11 
12 // Our FDSK. It is never changed from ETS. This is the permanent default tool key that is restored on every factory reset of the device.
13 const uint8_t SecurityInterfaceObject::_fdsk[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
14 uint8_t SecurityInterfaceObject::_secReport[] = { 0x00, 0x00, 0x00 };
15 uint8_t SecurityInterfaceObject::_secReportCtrl[] = { 0x00, 0x00, 0x00 };
16 
18 {
19  Property* properties[] =
20  {
23  // ReadCallback of PID_LOAD_STATE_CONTROL
24  [](SecurityInterfaceObject * obj, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t {
25  if (start == 0)
26  return 1;
27 
28  data[0] = obj->_state;
29  return 1;
30  },
31  // WriteCallback of PID_LOAD_STATE_CONTROL
32  [](SecurityInterfaceObject * obj, uint16_t start, uint8_t count, const uint8_t* data) -> uint8_t {
33  obj->loadEvent(data);
34  return 1;
35  }),
37  // Command Callback of PID_SECURITY_MODE
38  [](SecurityInterfaceObject * obj, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) -> void {
39  uint8_t serviceId = data[1] & 0xff;
40 
41  if (serviceId != 0)
42  {
43  resultData[0]
45  resultLength = 1;
46  return;
47  }
48  if (length == 3)
49  {
50  uint8_t mode = data[2];
51 
52  if (mode > 1)
53  {
54  resultData[0] = ReturnCodes::DataVoid;
55  resultLength = 1;
56  return;
57  }
58 
59  obj->setSecurityMode(mode == 1);
60  resultData[0] = ReturnCodes::Success;
61  resultData[1] = serviceId;
62  resultLength = 2;
63  return;
64  }
65  resultData[0] = ReturnCodes::GenericError;
66  resultLength = 1;
67  },
68  // State Callback of PID_SECURITY_MODE
69  [](SecurityInterfaceObject * obj, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) -> void {
70  uint8_t serviceId = data[1] & 0xff;
71 
72  if (serviceId != 0)
73  {
74  resultData[0]
76  resultLength = 1;
77  return;
78  }
79  if (length == 2)
80  {
81  resultData[0]
83  resultData[1] = serviceId;
84  resultData[2] = obj->isSecurityModeEnabled() ? 1 : 0;
85  resultLength = 3;
86  return;
87  }
88  resultData[0] = ReturnCodes::GenericError;
89  resultLength = 1;
90  }),
91  new DataProperty( PID_P2P_KEY_TABLE, true, PDT_GENERIC_20, 1, ReadLv3 | WriteLv0 ), // written by ETS
92  new DataProperty( PID_GRP_KEY_TABLE, true, PDT_GENERIC_18, 50, ReadLv3 | WriteLv0 ), // written by ETS
95  // Command Callback of PID_SECURITY_FAILURES_LOG
96  [](SecurityInterfaceObject * obj, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) -> void {
97  if (length != 3)
98  {
99  resultData[0]
101  resultLength = 1;
102  return;
103  }
104  uint8_t id = data[1];
105  uint8_t info = data[2];
106 
107  if (id == 0 && info == 0)
108  {
109  obj->clearFailureLog();
110  resultData[0] = ReturnCodes::Success;
111  resultData[1] = id;
112  resultLength = 2;
113  return;
114  }
115  resultData[0] = ReturnCodes::GenericError;
116  resultLength = 1;
117  },
118  // State Callback of PID_SECURITY_FAILURES_LOG
119  [](SecurityInterfaceObject * obj, uint8_t* data, uint8_t length, uint8_t* resultData, uint8_t& resultLength) -> void {
120  if (length != 3)
121  {
122  resultData[0]
124  resultLength = 1;
125  return;
126  }
127  uint8_t id = data[1];
128  uint8_t info = data[2];
129 
130  // failure counters
131  if (id == 0 && info == 0)
132  {
133  resultData[0]
135  resultData[1] = id;
136  resultData[2] = info;
137  obj->getFailureCounters(&resultData[3]); // Put 8 bytes in the buffer
138  resultLength = 3 + 8;
139  return;
140  }
141  // query latest failure by index
142  else if (id == 1)
143  {
144  uint8_t maxBufferSize = resultLength; // Remember the maximum buffer size of the buffer that is provided to us
145  uint8_t index = info;
146  uint8_t numBytes = obj->getFromFailureLogByIndex(index, &resultData[2], maxBufferSize);
147 
148  if ( numBytes > 0)
149  {
150  resultData[0] = ReturnCodes::Success;
151  resultData[1] = id;
152  resultData[2] = index;
153  resultLength += numBytes;
154  resultLength = 3 + numBytes;
155  return;
156  }
157 
158  resultData[0] = ReturnCodes::DataVoid;
159  resultData[1] = id;
160  resultLength = 2;
161  return;
162  }
163  resultData[0] = ReturnCodes::GenericError;
164  resultLength = 1;
165  }),
166  new DataProperty( PID_TOOL_KEY, true, PDT_GENERIC_16, 1, ReadLv3 | WriteLv0, (uint8_t*) _fdsk ), // default is FDSK // ETS changes this property during programming from FDSK to some random key!
167  new DataProperty( PID_SECURITY_REPORT, true, PDT_BITSET8, 1, ReadLv3 | WriteLv0, _secReport ), // Not implemented
168  new DataProperty( PID_SECURITY_REPORT_CONTROL, true, PDT_BINARY_INFORMATION, 1, ReadLv3 | WriteLv0, _secReportCtrl ), // Not implemented
169  new DataProperty( PID_SEQUENCE_NUMBER_SENDING, true, PDT_GENERIC_06, 1, ReadLv3 | WriteLv0 ), // Updated by our device accordingly
170  new DataProperty( PID_ZONE_KEY_TABLE, true, PDT_GENERIC_19, 1, ReadLv3 | WriteLv0 ), // written by ETS
171  new DataProperty( PID_GO_SECURITY_FLAGS, true, PDT_GENERIC_01, 256, ReadLv3 | WriteLv0 ), // written by ETS
172  new DataProperty( PID_ROLE_TABLE, true, PDT_GENERIC_01, 1, ReadLv3 | WriteLv0 ), // written by ETS
173  new DataProperty( PID_ERROR_CODE, false, PDT_ENUM8, 1, ReadLv3 | WriteLv0, (uint8_t)E_NO_FAULT),
174  new DataProperty( PID_TOOL_SEQUENCE_NUMBER_SENDING, true, PDT_GENERIC_06, 1, ReadLv3 | WriteLv0 ) // Updated by our device accordingly (non-standardized!)
175  };
176  initializeProperties(sizeof(properties), properties);
177 }
178 
179 uint8_t* SecurityInterfaceObject::save(uint8_t* buffer)
180 {
181  buffer = pushByte(_state, buffer);
182  buffer = pushByte(_securityModeEnabled, buffer);
183 
184  return InterfaceObject::save(buffer);
185 }
186 
187 const uint8_t* SecurityInterfaceObject::restore(const uint8_t* buffer)
188 {
189  uint8_t state = 0;
190  buffer = popByte(state, buffer);
191  _state = (LoadState)state;
192 
193  uint8_t securityModeEnabled = 0;
194  buffer = popByte(securityModeEnabled, buffer);
195  _securityModeEnabled = securityModeEnabled;
196 
197  return InterfaceObject::restore(buffer);
198 }
199 
201 {
202  return 2 + InterfaceObject::saveSize();
203 }
204 
205 void SecurityInterfaceObject::setSecurityMode(bool enabled)
206 {
207  print("Security mode set to: ");
208  println(enabled ? "enabled" : "disabled");
209  _securityModeEnabled = enabled;
210 }
211 
213 {
214  return _securityModeEnabled;
215 }
216 
217 void SecurityInterfaceObject::clearFailureLog()
218 {
219  println("clearFailureLog()");
220 }
221 
222 void SecurityInterfaceObject::getFailureCounters(uint8_t* data)
223 {
224  memset(data, 0, 8);
225  println("getFailureCounters()");
226 }
227 
228 uint8_t SecurityInterfaceObject::getFromFailureLogByIndex(uint8_t index, uint8_t* data, uint8_t maxDataLen)
229 {
230  print("getFromFailureLogByIndex(): Index: ");
231  println(index);
232  return 0;
233 }
234 
236 {
237  return _state == LS_LOADED;
238 }
239 
241 {
242  return _state;
243 }
244 
245 void SecurityInterfaceObject::loadEvent(const uint8_t* data)
246 {
247  switch (_state)
248  {
249  case LS_UNLOADED:
250  loadEventUnloaded(data);
251  break;
252 
253  case LS_LOADING:
254  loadEventLoading(data);
255  break;
256 
257  case LS_LOADED:
258  loadEventLoaded(data);
259  break;
260 
261  case LS_ERROR:
262  loadEventError(data);
263  break;
264 
265  default:
266  /* do nothing */
267  break;
268  }
269 }
270 
271 void SecurityInterfaceObject::loadEventUnloaded(const uint8_t* data)
272 {
273  uint8_t event = data[0];
274 
275  switch (event)
276  {
277  case LE_NOOP:
278  case LE_LOAD_COMPLETED:
280  case LE_UNLOAD:
281  break;
282 
283  case LE_START_LOADING:
285  break;
286 
287  default:
289  errorCode(E_GOT_UNDEF_LOAD_CMD);
290  }
291 }
292 
293 void SecurityInterfaceObject::loadEventLoading(const uint8_t* data)
294 {
295  uint8_t event = data[0];
296 
297  switch (event)
298  {
299  case LE_NOOP:
300  case LE_START_LOADING:
301  break;
302 
303  case LE_LOAD_COMPLETED:
305  break;
306 
307  case LE_UNLOAD:
309  break;
310 
311  case LE_ADDITIONAL_LOAD_CONTROLS: // Not supported here
312  default:
314  errorCode(E_GOT_UNDEF_LOAD_CMD);
315  }
316 }
317 
318 void SecurityInterfaceObject::loadEventLoaded(const uint8_t* data)
319 {
320  uint8_t event = data[0];
321 
322  switch (event)
323  {
324  case LE_NOOP:
325  case LE_LOAD_COMPLETED:
326  break;
327 
328  case LE_START_LOADING:
330  break;
331 
332  case LE_UNLOAD:
334  break;
335 
338  errorCode(E_INVALID_OPCODE);
339  break;
340 
341  default:
343  errorCode(E_GOT_UNDEF_LOAD_CMD);
344  }
345 }
346 
347 void SecurityInterfaceObject::loadEventError(const uint8_t* data)
348 {
349  uint8_t event = data[0];
350 
351  switch (event)
352  {
353  case LE_NOOP:
354  case LE_LOAD_COMPLETED:
356  case LE_START_LOADING:
357  break;
358 
359  case LE_UNLOAD:
361  break;
362 
363  default:
365  errorCode(E_GOT_UNDEF_LOAD_CMD);
366  }
367 }
368 
370 {
371  if (newState == _state)
372  return;
373 
374  //beforeStateChange(newState);
375  _state = newState;
376 }
377 
378 void SecurityInterfaceObject::errorCode(ErrorCode errorCode)
379 {
380  uint8_t data = errorCode;
382  prop->write(data);
383 }
384 
385 void SecurityInterfaceObject::masterReset(EraseCode eraseCode, uint8_t channel)
386 {
387  if (eraseCode == FactoryReset)
388  {
389  // TODO handle different erase codes
390  println("Factory reset of security interface object requested.");
391  setSecurityMode(false);
392  property(PID_TOOL_KEY)->write(1, 1, _fdsk);
393  }
394 }
395 
397 {
398  // There is only one tool key
399  const uint8_t* toolKey = propertyData(PID_TOOL_KEY);
400  return toolKey;
401 }
402 
403 const uint8_t* SecurityInterfaceObject::p2pKey(uint16_t addressIndex)
404 {
405  if (!isLoaded())
406  return nullptr;
407 
408  // Get number of entries for this property
409  uint16_t numElements = getNumberOfElements(PID_P2P_KEY_TABLE);
410 
411  if (numElements > 0)
412  {
413  uint8_t elementSize = propertySize(PID_P2P_KEY_TABLE);
414 
415  // Search for address index
416  uint8_t entry[elementSize]; // 2 bytes index + keysize (16 bytes) + 2 bytes(roles) = 20 bytes
417 
418  for (int i = 1; i <= numElements; i++)
419  {
420  property(PID_P2P_KEY_TABLE)->read(i, 1, entry);
421  uint16_t index = (entry[0] << 8) | entry[1];
422 
423  if (index > addressIndex)
424  {
425  return nullptr;
426  }
427 
428  if (index == addressIndex)
429  {
430  return propertyData(PID_P2P_KEY_TABLE, i) + sizeof(index);
431  }
432  }
433  }
434 
435  return nullptr;
436 }
437 
438 const uint8_t* SecurityInterfaceObject::groupKey(uint16_t addressIndex)
439 {
440  if (!isLoaded())
441  return nullptr;
442 
443  // Get number of entries for this property
444  uint16_t numElements = getNumberOfElements(PID_GRP_KEY_TABLE);
445 
446  if (numElements > 0)
447  {
448  uint8_t elementSize = propertySize(PID_GRP_KEY_TABLE);
449 
450  // Search for address index
451  uint8_t entry[elementSize]; // 2 bytes index + keysize (16 bytes) = 18 bytes
452 
453  for (int i = 1; i <= numElements; i++)
454  {
455  property(PID_GRP_KEY_TABLE)->read(i, 1, entry);
456  uint16_t index = ((entry[0] << 8) | entry[1]);
457 
458  if (index > addressIndex)
459  {
460  return nullptr;
461  }
462 
463  if (index == addressIndex)
464  {
465  return propertyData(PID_GRP_KEY_TABLE, i) + sizeof(index);
466  }
467  }
468  }
469 
470  return nullptr;
471 }
472 
474 {
475  // Get number of entries for this property
476  uint16_t numElements = getNumberOfElements(PID_SECURITY_INDIVIDUAL_ADDRESS_TABLE);
477 
478  if (numElements > 0)
479  {
481 
482  // Search for individual address
483  uint8_t entry[elementSize]; // 2 bytes address + 6 bytes seqno = 8 bytes
484 
485  for (int i = 1; i <= numElements; i++)
486  {
488  uint16_t addr = (entry[0] << 8) | entry[1];
489 
490  if (addr == indAddr)
491  {
492  return i;
493  }
494  }
495  }
496 
497  // Not found
498  return 0;
499 }
500 
501 void SecurityInterfaceObject::setSequenceNumber(bool toolAccess, uint64_t seqNum)
502 {
503  uint8_t seqBytes[6] = {0x00};
504  sixBytesFromUInt64(seqNum, seqBytes);
505 
506  if (toolAccess)
507  {
509  }
510  else
511  {
512  property(PID_SEQUENCE_NUMBER_SENDING)->write(1, 1, seqBytes);
513  }
514 }
515 
516 uint16_t SecurityInterfaceObject::getNumberOfElements(PropertyID propId)
517 {
518  // Get number of entries for this property
519  uint16_t numElements = 0;
520 
521  uint8_t data[sizeof(uint16_t)]; // is sizeof(_currentElements) which is uint16_t
522  uint8_t count = property(propId)->read(0, 1, data);
523 
524  if (count > 0)
525  {
526  popWord(numElements, data);
527  }
528 
529  return numElements;
530 }
531 
533 {
534  // Get number of entries for this property
535  uint16_t numElements = getNumberOfElements(PID_SECURITY_INDIVIDUAL_ADDRESS_TABLE);
536 
537  if (numElements > 0)
538  {
540 
541  // Search for individual address
542  uint8_t entry[elementSize]; // 2 bytes address + 6 bytes seqno = 8 bytes
543 
544  for (int i = 1; i <= numElements; i++)
545  {
547  uint16_t addr = (entry[0] << 8) | entry[1];
548 
549  if (addr == deviceAddr)
550  {
551  return sixBytesToUInt64(&entry[2]);
552  }
553  }
554  }
555 
556  return 0;
557 }
558 
559 void SecurityInterfaceObject::setLastValidSequenceNumber(uint16_t deviceAddr, uint64_t seqNum)
560 {
561  // Get number of entries for this property
562  uint16_t numElements = getNumberOfElements(PID_SECURITY_INDIVIDUAL_ADDRESS_TABLE);
563 
564  if (numElements > 0)
565  {
567 
568  // Search for individual address
569  uint8_t entry[elementSize]; // 2 bytes address + 6 bytes seqno = 8 bytes
570 
571  for (int i = 1; i <= numElements; i++)
572  {
574  uint16_t addr = (entry[0] << 8) | entry[1];
575 
576  if (addr == deviceAddr)
577  {
578  sixBytesFromUInt64(seqNum, &entry[2]);
580  }
581  }
582  }
583 }
584 
586 {
587  // security table uses same index as group object table
588 
589  uint8_t data[propertySize(PID_GO_SECURITY_FLAGS)];
590 
591  uint8_t count = property(PID_GO_SECURITY_FLAGS)->read(index, 1, data);
592 
593  if (count > 0)
594  {
595  // write access flags, approved spec. AN158, p.97
596  bool conf = (data[0] & 2) == 2;
597  bool auth = (data[0] & 1) == 1;
599  }
600 
601  return DataSecurity::None;
602 }
603 
604 #endif
605 
void print(const char *s)
void println(const char *s)
const uint8_t * popByte(uint8_t &b, const uint8_t *data)
Definition: bits.cpp:4
void sixBytesFromUInt64(uint64_t num, uint8_t *toByteArray)
Definition: bits.cpp:101
uint8_t * pushByte(uint8_t b, uint8_t *data)
Definition: bits.cpp:57
uint64_t sixBytesToUInt64(uint8_t *data)
Definition: bits.cpp:111
const uint8_t * popWord(uint16_t &w, const uint8_t *data)
Definition: bits.cpp:34
uint8_t * save(uint8_t *buffer) override
This method is called when the object should save its state to the buffer.
const uint8_t * propertyData(PropertyID id)
const uint8_t * restore(const uint8_t *buffer) override
This method is called when the object should restore its state from the buffer.
virtual uint8_t propertySize(PropertyID id)
Gets the size of of property in bytes.
virtual void state(PropertyID id, uint8_t *data, uint8_t length, uint8_t *resultData, uint8_t &resultLength)
Get state of a function property of the interface object.
virtual void initializeProperties(size_t propertiesSize, Property **properties)
Intializes the Property-array the the supplied values.
uint16_t saveSize() override
Property * property(PropertyID id)
Gets property with PropertyID id if it exists and nullptr otherwise.
virtual uint8_t read(uint16_t start, uint8_t count, uint8_t *data) const =0
virtual uint8_t write(uint16_t start, uint8_t count, const uint8_t *data)=0
const uint8_t * groupKey(uint16_t addressIndex)
uint64_t getLastValidSequenceNumber(uint16_t deviceAddr)
void masterReset(EraseCode eraseCode, uint8_t channel) override
uint8_t * save(uint8_t *buffer) override
This method is called when the object should save its state to the buffer.
void setLastValidSequenceNumber(uint16_t deviceAddr, uint64_t seqNum)
void setSequenceNumber(bool toolAccess, uint64_t seqNum)
const uint8_t * p2pKey(uint16_t addressIndex)
const uint8_t * restore(const uint8_t *buffer) override
This method is called when the object should restore its state from the buffer.
uint16_t indAddressIndex(uint16_t indAddr)
DataSecurity getGroupObjectSecurity(uint16_t index)
@ OT_SECURITY
Security Interface Object.
EraseCode
Definition: knx_types.h:242
@ FactoryReset
Definition: knx_types.h:245
DataSecurity
Definition: knx_types.h:223
@ AuthConf
Definition: knx_types.h:226
@ Auth
Definition: knx_types.h:225
@ None
Definition: knx_types.h:224
@ DataVoid
Definition: knx_types.h:93
@ InvalidCommand
Definition: knx_types.h:87
@ GenericError
Definition: knx_types.h:100
@ Success
Definition: knx_types.h:83
@ LE_START_LOADING
Definition: property.h:210
@ LE_LOAD_COMPLETED
Definition: property.h:211
@ LE_NOOP
Definition: property.h:209
@ LE_UNLOAD
Definition: property.h:213
@ LE_ADDITIONAL_LOAD_CONTROLS
Definition: property.h:212
PropertyID
Definition: property.h:70
@ PID_ERROR_CODE
Definition: property.h:88
@ PID_SECURITY_FAILURES_LOG
Definition: property.h:170
@ PID_P2P_KEY_TABLE
Definition: property.h:167
@ PID_GO_SECURITY_FLAGS
Definition: property.h:176
@ PID_ROLE_TABLE
Definition: property.h:177
@ PID_OBJECT_TYPE
Interface Object Type independent Properties.
Definition: property.h:72
@ PID_SECURITY_INDIVIDUAL_ADDRESS_TABLE
Definition: property.h:169
@ PID_SECURITY_REPORT_CONTROL
Definition: property.h:173
@ PID_TOOL_SEQUENCE_NUMBER_SENDING
Definition: property.h:178
@ PID_SECURITY_MODE
Security Interface Object.
Definition: property.h:166
@ PID_TOOL_KEY
Definition: property.h:171
@ PID_LOAD_STATE_CONTROL
Definition: property.h:73
@ PID_ZONE_KEY_TABLE
Definition: property.h:175
@ PID_GRP_KEY_TABLE
Definition: property.h:168
@ PID_SEQUENCE_NUMBER_SENDING
Definition: property.h:174
@ PID_SECURITY_REPORT
Definition: property.h:172
ErrorCode
Definition: property.h:218
@ E_NO_FAULT
Definition: property.h:219
@ E_GOT_UNDEF_LOAD_CMD
Definition: property.h:233
@ E_INVALID_OPCODE
Definition: property.h:230
@ PDT_CONTROL
length: 1 read, 10 write
Definition: property.h:18
@ PDT_GENERIC_16
length: 16
Definition: property.h:50
@ PDT_GENERIC_08
length: 8
Definition: property.h:42
@ PDT_GENERIC_18
length: 18
Definition: property.h:52
@ PDT_BINARY_INFORMATION
length: 3
Definition: property.h:58
@ PDT_GENERIC_06
length: 6
Definition: property.h:40
@ PDT_BITSET8
length: 3
Definition: property.h:59
@ PDT_ENUM8
length: 3
Definition: property.h:61
@ PDT_GENERIC_19
length: 19
Definition: property.h:53
@ PDT_GENERIC_20
length: 20
Definition: property.h:54
@ PDT_UNSIGNED_INT
length: 2
Definition: property.h:22
@ PDT_GENERIC_01
length: 1
Definition: property.h:35
@ WriteLv0
Definition: property.h:247
@ WriteLv3
Definition: property.h:250
@ ReadLv3
Definition: property.h:246
LoadState
Definition: property.h:198
@ LS_LOADED
Definition: property.h:200
@ LS_UNLOADED
Definition: property.h:199
@ LS_LOADING
Definition: property.h:201
@ LS_ERROR
Definition: property.h:202