knx
ETS configurable knx-stack
secure_application_layer.cpp
Go to the documentation of this file.
1 #include "config.h"
2 #ifdef USE_DATASECURE
3 
5 #include "transport_layer.h"
6 #include "cemi_frame.h"
8 #include "address_table_object.h"
10 #include "device_object.h"
11 #include "apdu.h"
12 #include "bau.h"
13 #include "string.h"
14 #include "bits.h"
15 
16 // Select what cipher modes to include. We need AES128-CBC and AES128-CTR modes.
17 #define CBC 1
18 #define CTR 1
19 #define ECB 0
20 #include "aes.hpp"
21 
22 static constexpr uint8_t kSecureDataPdu = 0;
23 static constexpr uint8_t kSecureSyncRequest = 2;
24 static constexpr uint8_t kSecureSyncResponse = 3;
25 
27  ApplicationLayer(bau),
28  _secIfObj(secIfObj),
29  _deviceObj(deviceObj)
30 {
31 }
32 
34 {
35  _addrTab = &addrTable;
36 }
37 
38 /* from transport layer */
39 
40 void SecureApplicationLayer::dataGroupIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu)
41 {
42  if (_addrTab == nullptr)
43  return;
44 
45  println("dataGroupIndication");
46 
47  if (apdu.type() == SecureService)
48  {
49  // Will be filled in by decodeSecureApdu()
50  SecurityControl secCtrl;
51 
52  // Decrypt secure APDU
53  // Somehow ugly that we need to know the size in advance here at this point
54  uint16_t plainApduLength = apdu.length() - 3 - 6 - 4; // secureAdsuLength - sizeof(tpci,apci,scf) - sizeof(seqNum) - sizeof(mac)
55  CemiFrame plainFrame(plainApduLength);
56 
57  // Decrypt secure APDU
58  if (decodeSecureApdu(apdu, plainFrame.apdu(), secCtrl))
59  {
60  // Process decrypted inner APDU
61  ApplicationLayer::dataGroupIndication(hopType, priority, tsap, plainFrame.apdu(), secCtrl);
62  }
63 
64  return;
65  }
66 
67  ApplicationLayer::dataGroupIndication(hopType, priority, tsap, apdu);
68 }
69 
70 void SecureApplicationLayer::dataGroupConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, bool status)
71 {
72  println("dataGroupConfirm");
73 
74  if (apdu.type() == SecureService)
75  {
76  // We do not care about confirmations of our sync communication
77  if (isSyncService(apdu))
78  {
79  return;
80  }
81 
82  // Will be filled in by decodeSecureApdu()
83  SecurityControl secCtrl;
84 
85  // Decrypt secure APDU
86  // Somehow ugly that we need to know the size in advance here at this point
87  uint16_t plainApduLength = apdu.length() - 3 - 6 - 4; // secureAdsuLength - sizeof(tpci,apci,scf) - sizeof(seqNum) - sizeof(mac)
88  CemiFrame plainFrame(plainApduLength);
89 
90  // Decrypt secure APDU
91  if (decodeSecureApdu(apdu, plainFrame.apdu(), secCtrl))
92  {
93  // Process decrypted inner APDU
94  ApplicationLayer::dataGroupConfirm(ack, hopType, priority, tsap, plainFrame.apdu(), secCtrl, status);
95  }
96 
97  return;
98  }
99 
100  ApplicationLayer::dataGroupConfirm(ack, hopType, priority, tsap, apdu, status);
101 }
102 
103 void SecureApplicationLayer::dataBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu)
104 {
105  println("dataBroadcastIndication");
106 
107  if (apdu.type() == SecureService)
108  {
109  // Will be filled in by decodeSecureApdu()
110  SecurityControl secCtrl;
111 
112  // Decrypt secure APDU
113  // Somehow ugly that we need to know the size in advance here at this point
114  uint16_t plainApduLength = apdu.length() - 3 - 6 - 4; // secureAdsuLength - sizeof(tpci,apci,scf) - sizeof(seqNum) - sizeof(mac)
115  CemiFrame plainFrame(plainApduLength);
116 
117  // Decrypt secure APDU
118  if (decodeSecureApdu(apdu, plainFrame.apdu(), secCtrl))
119  {
120  // Process decrypted inner APDU
121  ApplicationLayer::dataBroadcastIndication(hopType, priority, source, plainFrame.apdu(), secCtrl);
122  }
123 
124  return;
125  }
126 
127  ApplicationLayer::dataBroadcastIndication(hopType, priority, source, apdu);
128 }
129 
130 void SecureApplicationLayer::dataBroadcastConfirm(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, bool status)
131 {
132  println("dataBroadcastConfirm");
133 
134  if (apdu.type() == SecureService)
135  {
136  // We do not care about confirmations of our sync communication
137  if (isSyncService(apdu))
138  {
139  return;
140  }
141 
142  // Will be filled in by decodeSecureApdu()
143  SecurityControl secCtrl;
144 
145  // Decrypt secure APDU
146  // Somehow ugly that we need to know the size in advance here at this point
147  uint16_t plainApduLength = apdu.length() - 3 - 6 - 4; // secureAdsuLength - sizeof(tpci,apci,scf) - sizeof(seqNum) - sizeof(mac)
148  CemiFrame plainFrame(plainApduLength);
149 
150  // Decrypt secure APDU
151  if (decodeSecureApdu(apdu, plainFrame.apdu(), secCtrl))
152  {
153  // Process decrypted inner APDU
154  ApplicationLayer::dataBroadcastConfirm(ack, hopType, priority, plainFrame.apdu(), secCtrl, status);
155  }
156 
157  return;
158  }
159 
160  ApplicationLayer::dataBroadcastConfirm(ack, hopType, priority, apdu, status);
161 }
162 
164 {
165  println("dataSystemBroadcastIndication");
166 
167  if (apdu.type() == SecureService)
168  {
169  // Will be filled in by decodeSecureApdu()
170  SecurityControl secCtrl;
171 
172  // Decrypt secure APDU
173  // Somehow ugly that we need to know the size in advance here at this point
174  uint16_t plainApduLength = apdu.length() - 3 - 6 - 4; // secureAdsuLength - sizeof(tpci,apci,scf) - sizeof(seqNum) - sizeof(mac)
175  CemiFrame plainFrame(plainApduLength);
176 
177  // Decrypt secure APDU
178  if (decodeSecureApdu(apdu, plainFrame.apdu(), secCtrl))
179  {
180  // Process decrypted inner APDU
181  ApplicationLayer::dataSystemBroadcastIndication(hopType, priority, source, plainFrame.apdu(), secCtrl);
182  }
183 
184  return;
185  }
186 
187  ApplicationLayer::dataSystemBroadcastIndication(hopType, priority, source, apdu);
188 }
189 
191 {
192  println("dataSystemBroadcastConfirm");
193 
194  if (apdu.type() == SecureService)
195  {
196  // We do not care about confirmations of our sync communication
197  if (isSyncService(apdu))
198  {
199  return;
200  }
201 
202  // Will be filled in by decodeSecureApdu()
203  SecurityControl secCtrl;
204 
205  // Decrypt secure APDU
206  // Somehow ugly that we need to know the size in advance here at this point
207  uint16_t plainApduLength = apdu.length() - 3 - 6 - 4; // secureAdsuLength - sizeof(tpci,apci,scf) - sizeof(seqNum) - sizeof(mac)
208  CemiFrame plainFrame(plainApduLength);
209 
210  // Decrypt secure APDU
211  if (decodeSecureApdu(apdu, plainFrame.apdu(), secCtrl))
212  {
213  // Process decrypted inner APDU
214  ApplicationLayer::dataSystemBroadcastConfirm(hopType, priority, plainFrame.apdu(), secCtrl, status);
215  }
216 
217  return;
218  }
219 
220  ApplicationLayer::dataSystemBroadcastConfirm(hopType, priority, apdu, status);
221 }
222 
223 void SecureApplicationLayer::dataIndividualIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu)
224 {
225  println("dataIndividualIndication");
226 
227  if (apdu.type() == SecureService)
228  {
229  // Will be filled in by decodeSecureApdu()
230  SecurityControl secCtrl;
231 
232  // Decrypt secure APDU
233  // Somehow ugly that we need to know the size in advance here at this point
234  uint16_t plainApduLength = apdu.length() - 3 - 6 - 4; // secureAdsuLength - sizeof(tpci,apci,scf) - sizeof(seqNum) - sizeof(mac)
235  CemiFrame plainFrame(plainApduLength);
236 
237  // Decrypt secure APDU
238  if (decodeSecureApdu(apdu, plainFrame.apdu(), secCtrl))
239  {
240  // Process decrypted inner APDU
241  ApplicationLayer::dataIndividualIndication(hopType, priority, source, plainFrame.apdu(), secCtrl);
242  }
243 
244  return;
245  }
246 
247  ApplicationLayer::dataIndividualIndication(hopType, priority, source, apdu);
248 }
249 
250 void SecureApplicationLayer::dataIndividualConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t source, APDU& apdu, bool status)
251 {
252  println("dataIndividualConfirm");
253 
254  if (apdu.type() == SecureService)
255  {
256  // We do not care about confirmations of our sync communication
257  if (isSyncService(apdu))
258  {
259  return;
260  }
261 
262  // Will be filled in by decodeSecureApdu()
263  SecurityControl secCtrl;
264 
265  // Decrypt secure APDU
266  // Somehow ugly that we need to know the size in advance here at this point
267  uint16_t plainApduLength = apdu.length() - 3 - 6 - 4; // secureAdsuLength - sizeof(tpci,apci,scf) - sizeof(seqNum) - sizeof(mac)
268  CemiFrame plainFrame(plainApduLength);
269 
270  // Decrypt secure APDU
271  if (decodeSecureApdu(apdu, plainFrame.apdu(), secCtrl))
272  {
273  // Process decrypted inner APDU
274  ApplicationLayer::dataIndividualConfirm(ack, hopType, priority, source, apdu, secCtrl, status);
275  }
276 
277  return;
278  }
279  else
280  {
281  ApplicationLayer::dataIndividualConfirm(ack, hopType, priority, source, apdu, status);
282  }
283 }
284 
286 {
287  println("dataConnectedIndication");
288 
289  if (apdu.type() == SecureService)
290  {
291  // Will be filled in by decodeSecureApdu()
292  SecurityControl secCtrl;
293 
294  // Decrypt secure APDU
295  // Somehow ugly that we need to know the size in advance here at this point
296  uint16_t plainApduLength = apdu.length() - 3 - 6 - 4; // secureAdsuLength - sizeof(tpci,apci,scf) - sizeof(seqNum) - sizeof(mac)
297  CemiFrame plainFrame(plainApduLength);
298 
299  // Decrypt secure APDU
300  if (decodeSecureApdu(apdu, plainFrame.apdu(), secCtrl))
301  {
302  // Process decrypted inner APDU
303  ApplicationLayer::dataConnectedIndication(priority, tsap, plainFrame.apdu(), secCtrl);
304  }
305 
306  return;
307  }
308 
309  ApplicationLayer::dataConnectedIndication(priority, tsap, apdu);
310 }
311 
313 {
314  // Just the confirmation issued by the transport layer in case of T_DATA_CONNECTED
316 }
317 
318 /* to transport layer */
319 
320 void SecureApplicationLayer::dataGroupRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl)
321 {
322  if (_addrTab == nullptr)
323  return;
324 
325  println("dataGroupRequest");
326 
327  if (secCtrl.dataSecurity != DataSecurity::None)
328  {
329  apdu.frame().sourceAddress(_deviceObj.individualAddress());
330  apdu.frame().destinationAddress(_addrTab->getGroupAddress(tsap));
332 
333  uint16_t secureApduLength = apdu.length() + 3 + 6 + 4; // 3(TPCI,APCI,SCF) + sizeof(seqNum) + apdu.length() + 4
334  CemiFrame secureFrame(secureApduLength);
335 
336  // create secure APDU
337  if (createSecureApdu(apdu, secureFrame.apdu(), secCtrl))
338  {
339  ApplicationLayer::dataGroupRequest(ack, hopType, priority, tsap, secureFrame.apdu(), secCtrl);
340  }
341 
342  return;
343  }
344 
345  ApplicationLayer::dataGroupRequest(ack, hopType, priority, tsap, apdu, secCtrl);
346 }
347 
349 {
350  println("dataBroadcastRequest");
351 
352  if (secCtrl.dataSecurity != DataSecurity::None)
353  {
354  apdu.frame().sourceAddress(_deviceObj.individualAddress());
355  apdu.frame().destinationAddress(0x0000);
358 
359  uint16_t secureApduLength = apdu.length() + 3 + 6 + 4; // 3(TPCI,APCI,SCF) + sizeof(seqNum) + apdu.length() + 4
360  CemiFrame secureFrame(secureApduLength);
361 
362  // create secure APDU
363  if (createSecureApdu(apdu, secureFrame.apdu(), secCtrl))
364  {
365  ApplicationLayer::dataBroadcastRequest(ack, hopType, SystemPriority, secureFrame.apdu(), secCtrl);
366  }
367 
368  return;
369  }
370 
371  ApplicationLayer::dataBroadcastRequest(ack, hopType, SystemPriority, apdu, secCtrl);
372 }
373 
375 {
376  println("dataSystemBroadcastRequest");
377 
378  if (secCtrl.dataSecurity != DataSecurity::None)
379  {
380  apdu.frame().sourceAddress(_deviceObj.individualAddress());
381  apdu.frame().destinationAddress(0x0000);
384 
385  uint16_t secureApduLength = apdu.length() + 3 + 6 + 4; // 3(TPCI,APCI,SCF) + sizeof(seqNum) + apdu.length() + 4
386  CemiFrame secureFrame(secureApduLength);
387 
388  // create secure APDU
389  if (createSecureApdu(apdu, secureFrame.apdu(), secCtrl))
390  {
391  ApplicationLayer::dataSystemBroadcastRequest(ack, hopType, SystemPriority, secureFrame.apdu(), secCtrl);
392  }
393 
394  return;
395  }
396 
397  ApplicationLayer::dataSystemBroadcastRequest(ack, hopType, SystemPriority, apdu, secCtrl);
398 }
399 
400 void SecureApplicationLayer::dataIndividualRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t destination, APDU& apdu, const SecurityControl& secCtrl)
401 {
402  println("dataIndividualRequest");
403 
404  if (secCtrl.dataSecurity != DataSecurity::None)
405  {
406  apdu.frame().sourceAddress(_deviceObj.individualAddress());
407  apdu.frame().destinationAddress(destination);
409 
410  uint16_t secureApduLength = apdu.length() + 3 + 6 + 4; // 3(TPCI,APCI,SCF) + sizeof(seqNum) + apdu.length() + 4
411  CemiFrame secureFrame(secureApduLength);
412 
413  // create secure APDU
414  if (createSecureApdu(apdu, secureFrame.apdu(), secCtrl))
415  {
416  ApplicationLayer::dataIndividualRequest(ack, hopType, priority, destination, secureFrame.apdu(), secCtrl);
417  }
418 
419  return;
420  }
421 
422  ApplicationLayer::dataIndividualRequest(ack, hopType, priority, destination, apdu, secCtrl);
423 }
424 
425 void SecureApplicationLayer::dataConnectedRequest(uint16_t tsap, Priority priority, APDU& apdu, const SecurityControl& secCtrl)
426 {
427  println("dataConnectedRequest");
428 
429  if (secCtrl.dataSecurity != DataSecurity::None)
430  {
431  apdu.frame().sourceAddress(_deviceObj.individualAddress());
434 
435  uint16_t secureApduLength = apdu.length() + 3 + 6 + 4; // 3(TPCI,APCI,SCF) + sizeof(seqNum) + apdu.length() + 4
436  CemiFrame secureFrame(secureApduLength);
437 
438  // create secure APDU
439  if (createSecureApdu(apdu, secureFrame.apdu(), secCtrl))
440  {
441  ApplicationLayer::dataConnectedRequest(tsap, priority, secureFrame.apdu(), secCtrl);
442  }
443 
444  return;
445  }
446 
447  // apdu must be valid until it was confirmed
448  ApplicationLayer::dataConnectedRequest(tsap, priority, apdu, secCtrl);
449 }
450 
451 void SecureApplicationLayer::encryptAesCbc(uint8_t* buffer, uint16_t bufLen, const uint8_t* iv, const uint8_t* key)
452 {
453  // Use zeroes as IV for first round
454  uint8_t zeroIv[16] = {0x00};
455 
456  struct AES_ctx ctx;
457  AES_init_ctx_iv(&ctx, key, zeroIv);
458 
459  // Now encrypt first block B0.
460  AES_CBC_encrypt_buffer(&ctx, (uint8_t*) iv, 16);
461 
462  // Encrypt remaining buffer
463  AES_CBC_encrypt_buffer(&ctx, buffer, bufLen);
464 }
465 
466 void SecureApplicationLayer::xcryptAesCtr(uint8_t* buffer, uint16_t bufLen, const uint8_t* iv, const uint8_t* key)
467 {
468  struct AES_ctx ctx;
469 
470  AES_init_ctx_iv(&ctx, key, iv);
471 
472  AES_CTR_xcrypt_buffer(&ctx, buffer, bufLen);
473 }
474 
475 uint32_t SecureApplicationLayer::calcAuthOnlyMac(uint8_t* apdu, uint8_t apduLength, const uint8_t* key, uint8_t* iv, uint8_t* ctr0)
476 {
477  uint16_t bufLen = 2 + apduLength; // 2 bytes for the length field (uint16_t)
478  // AES-128 operates on blocks of 16 bytes, add padding
479  uint16_t bufLenPadded = (bufLen + 15) / 16 * 16;
480  uint8_t buffer[bufLenPadded];
481  // Make sure to have zeroes everywhere, because of the padding
482  memset(buffer, 0x00, bufLenPadded);
483 
484  uint8_t* pBuf = buffer;
485 
486  pBuf = pushWord(apduLength, pBuf);
487  pBuf = pushByteArray(apdu, apduLength, pBuf);
488 
489  encryptAesCbc(buffer, bufLenPadded, iv, key);
490  xcryptAesCtr(buffer, 4, ctr0, key); // 4 bytes only for the MAC
491 
492  uint32_t mac;
493  popInt(mac, &buffer[0]);
494 
495  return mac;
496 }
497 
498 uint32_t SecureApplicationLayer::calcConfAuthMac(uint8_t* associatedData, uint16_t associatedDataLength,
499  uint8_t* apdu, uint8_t apduLength,
500  const uint8_t* key, uint8_t* iv)
501 {
502  uint16_t bufLen = 2 + associatedDataLength + apduLength; // 2 bytes for the length field (uint16_t)
503  // AES-128 operates on blocks of 16 bytes, add padding
504  uint16_t bufLenPadded = (bufLen + 15) / 16 * 16;
505  uint8_t buffer[bufLenPadded];
506  // Make sure to have zeroes everywhere, because of the padding
507  memset(buffer, 0x00, bufLenPadded);
508 
509  uint8_t* pBuf = buffer;
510 
511  pBuf = pushWord(associatedDataLength, pBuf);
512  pBuf = pushByteArray(associatedData, associatedDataLength, pBuf);
513  pBuf = pushByteArray(apdu, apduLength, pBuf);
514 
515  encryptAesCbc(buffer, bufLenPadded, iv, key);
516 
517  uint32_t mac;
518  popInt(mac, &buffer[bufLenPadded - 16]); // bufLenPadded has a guaranteed minimum size of 16 bytes
519 
520  return mac;
521 }
522 
523 void SecureApplicationLayer::block0(uint8_t* buffer, uint8_t* seqNum, uint16_t indSrcAddr, uint16_t dstAddr, bool dstAddrIsGroupAddr, uint8_t extFrameFormat, uint8_t tpci, uint8_t apci, uint8_t payloadLength)
524 {
525  uint8_t* pBuf = buffer;
526  pBuf = pushByteArray(seqNum, 6, pBuf);
527  pBuf = pushWord(indSrcAddr, pBuf);
528  pBuf = pushWord(dstAddr, pBuf);
529  pBuf = pushByte(0x00, pBuf); // FT: frametype
530  pBuf = pushByte( (dstAddrIsGroupAddr ? 0x80 : 0x00) | (extFrameFormat & 0xf), pBuf); // AT: address type
531  pBuf = pushByte(tpci, pBuf); // TPCI
532  pBuf = pushByte(apci, pBuf); // APCI // draft spec shows something different!
533  pBuf = pushByte(0x00, pBuf); // Reserved: fixed 0x00 (really?)
534  pBuf = pushByte(payloadLength, pBuf); // Payload length
535 }
536 
537 void SecureApplicationLayer::blockCtr0(uint8_t* buffer, uint8_t* seqNum, uint16_t indSrcAddr, uint16_t dstAddr)
538 {
539  uint8_t* pBuf = buffer;
540  pBuf = pushByteArray(seqNum, 6, pBuf);
541  pBuf = pushWord(indSrcAddr, pBuf);
542  pBuf = pushWord(dstAddr, pBuf);
543  pBuf = pushInt(0x00000000, pBuf);
544  pBuf = pushByte(0x01, pBuf);
545 }
546 
547 uint16_t SecureApplicationLayer::groupAddressIndex(uint16_t groupAddr)
548 {
549  // Just for safety reasons, we should never get here, because the dataGroupIndication will return already return early without doing anything
550  if (_addrTab == nullptr)
551  return 0;
552 
553  return _addrTab->getTsap(groupAddr);
554 }
555 
556 const uint8_t* SecureApplicationLayer::securityKey(uint16_t addr, bool isGroupAddress)
557 {
558  if (isGroupAddress)
559  {
560  uint16_t gaIndex = groupAddressIndex(addr);
561 
562  if (gaIndex > 0)
563  return _secIfObj.groupKey(gaIndex);
564  }
565  else
566  {
567  uint16_t iaIndex = _secIfObj.indAddressIndex(addr);
568 
569  if (iaIndex > 0)
570  return _secIfObj.p2pKey(iaIndex);
571  }
572 
573  return nullptr;
574 }
575 
576 // returns next outgoing sequence number for secure communication
577 uint64_t SecureApplicationLayer::nextSequenceNumber(bool toolAccess)
578 {
579  return toolAccess ? _sequenceNumberToolAccess : _sequenceNumber;
580 }
581 
582 // stores next outgoing sequence number for secure communication
583 void SecureApplicationLayer::updateSequenceNumber(bool toolAccess, uint64_t seqNum)
584 {
585  if (toolAccess)
586  {
587  _sequenceNumberToolAccess = seqNum;
588  }
589  else
590  {
591  _sequenceNumber = seqNum;
592  }
593 
594  // Also update the properties accordingly
595  _secIfObj.setSequenceNumber(toolAccess, seqNum);
596 }
597 
598 uint64_t SecureApplicationLayer::lastValidSequenceNumber(bool toolAccess, uint16_t srcAddr)
599 {
600  if (toolAccess)
601  {
602  // TODO: check if we really have to support multiple tools at the same time
603  if (srcAddr == _deviceObj.individualAddress())
604  return _sequenceNumberToolAccess;
605 
606  return _lastValidSequenceNumberTool;
607  }
608  else
609  {
610  return _secIfObj.getLastValidSequenceNumber(srcAddr);
611  }
612 
613  return 0;
614 }
615 
616 void SecureApplicationLayer::updateLastValidSequence(bool toolAccess, uint16_t remoteAddr, uint64_t seqNo)
617 {
618  if (toolAccess)
619  // TODO: check if we really have to support multiple tools at the same time
620  _lastValidSequenceNumberTool = seqNo;
621  else
622  {
623  _secIfObj.setLastValidSequenceNumber(remoteAddr, seqNo);
624  }
625 }
626 
627 void SecureApplicationLayer::sendSyncRequest(uint16_t dstAddr, bool dstAddrIsGroupAddr, const SecurityControl& secCtrl, bool systemBcast)
628 {
629  if (secCtrl.dataSecurity != DataSecurity::AuthConf)
630  {
631  println("sync.req is always sent with auth+conf!");
632  return;
633  }
634 
635  _syncReqBroadcastOutgoing = (dstAddr == 0x0000) && dstAddrIsGroupAddr;
636 
637  // use random number in SyncResponse
638  uint64_t challenge = getRandomNumber();
639 
640  uint8_t asdu[6];
641  sixBytesFromUInt64(challenge, &asdu[0]);
642 
643  CemiFrame request(2 + 6 + sizeof(asdu) + 4); // 2 bytes (APCI, SCF) + 6 bytes (SeqNum) + 6 bytes (challenge) + 4 bytes (MAC)
644  // Note: additional TPCI byte is already handled internally!
645 
646  uint8_t tpci = 0;
647 
648  if (!_syncReqBroadcastOutgoing)
649  {
650  if (isConnected())
651  {
652  tpci |= 0x40 | _transportLayer->getTpciSeqNum(); // get next TPCI sequence number for MAC calculation from TL (T_DATA_CONNECTED)
653  }
654  }
655 
656  print("sendSyncRequest: TPCI: ");
657  println(tpci, HEX);
658 
659  if (secure(request.data() + APDU_LPDU_DIFF, kSecureSyncRequest, _deviceObj.individualAddress(), dstAddr, dstAddrIsGroupAddr, tpci, asdu, sizeof(asdu), secCtrl, systemBcast))
660  {
661  println("SyncRequest: ");
662  request.apdu().printPDU();
663 
664  if (_syncReqBroadcastOutgoing)
665  {
667  }
668  else
669  {
670  // either send on T_DATA_INDIVIDUAL or T_DATA_CONNECTED
671  if (isConnected())
672  {
674  }
675  else
676  {
677  // Send encrypted SyncResponse message using T_DATA_INDIVIDUAL
679  }
680  }
681 
682  Addr toAddr = _syncReqBroadcastOutgoing ? (Addr)GrpAddr(0) : (Addr)IndAddr(dstAddr);
683  _pendingOutgoingSyncRequests.insertOrAssign(toAddr, challenge);
684  }
685  else
686  {
687  println("SyncRequest: failure during encryption");
688  }
689 }
690 
691 void SecureApplicationLayer::sendSyncResponse(uint16_t dstAddr, bool dstAddrIsGroupAddr, const SecurityControl& secCtrl, uint64_t remoteNextSeqNum, bool systemBcast)
692 {
693  if (secCtrl.dataSecurity != DataSecurity::AuthConf)
694  {
695  println("sync.res is always sent with auth+conf!");
696  return;
697  }
698 
699  uint64_t ourNextSeqNum = nextSequenceNumber(secCtrl.toolAccess);
700 
701  uint8_t asdu[12];
702  sixBytesFromUInt64(ourNextSeqNum, &asdu[0]);
703  sixBytesFromUInt64(remoteNextSeqNum, &asdu[6]);
704 
705  CemiFrame response(2 + 6 + sizeof(asdu) + 4); // 2 bytes (APCI, SCF) + 6 bytes (SeqNum) + 12 bytes + 4 bytes (MAC)
706  // Note: additional TPCI byte is already handled internally!
707 
708  uint8_t tpci = 0;
709 
710  if (!_syncReqBroadcastIncoming)
711  {
712  if (isConnected())
713  {
714  tpci |= 0x40 | _transportLayer->getTpciSeqNum(); // get next TPCI sequence number for MAC calculation from TL (T_DATA_CONNECTED)
715  }
716  }
717 
718  print("sendSyncResponse: TPCI: ");
719  println(tpci, HEX);
720 
721  if (secure(response.data() + APDU_LPDU_DIFF, kSecureSyncResponse, _deviceObj.individualAddress(), dstAddr, dstAddrIsGroupAddr, tpci, asdu, sizeof(asdu), secCtrl, systemBcast))
722  {
723  _lastSyncRes = millis();
724 
725  println("SyncResponse: ");
726  response.apdu().printPDU();
727 
728  if (_syncReqBroadcastIncoming)
729  {
731  }
732  else
733  {
734  // either send on T_DATA_INDIVIDUAL or T_DATA_CONNECTED
735  if (isConnected())
736  {
738  }
739  else
740  {
741  // Send encrypted SyncResponse message using T_DATA_INDIVIDUAL
743  }
744  }
745  }
746  else
747  {
748  println("SyncResponse: failure during encryption");
749  }
750 }
751 
752 void SecureApplicationLayer::receivedSyncRequest(uint16_t srcAddr, uint16_t dstAddr, bool dstAddrIsGroupAddr, const SecurityControl& secCtrl, uint8_t* seqNum, uint64_t challenge, bool systemBcast)
753 {
754  println("Received SyncRequest:");
755 
756  uint64_t nextRemoteSeqNum = sixBytesToUInt64(seqNum);
757  uint64_t nextSeqNum = 1 + lastValidSequenceNumber(secCtrl.toolAccess, srcAddr);
758 
759  if (nextRemoteSeqNum > nextSeqNum)
760  {
761  updateLastValidSequence(secCtrl.toolAccess, srcAddr, nextRemoteSeqNum - 1);
762  nextSeqNum = nextRemoteSeqNum;
763  }
764 
765  _syncReqBroadcastIncoming = (dstAddr == 0x0000) && dstAddrIsGroupAddr;
766 
767  // Remember challenge for securing the sync.res later
768  _pendingIncomingSyncRequests.insertOrAssign(_syncReqBroadcastIncoming ? (Addr) GrpAddr(0) : (Addr) IndAddr(srcAddr), challenge);
769 
770  uint16_t toAddr = _syncReqBroadcastIncoming ? dstAddr : srcAddr;
771  bool toIsGroupAddress = _syncReqBroadcastIncoming;
772  sendSyncResponse(toAddr, toIsGroupAddress, secCtrl, nextSeqNum, systemBcast);
773 }
774 
775 void SecureApplicationLayer::receivedSyncResponse(uint16_t remote, const SecurityControl& secCtrl, uint8_t* plainApdu)
776 {
777  println("Received SyncResponse:");
778 
779  if (_syncReqBroadcastOutgoing)
780  {
781  if (_pendingOutgoingSyncRequests.get(GrpAddr(0)) == nullptr)
782  {
783  println("Cannot handle sync.res without pending sync.req! (broadcast/systembroadcast)");
784  return;
785  }
786  }
787  else
788  {
789  if (_pendingOutgoingSyncRequests.get(IndAddr(remote)) == nullptr)
790  {
791  println("Cannot handle sync.res without pending sync.req!");
792  return;
793  }
794  }
795 
796  // Bytes 0-5 in the "APDU" buffer contain the remote sequence number
797  // Bytes 6-11 in the "APDU" buffer contain the local sequence number
798  uint64_t remoteSeq = sixBytesToUInt64(plainApdu + 0);
799  uint64_t localSeq = sixBytesToUInt64(plainApdu + 6);
800 
801  uint64_t last = lastValidSequenceNumber(secCtrl.toolAccess, remote);
802 
803  if (remoteSeq - 1 > last)
804  {
805  //logger.debug("sync.res update {} last valid {} seq -> {}", remote, toolAccess ? "tool access" : "p2p", remoteSeq -1);
806  updateLastValidSequence(secCtrl.toolAccess, remote, remoteSeq - 1);
807  }
808 
809  uint64_t next = nextSequenceNumber(secCtrl.toolAccess);
810 
811  if (localSeq > next)
812  {
813  //logger.debug("sync.res update local next {} seq -> {}", toolAccess ? "tool access" : "p2p", localSeq);
814  updateSequenceNumber(secCtrl.toolAccess, localSeq);
815  }
816 
817  Addr remoteAddr = _syncReqBroadcastOutgoing ? (Addr)GrpAddr(0) : (Addr)IndAddr(remote);
818  _pendingOutgoingSyncRequests.erase(remoteAddr);
819 }
820 
821 bool SecureApplicationLayer::decrypt(uint8_t* plainApdu, uint16_t plainApduLength, uint16_t srcAddr, uint16_t dstAddr, bool dstAddrIsGroupAddr, uint8_t tpci, uint8_t* secureAsdu, SecurityControl& secCtrl, bool systemBcast)
822 {
823  const uint8_t* pBuf;
824  uint8_t scf;
825 
826  pBuf = popByte(scf, secureAsdu);
827 
828  bool toolAccess = ((scf & 0x80) == 0x80);
829  bool systemBroadcast = ((scf & 0x08) == 0x08);
830  uint8_t sai = (scf >> 4) & 0x07; // sai can only be 0x0 (CCM auth only) or 0x1 (CCM with auth+conf), other values are reserved
831  bool authOnly = ( sai == 0);
832  uint8_t service = (scf & 0x07); // only 0x0 (S-A_Data-PDU), 0x2 (S-A_Sync_Req-PDU) or 0x3 (S-A_Sync_Rsp-PDU) are valid values
833 
834  if (systemBroadcast != systemBcast)
835  {
836  println("SBC flag in SCF does not match actual communication mode!");
837  }
838 
839  secCtrl.toolAccess = toolAccess;
841 
842  bool syncReq = service == kSecureSyncRequest;
843  bool syncRes = service == kSecureSyncResponse;
844 
845  //const uint8_t* key = dstAddrIsGroupAddr ? securityKey(dstAddr, dstAddrIsGroupAddr) : toolAccess ? toolKey() : securityKey(srcAddr, false);
846  const uint8_t* key = dstAddrIsGroupAddr && (dstAddr != 0) ? securityKey(dstAddr, dstAddrIsGroupAddr) : toolAccess ? _secIfObj.toolKey() : securityKey(srcAddr, false);
847 
848  if (key == nullptr)
849  {
850  print("Error: No key found. toolAccess: ");
851  println(toolAccess ? "true" : "false");
852  return false;
853  }
854 
855  uint8_t seqNum[6];
856  pBuf = popByteArray(seqNum, 6, pBuf);
857  uint64_t receivedSeqNumber = sixBytesToUInt64(seqNum);
858 
859  // Provide array for KNX serial number if it is a SyncRequest
860  // DataService and SyncResponse do not use this variable.
861  uint8_t knxSerialNumber[6];
862 
863  uint16_t remainingPlainApduLength = plainApduLength;
864 
865  if (service == kSecureDataPdu)
866  {
867  if (srcAddr != _deviceObj.individualAddress())
868  {
869  uint64_t expectedSeqNumber = lastValidSequenceNumber(toolAccess, srcAddr) + 1;
870 
871  if (receivedSeqNumber < expectedSeqNumber)
872  {
873  // security failure
874  print("security failure: received seqNum: ");
875  print(receivedSeqNumber, HEX);
876  print(" < expected seqNum: ");
877  print(expectedSeqNumber, HEX);
878  return false;
879  }
880  }
881  }
882  else if (syncReq)
883  {
884  pBuf = popByteArray(knxSerialNumber, 6, pBuf);
885  remainingPlainApduLength -= 6;
886 
887  // ignore sync.reqs not addressed to us
888  if (!memcmp(knxSerialNumber, _deviceObj.propertyData(PID_SERIAL_NUMBER), 6))
889  {
890  uint8_t emptySerialNumber[6] = {0};
891 
892  if (systemBroadcast || dstAddr != _deviceObj.individualAddress() || !memcmp(knxSerialNumber, emptySerialNumber, 6))
893  return false;
894  }
895 
896  // if responded to another request within the last 1 second, ignore
897  if ((millis() - _lastSyncRes) < 1000)
898  {
899  return false;
900  }
901  }
902  else if (syncRes)
903  {
904  // fetch challenge depending on srcAddr to handle multiple requests
905  uint64_t* challenge = _pendingOutgoingSyncRequests.get(IndAddr(srcAddr));
906 
907  if (challenge == nullptr)
908  {
909  println("Cannot find matching challenge for source address!");
910  return false;
911  }
912 
913  uint8_t _challengeSixBytes[6];
914  sixBytesFromUInt64(*challenge, _challengeSixBytes);
915 
916  // in a sync.res, seq actually contains our challenge from sync.req xored with a random value
917  // extract the random value and store it in seqNum to use it for block0 and ctr0
918  for (uint8_t i = 0; i < sizeof(seqNum); i++)
919  {
920  seqNum[i] ^= _challengeSixBytes[i];
921  }
922  }
923 
924  pBuf = popByteArray(plainApdu, remainingPlainApduLength, pBuf);
925 
926  // No LTE-HEE for now
927  // Data Secure always uses extended frame format with APDU length > 15 octets (long messages), no standard frames
928  uint8_t extendedFrameFormat = 0;
929  // Clear IV buffer
930  uint8_t iv[16] = {0x00};
931  // Create first block B0 for AES CBC MAC calculation, used as IV later
932  /*
933  printHex("seq: ", seqNum, 6);
934  printHex("src: ", (uint8_t*) &srcAddr, 2);
935  printHex("dst: ", (uint8_t*) &dstAddr, 2);
936  print("dstAddrisGroup: ");println(dstAddrIsGroupAddr ? "true" : "false");
937  */
938  block0(iv, seqNum, srcAddr, dstAddr, dstAddrIsGroupAddr, extendedFrameFormat, tpci | (SecureService >> 8), SecureService & 0x00FF, remainingPlainApduLength);
939 
940  // Clear block counter0 buffer
941  uint8_t ctr0[16] = {0x00};
942  // Create first block for block counter 0
943  blockCtr0(ctr0, seqNum, srcAddr, dstAddr);
944 
945  uint32_t mac;
946  pBuf = popInt(mac, pBuf);
947 
948  if (authOnly)
949  {
950  // APDU is already plain, no decryption needed
951 
952  // Only check the MAC
953  uint32_t calculatedMac = calcAuthOnlyMac(plainApdu, remainingPlainApduLength, key, iv, ctr0);
954 
955  if (calculatedMac != mac)
956  {
957  // security failure
958  print("security failure(auth): calculated MAC: ");
959  print(calculatedMac, HEX);
960  print(" != received MAC: ");
961  print(mac, HEX);
962  println("\n");
963 
964  return false;
965  }
966 
967  memcpy(plainApdu, secureAsdu, remainingPlainApduLength);
968  }
969  else
970  {
971  // APDU is encrypted and needs decryption
972 
973  uint16_t bufLen = 4 + remainingPlainApduLength;
974  // AES-128 operates on blocks of 16 bytes, add padding
975  uint16_t bufLenPadded = (bufLen + 15) / 16 * 16;
976  uint8_t buffer[bufLenPadded];
977  //uint8_t buffer[bufLen];
978  // Make sure to have zeroes everywhere, because of the padding
979  memset(buffer, 0x00, bufLenPadded);
980 
981  pushInt(mac, &buffer[0]);
982  pushByteArray(plainApdu, remainingPlainApduLength, &buffer[4]); // apdu is still encrypted
983 
984  xcryptAesCtr(buffer, bufLenPadded, ctr0, key);
985  //xcryptAesCtr(buffer, bufLen, ctr0, key);
986 
987  uint32_t decryptedMac;
988  popInt(decryptedMac, &buffer[0]);
989  popByteArray(plainApdu, remainingPlainApduLength, &buffer[4]); // apdu is now decrypted (overwritten)
990 
991  // Do calculations for Auth+Conf
992  uint8_t associatedData[syncReq ? 7 : 1];
993  associatedData[0] = scf;
994 
995  if (syncReq)
996  {
997  memcpy(&associatedData[1], knxSerialNumber, 6);
998  }
999 
1000  /*
1001  printHex("APDU--------->", plainApdu, remainingPlainApduLength);
1002  printHex("Key---------->", key, 16);
1003  printHex("ASSOC-------->", associatedData, sizeof(associatedData));
1004  */
1005  uint32_t calculatedMac = calcConfAuthMac(associatedData, sizeof(associatedData), plainApdu, remainingPlainApduLength, key, iv);
1006 
1007  if (calculatedMac != decryptedMac)
1008  {
1009  // security failure
1010  print("security failure(conf+auth): calculated MAC: ");
1011  print(calculatedMac, HEX);
1012  print(" != decrypted MAC: ");
1013  print(decryptedMac, HEX);
1014  println("\n");
1015 
1016  return false;
1017  }
1018 
1019  // prevent a sync.req sent by us to trigger sync notification, this happens if we provide our own tool key
1020  // for decryption above
1021  if (syncReq && (srcAddr == _deviceObj.individualAddress()))
1022  return false;
1023 
1024  if (syncReq)
1025  {
1026  uint64_t challenge = sixBytesToUInt64(&plainApdu[0]);
1027  receivedSyncRequest(srcAddr, dstAddr, dstAddrIsGroupAddr, secCtrl, seqNum, challenge, systemBroadcast);
1028  return false;
1029  }
1030  else if (syncRes)
1031  {
1032  receivedSyncResponse(srcAddr, secCtrl, plainApdu);
1033  return false;
1034  }
1035  else
1036  {
1037  if (srcAddr == _deviceObj.individualAddress())
1038  {
1039  print("Update our next ");
1040  print(toolAccess ? "tool access" : "");
1041  print(" seq from ");
1042  print(srcAddr, HEX);
1043  print(" -> (+1) ");
1044  println(receivedSeqNumber, HEX);
1045  updateSequenceNumber(toolAccess, receivedSeqNumber + 1);
1046  }
1047  else
1048  {
1049  print("Update last valid ");
1050  print(toolAccess ? "tool access" : "");
1051  print(" seq from ");
1052  print(srcAddr, HEX);
1053  print(" -> ");
1054  println(receivedSeqNumber, HEX);
1055  updateLastValidSequence(toolAccess, srcAddr, receivedSeqNumber);
1056  }
1057  }
1058  }
1059 
1060  return true;
1061 }
1062 
1063 bool SecureApplicationLayer::decodeSecureApdu(APDU& secureApdu, APDU& plainApdu, SecurityControl& secCtrl)
1064 {
1065  // Decode secure APDU
1066 
1067  println("decodeSecureApdu: Secure APDU: ");
1068  secureApdu.printPDU();
1069 
1070  uint16_t srcAddress = secureApdu.frame().sourceAddress();
1071  uint16_t dstAddress = secureApdu.frame().destinationAddress();
1072  bool isDstAddrGroupAddr = secureApdu.frame().addressType() == GroupAddress;
1073  bool isSystemBroadcast = secureApdu.frame().systemBroadcast();
1074  uint8_t tpci = secureApdu.frame().data()[TPDU_LPDU_DIFF]; // FIXME: when cEMI class is refactored, there might be additional info fields in cEMI [fixed TPDU_LPDU_DIFF]
1075  print("decodeSecureApdu: TPCI: ");
1076  println(tpci, HEX);
1077  // Note:
1078  // The TPCI is also included in the MAC calculation to provide authenticity for this field.
1079  // However, a secure APDU (with a MAC) is only included in transport layer PDUs T_DATA_GROUP, T_DATA_TAG_GROUP, T_DATA_INDIVIDUAL, T_DATA_CONNECTED
1080  // and not in T_CONNECT, T_DISCONNECT, T_ACK, T_NACK.
1081  // This means the DATA/CONTROL flag is always 0(=DATA). The flag "NUMBERED" differentiates between T_DATA_INDIVIDUAL and T_DATA_CONNECTED.
1082  // The seqNumber is only used in T_DATA_CONNECTED and 0 in case of T_DATA_GROUP and T_DATA_GROUP (leaving out T_DATA_TAG_GROUP).
1083  // Summary: effectively only the "NUMBERED" flag (bit6) and the SeqNumber (bit5-2) are used from transport layer.
1084  // In T_DATA_* services the bits1-0 of TPCI octet are used as bits9-8 for APCI type which is fixed to 0x03. SecureService APCI is 0x03F1.
1085 
1086  // FIXME: when cEMI class is refactored, there might be additional info fields in cEMI (fixed APDU_LPDU_DIFF)
1087  // We are starting from TPCI octet (including): plainApdu.frame().data()+APDU_LPDU_DIFF
1088  if (decrypt(plainApdu.frame().data() + APDU_LPDU_DIFF, plainApdu.length() + 1, srcAddress, dstAddress, isDstAddrGroupAddr, tpci, secureApdu.data() + 1, secCtrl, isSystemBroadcast))
1089  {
1090  println("decodeSecureApdu: Plain APDU: ");
1091  plainApdu.frame().apdu().printPDU();
1092 
1093  return true;
1094  }
1095 
1096  return false;
1097 }
1098 
1099 bool SecureApplicationLayer::secure(uint8_t* buffer, uint16_t service, uint16_t srcAddr, uint16_t dstAddr, bool dstAddrIsGroupAddr, uint8_t tpci,
1100  uint8_t* apdu, uint16_t apduLength, const SecurityControl& secCtrl, bool systemBcast)
1101 {
1102  bool toolAccess = secCtrl.toolAccess;
1103  bool confidentiality = secCtrl.dataSecurity == DataSecurity::AuthConf;
1104 
1105  if (toolAccess)
1106  {
1107  if (!confidentiality)
1108  {
1109  println("Error: tool access requires auth+conf security");
1110  return false;
1111  }
1112 
1113  if (dstAddrIsGroupAddr && dstAddr != 0)
1114  {
1115  println("Error: tool access requires individual address");
1116  return false;
1117  }
1118  }
1119 
1120  const uint8_t* key = toolAccess ? _secIfObj.toolKey() : securityKey(dstAddr, dstAddrIsGroupAddr);
1121 
1122  if (key == nullptr)
1123  {
1124  print("Error: No key found. toolAccess: ");
1125  println(toolAccess ? "true" : "false");
1126  return false;
1127  }
1128 
1129  bool syncReq = service == kSecureSyncRequest;
1130  bool syncRes = service == kSecureSyncResponse;
1131 
1132  tpci |= SecureService >> 8; // OR'ing upper two APCI bits
1133  uint8_t apci = SecureService & 0x00FF;
1134  uint8_t* pBuf = buffer;
1135  pBuf = pushByte(tpci, pBuf); // TPCI
1136  pBuf = pushByte(apci, pBuf); // APCI
1137 
1138  uint8_t scf;
1139  scf = service;
1140  scf |= toolAccess ? 0x80 : 0;
1141  scf |= confidentiality ? 0x10 : 0;
1142  scf |= systemBcast ? 0x8 : 0;
1143 
1144  pBuf = pushByte(scf, pBuf); // SCF
1145 
1146  uint64_t seqSend = nextSequenceNumber(toolAccess);
1147 
1148  if (seqSend == 0)
1149  println("0 is not a valid sequence number");
1150 
1151  uint8_t seq[6];
1152  sixBytesFromUInt64(seqSend, seq);
1153 
1154  if (!syncRes)
1155  pBuf = pushByteArray(seq, 6, pBuf); // Sequence Number
1156 
1157  // Prepare associated data depending on service (SyncRequest, SyncResponse or just DataService)
1158  uint8_t associatedData[syncReq ? 7 : 1];
1159  associatedData[0] = scf;
1160 
1161  if (syncReq)
1162  {
1163  // TODO: NYI lookup serial number of target device for SBC sync.req
1164  uint8_t remoteSerialNo[6] = {0};
1165 
1166  uint8_t emptySerialNo[6] = {0};
1167  pBuf = pushByteArray(systemBcast ? remoteSerialNo : emptySerialNo, 6, pBuf);
1168  pushByteArray(_deviceObj.propertyData(PID_SERIAL_NUMBER), 6, &associatedData[1]);
1169  }
1170  else if (syncRes)
1171  {
1172  // use random number in SyncResponse
1173  uint64_t randomNumber = getRandomNumber();
1174  sixBytesFromUInt64(randomNumber, seq);
1175 
1176  Addr remote = _syncReqBroadcastIncoming ? (Addr)GrpAddr(0) : (Addr)IndAddr(dstAddr);
1177 
1178  // Get challenge from sync.req
1179  uint64_t* challenge = _pendingIncomingSyncRequests.get(remote);
1180 
1181  if (challenge == nullptr)
1182  {
1183  println("Cannot send sync.res without corresponding sync.req");
1184  return false;
1185  }
1186  else
1187  {
1188  _pendingIncomingSyncRequests.erase(remote);
1189  }
1190 
1191  uint8_t challengeSixBytes[6];
1192  sixBytesFromUInt64(*challenge, challengeSixBytes);
1193  //printHex("Decrypted challenge: ", challengeSixBytes, 6);
1194 
1195  // Now XOR the new random SeqNum with the challenge from the SyncRequest
1196  uint8_t rndXorChallenge[6];
1197  pushByteArray(seq, 6, rndXorChallenge);
1198 
1199  for (uint8_t i = 0; i < sizeof(rndXorChallenge); i++)
1200  {
1201  rndXorChallenge[i] ^= challengeSixBytes[i];
1202  }
1203 
1204  pBuf = pushByteArray(rndXorChallenge, 6, pBuf);
1205  }
1206 
1207  // No LTE-HEE for now
1208  // Data Secure always uses extended frame format with APDU length > 15 octets (long messages), no standard frames
1209  uint8_t extendedFrameFormat = 0;
1210  // Clear IV buffer
1211  uint8_t iv[16] = {0x00};
1212  // Create first block B0 for AES CBC MAC calculation, used as IV later
1213  /*
1214  printHex("seq: ", seq, 6);
1215  printHex("src: ", (uint8_t*) &srcAddr, 2);
1216  printHex("dst: ", (uint8_t*) &dstAddr, 2);
1217  print("dstAddrisGroup: ");println(dstAddrIsGroupAddr ? "true" : "false");
1218  */
1219  block0(iv, seq, srcAddr, dstAddr, dstAddrIsGroupAddr, extendedFrameFormat, tpci, apci, apduLength);
1220 
1221  // Clear block counter0 buffer
1222  uint8_t ctr0[16] = {0x00};
1223  // Create first block for block counter 0
1224  blockCtr0(ctr0, seq, srcAddr, dstAddr);
1225 
1226  if (confidentiality)
1227  {
1228  // Do calculations for Auth+Conf
1229  /*
1230  printHex("APDU--------->", apdu, apduLength);
1231  printHex("Key---------->", key, 16);
1232  printHex("ASSOC-------->", associatedData, sizeof(associatedData));
1233  */
1234  uint32_t mac = calcConfAuthMac(associatedData, sizeof(associatedData), apdu, apduLength, key, iv);
1235 
1236  uint8_t tmpBuffer[4 + apduLength];
1237  pushInt(mac, tmpBuffer);
1238  pushByteArray(apdu, apduLength, &tmpBuffer[4]);
1239 
1240  xcryptAesCtr(tmpBuffer, apduLength + 4, ctr0, key); // APDU + MAC (4 bytes)
1241 
1242  pBuf = pushByteArray(tmpBuffer + 4, apduLength, pBuf); // Encrypted APDU
1243  pBuf = pushByteArray(tmpBuffer + 0, 4, pBuf); // Encrypted MAC
1244 
1245  //print("MAC(encrypted): ");
1246  //println(*((uint32_t*)(tmpBuffer + 0)),HEX);
1247  }
1248  else
1249  {
1250  // Do calculations for AuthOnly
1251  uint32_t tmpMac = calcAuthOnlyMac(apdu, apduLength, key, iv, ctr0);
1252 
1253  pBuf = pushByteArray(apdu, apduLength, pBuf); // Plain APDU
1254  pBuf = pushInt(tmpMac, pBuf); // MAC
1255 
1256  print("MAC: ");
1257  println(tmpMac, HEX);
1258  }
1259 
1260  return true;
1261 }
1262 
1263 bool SecureApplicationLayer::createSecureApdu(APDU& plainApdu, APDU& secureApdu, const SecurityControl& secCtrl)
1264 {
1265  // Create secure APDU
1266 
1267  println("createSecureApdu: Plain APDU: ");
1268  plainApdu.printPDU();
1269 
1270  uint16_t srcAddress = plainApdu.frame().sourceAddress();
1271  uint16_t dstAddress = plainApdu.frame().destinationAddress();
1272  bool isDstAddrGroupAddr = plainApdu.frame().addressType() == GroupAddress;
1273  bool isSystemBroadcast = plainApdu.frame().systemBroadcast();
1274  uint8_t tpci = 0x00;
1275 
1276  if (isConnected())
1277  {
1278  tpci |= 0x40 | _transportLayer->getTpciSeqNum(); // get next TPCI sequence number for MAC calculation from TL (T_DATA_CONNECTED)
1279  }
1280 
1281  print("createSecureApdu: TPCI: ");
1282  println(tpci, HEX);
1283  // Note:
1284  // The TPCI is also included in the MAC calculation to provide authenticity for this field.
1285  // However, a secure APDU (with a MAC) is only included in transport layer PDUs T_DATA_GROUP, T_DATA_TAG_GROUP, T_DATA_INDIVIDUAL, T_DATA_CONNECTED
1286  // and not in T_CONNECT, T_DISCONNECT, T_ACK, T_NACK.
1287  // This means the DATA/CONTROL flag is always 0(=DATA). The flag "NUMBERED" differentiates between T_DATA_INDIVIDUAL and T_DATA_CONNECTED.
1288  // The seqNumber is only used in T_DATA_CONNECTED and 0 in case of T_DATA_GROUP and T_DATA_GROUP (leaving out T_DATA_TAG_GROUP).
1289  // Summary: effectively only the "NUMBERED" flag (bit6) and the SeqNumber (bit5-2) are used from transport layer.
1290  // In T_DATA_* services the bits1-0 of TPCI octet are used as bits9-8 for APCI type which is fixed to 0x03. SecureService APCI is 0x03F1.
1291 
1292  // FIXME: when cEMI class is refactored, there might be additional info fields in cEMI (fixed APDU_LPDU_DIFF)
1293  // We are starting from TPCI octet (including): plainApdu.frame().data()+APDU_LPDU_DIFF
1294  if (secure(secureApdu.frame().data() + APDU_LPDU_DIFF, kSecureDataPdu, srcAddress, dstAddress, isDstAddrGroupAddr, tpci, plainApdu.frame().data() + APDU_LPDU_DIFF, plainApdu.length() + 1, secCtrl, isSystemBroadcast))
1295  {
1296  print("Update our next ");
1297  print(secCtrl.toolAccess ? "tool access" : "");
1298  print(" seq from ");
1299  print(srcAddress, HEX);
1300  print(" -> (+1) ");
1301  println(nextSequenceNumber(secCtrl.toolAccess), HEX);
1302  updateSequenceNumber(secCtrl.toolAccess, nextSequenceNumber(secCtrl.toolAccess) + 1);
1303 
1304  println("createSecureApdu: Secure APDU: ");
1305  secureApdu.frame().apdu().printPDU();
1306 
1307  return true;
1308  }
1309 
1310  return false;
1311 }
1312 
1313 uint64_t SecureApplicationLayer::getRandomNumber()
1314 {
1315  return 0x000102030405; // TODO: generate random number
1316 }
1317 
1319 {
1320  // TODO: handle timeout of outgoing sync requests
1321  //_pendingOutgoingSyncRequests
1322 }
1323 
1324 bool SecureApplicationLayer::isSyncService(APDU& secureApdu)
1325 {
1326  uint8_t scf = *(secureApdu.data() + 1);
1327  uint8_t service = (scf & 0x07); // only 0x0 (S-A_Data-PDU), 0x2 (S-A_Sync_Req-PDU) or 0x3 (S-A_Sync_Rsp-PDU) are valid values
1328 
1329  if ((service == kSecureSyncRequest) || (service == kSecureSyncResponse))
1330  {
1331  return true;
1332  }
1333 
1334  return false;
1335 }
1336 #endif
void AES_CTR_xcrypt_buffer(struct AES_ctx *ctx, uint8_t *buf, uint32_t length)
Definition: aes.c:569
void AES_init_ctx_iv(struct AES_ctx *ctx, const uint8_t *key, const uint8_t *iv)
Definition: aes.c:239
void AES_CBC_encrypt_buffer(struct AES_ctx *ctx, uint8_t *buf, uint32_t length)
Definition: aes.c:529
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
uint8_t * pushInt(uint32_t i, uint8_t *data)
Definition: bits.cpp:72
uint8_t * pushByteArray(const uint8_t *src, uint32_t size, uint8_t *data)
Definition: bits.cpp:82
const uint8_t * popByteArray(uint8_t *dst, uint32_t size, const uint8_t *data)
Definition: bits.cpp:48
void sixBytesFromUInt64(uint64_t num, uint8_t *toByteArray)
Definition: bits.cpp:101
uint8_t * pushWord(uint16_t w, uint8_t *data)
Definition: bits.cpp:64
uint8_t * pushByte(uint8_t b, uint8_t *data)
Definition: bits.cpp:57
const uint8_t * popInt(uint32_t &i, const uint8_t *data)
Definition: bits.cpp:41
uint64_t sixBytesToUInt64(uint8_t *data)
Definition: bits.cpp:111
uint32_t millis()
This class represents an Application Protocol Data Unit.
Definition: apdu.h:12
void printPDU()
Print the contents of the APDU to console.
Definition: apdu.cpp:43
ApduType type()
Get the type of the APDU.
Definition: apdu.cpp:9
uint8_t * data()
Get a pointer to the data.
Definition: apdu.cpp:28
uint8_t length() const
Get the length of the APDU.
Definition: apdu.cpp:38
CemiFrame & frame()
Get the CemiFrame this APDU is part of.
Definition: apdu.cpp:33
This class represents the group address table.
uint16_t getGroupAddress(uint16_t tsap)
Get the group address mapped to a TSAP.
uint16_t getTsap(uint16_t groupAddress)
Get the TSAP mapped to a group address.
This is an implementation of the application layer as specified in .
virtual void dataSystemBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU &apdu)
virtual void dataConnectedRequest(uint16_t tsap, Priority priority, APDU &apdu, const SecurityControl &secCtrl)
virtual void dataIndividualRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t destination, APDU &apdu, const SecurityControl &secCtrl)
virtual void dataBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU &apdu)
TransportLayer * _transportLayer
virtual void dataGroupRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU &apdu, const SecurityControl &secCtrl)
virtual void dataConnectedIndication(Priority priority, uint16_t tsap, APDU &apdu)
virtual void dataGroupConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU &apdu, bool status)
Report the status of an APDU that we sent via multicast communication back to us.
virtual void dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU &apdu, const SecurityControl &secCtrl)
virtual void dataSystemBroadcastConfirm(HopCountType hopType, Priority priority, APDU &apdu, bool status)
virtual void dataIndividualConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU &apdu, bool status)
virtual void dataBroadcastConfirm(AckType ack, HopCountType hopType, Priority priority, APDU &apdu, bool status)
virtual void dataGroupIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU &apdu)
Somebody send us an APDU via multicast communication.
uint16_t getConnectedTsasp()
virtual void dataConnectedConfirm(uint16_t tsap)
virtual void dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU &apdu, const SecurityControl &secCtrl)
virtual void dataIndividualIndication(HopCountType hopType, Priority priority, uint16_t source, APDU &apdu)
SystemBroadcast systemBroadcast() const
Definition: cemi_frame.cpp:237
uint16_t sourceAddress() const
Definition: cemi_frame.cpp:303
uint8_t * data()
Definition: cemi_frame.cpp:195
APDU & apdu()
Definition: cemi_frame.cpp:367
uint16_t destinationAddress() const
Definition: cemi_frame.cpp:315
AddressType addressType() const
Definition: cemi_frame.cpp:281
uint16_t individualAddress()
const uint8_t * propertyData(PropertyID id)
bool insertOrAssign(K key, V value)
Definition: simple_map.h:59
bool erase(K key)
Definition: simple_map.h:80
V * get(K key)
Definition: simple_map.h:97
void dataConnectedRequest(uint16_t tsap, Priority priority, APDU &apdu, const SecurityControl &secCtrl) override
void dataGroupRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU &apdu, const SecurityControl &secCtrl) override
void dataIndividualConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU &apdu, bool status) override
void dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU &apdu, const SecurityControl &secCtrl) override
void dataGroupIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU &apdu) override
Somebody send us an APDU via multicast communication.
void dataSystemBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU &apdu) override
void dataConnectedIndication(Priority priority, uint16_t tsap, APDU &apdu) override
void dataConnectedConfirm(uint16_t tsap) override
void dataSystemBroadcastConfirm(HopCountType hopType, Priority priority, APDU &apdu, bool status) override
SecureApplicationLayer(DeviceObject &deviceObj, SecurityInterfaceObject &secIfObj, BusAccessUnit &bau)
The constructor.
void groupAddressTable(AddressTableObject &addrTable)
void dataGroupConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU &apdu, bool status) override
Report the status of an APDU that we sent via multicast communication back to us.
void dataBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU &apdu) override
void dataIndividualIndication(HopCountType hopType, Priority priority, uint16_t source, APDU &apdu) override
void dataIndividualRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t destination, APDU &apdu, const SecurityControl &secCtrl) override
void dataBroadcastConfirm(AckType ack, HopCountType hopType, Priority priority, APDU &apdu, bool status) override
void dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU &apdu, const SecurityControl &secCtrl) override
const uint8_t * groupKey(uint16_t addressIndex)
uint64_t getLastValidSequenceNumber(uint16_t deviceAddr)
void setLastValidSequenceNumber(uint16_t deviceAddr, uint64_t seqNum)
void setSequenceNumber(bool toolAccess, uint64_t seqNum)
const uint8_t * p2pKey(uint16_t addressIndex)
uint16_t indAddressIndex(uint16_t indAddr)
void dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU &apdu)
void dataConnectedRequest(uint16_t tsap, Priority priority, APDU &apdu)
void dataIndividualRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t destination, APDU &apdu)
uint16_t getConnectionAddress()
uint8_t getTpciSeqNum()
HopCountType
Definition: knx_types.h:124
@ NetworkLayerParameter
use NetworkLayer::hopCount as NPDU::hopCount
Definition: knx_types.h:126
Priority
Definition: knx_types.h:10
@ SystemPriority
Mainly used by ETS for device programming.
Definition: knx_types.h:14
@ SecureService
Definition: knx_types.h:219
AckType
Definition: knx_types.h:18
@ AckDontCare
We don't care about DataLinkLayer acknowledgement.
Definition: knx_types.h:19
@ GroupAddress
Definition: knx_types.h:35
@ IndividualAddress
Definition: knx_types.h:34
@ AuthConf
Definition: knx_types.h:226
@ Auth
Definition: knx_types.h:225
@ None
Definition: knx_types.h:224
@ Broadcast
Definition: knx_types.h:114
@ SysBroadcast
Definition: knx_types.h:113
@ PID_SERIAL_NUMBER
Definition: property.h:78
Definition: aes.h:44
DataSecurity dataSecurity
Definition: knx_types.h:232