mirror of
				https://github.com/thelsing/knx.git
				synced 2025-10-26 10:26:25 +01:00 
			
		
		
		
	save work
This commit is contained in:
		
							parent
							
								
									9cee6c8bc5
								
							
						
					
					
						commit
						eb11180858
					
				@ -149,6 +149,8 @@ class ApplicationLayer
 | 
			
		||||
    virtual void dataIndividualRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t destination, APDU& apdu);
 | 
			
		||||
    virtual void dataConnectedRequest(uint16_t tsap, Priority priority, APDU& apdu); // apdu must be valid until it was confirmed
 | 
			
		||||
 | 
			
		||||
    uint16_t getConnectedTsasp() {return _connectedTsap;}
 | 
			
		||||
 | 
			
		||||
    // Protected: we need to access it in derived class SecureApplicationLayer
 | 
			
		||||
    TransportLayer* _transportLayer = 0;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -39,6 +39,9 @@ void BauSystemB::loop()
 | 
			
		||||
    _transLayer.loop();
 | 
			
		||||
    sendNextGroupTelegram();
 | 
			
		||||
    nextRestartState();
 | 
			
		||||
#ifdef USE_DATASECURE
 | 
			
		||||
    _appLayer.loop();
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool BauSystemB::enabled()
 | 
			
		||||
 | 
			
		||||
@ -25,7 +25,6 @@ uint64_t sequenceNumber = 0;
 | 
			
		||||
uint64_t lastValidSequenceNumberTool = 0;
 | 
			
		||||
uint64_t lastValidSequenceNumber = 0;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
SecureApplicationLayer::SecureApplicationLayer(DeviceObject &deviceObj, SecurityInterfaceObject &secIfObj, AssociationTableObject& assocTable, BusAccessUnit& bau):
 | 
			
		||||
    ApplicationLayer(assocTable, bau),
 | 
			
		||||
    _secIfObj(secIfObj),
 | 
			
		||||
@ -244,7 +243,7 @@ void SecureApplicationLayer::dataConnectedConfirm(uint16_t tsap)
 | 
			
		||||
void SecureApplicationLayer::dataGroupRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu)
 | 
			
		||||
{
 | 
			
		||||
    // TODO:
 | 
			
		||||
    // get flags for this TSAP from PID_GO_SECURITY_FLAGS from SecIntObj
 | 
			
		||||
    // get flags auth and confidentiality for this TSAP from PID_GO_SECURITY_FLAGS from SecIntObj
 | 
			
		||||
    bool needsEncryption = false;
 | 
			
		||||
 | 
			
		||||
    if (needsEncryption)
 | 
			
		||||
@ -265,7 +264,6 @@ void SecureApplicationLayer::dataGroupRequest(AckType ack, HopCountType hopType,
 | 
			
		||||
void SecureApplicationLayer::dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu)
 | 
			
		||||
{
 | 
			
		||||
    // TODO:
 | 
			
		||||
    // get flags for this TSAP from PID_GO_SECURITY_FLAGS from SecIntObj
 | 
			
		||||
    bool needsEncryption = true;
 | 
			
		||||
 | 
			
		||||
    if (needsEncryption)
 | 
			
		||||
@ -286,7 +284,6 @@ void SecureApplicationLayer::dataBroadcastRequest(AckType ack, HopCountType hopT
 | 
			
		||||
void SecureApplicationLayer::dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu)
 | 
			
		||||
{
 | 
			
		||||
    // TODO:
 | 
			
		||||
    // get flags for this TSAP from PID_GO_SECURITY_FLAGS from SecIntObj
 | 
			
		||||
    bool needsEncryption = true;
 | 
			
		||||
 | 
			
		||||
    if (needsEncryption)
 | 
			
		||||
@ -307,7 +304,6 @@ void SecureApplicationLayer::dataSystemBroadcastRequest(AckType ack, HopCountTyp
 | 
			
		||||
void SecureApplicationLayer::dataIndividualRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t destination, APDU& apdu)
 | 
			
		||||
{
 | 
			
		||||
    // TODO:
 | 
			
		||||
    // get flags for this TSAP from PID_GO_SECURITY_FLAGS from SecIntObj
 | 
			
		||||
    bool needsEncryption = true;
 | 
			
		||||
 | 
			
		||||
    if (needsEncryption)
 | 
			
		||||
@ -328,7 +324,6 @@ void SecureApplicationLayer::dataIndividualRequest(AckType ack, HopCountType hop
 | 
			
		||||
void SecureApplicationLayer::dataConnectedRequest(uint16_t tsap, Priority priority, APDU& apdu)
 | 
			
		||||
{
 | 
			
		||||
    // TODO:
 | 
			
		||||
    // get flags for this TSAP from PID_GO_SECURITY_FLAGS from SecIntObj
 | 
			
		||||
    bool needsEncryption = true;
 | 
			
		||||
 | 
			
		||||
    if (needsEncryption)
 | 
			
		||||
@ -594,6 +589,55 @@ void SecureApplicationLayer::updateLastValidSequence(bool toolAccess, uint16_t r
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SecureApplicationLayer::sendSyncRequest(uint16_t dstAddr, bool dstAddrIsGroupAddr, bool toolAccess)
 | 
			
		||||
{
 | 
			
		||||
    _syncReqBroadcastOutgoing = (dstAddr == 0x0000) && dstAddrIsGroupAddr;
 | 
			
		||||
 | 
			
		||||
    // use random number in SyncResponse
 | 
			
		||||
    uint64_t challenge = getRandomNumber();
 | 
			
		||||
 | 
			
		||||
    uint8_t asdu[6];
 | 
			
		||||
    sixBytesFromUInt64(challenge, &asdu[0]);
 | 
			
		||||
 | 
			
		||||
    CemiFrame request(2 + 6 + sizeof(asdu) + 4); // 2 bytes (APCI, SCF) + 6 bytes (SeqNum) + 6 bytes (challenge) + 4 bytes (MAC)
 | 
			
		||||
                                                      // Note: additional TPCI byte is already handled internally!
 | 
			
		||||
 | 
			
		||||
    uint8_t tpci = 0;
 | 
			
		||||
    if (!_syncReqBroadcastOutgoing)
 | 
			
		||||
    {
 | 
			
		||||
        tpci = _transportLayer->getTPCI(dstAddr); // get next TPCI sequence number for MAC calculation from TL
 | 
			
		||||
    }
 | 
			
		||||
    print("sendSyncRequest: TPCI: ");
 | 
			
		||||
    println(tpci, HEX);
 | 
			
		||||
 | 
			
		||||
    if(secure(request.data() + APDU_LPDU_DIFF, SecureSyncRequest, _deviceObj.induvidualAddress(), dstAddr, dstAddrIsGroupAddr, tpci, asdu, sizeof(asdu), toolAccess, true))
 | 
			
		||||
    {
 | 
			
		||||
        println("SyncRequest: ");
 | 
			
		||||
        request.apdu().printPDU();
 | 
			
		||||
 | 
			
		||||
        if (_syncReqBroadcastOutgoing)
 | 
			
		||||
        {
 | 
			
		||||
            _transportLayer->dataBroadcastRequest(AckType::AckDontCare, HopCountType::NetworkLayerParameter, Priority::SystemPriority, request.apdu());
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            // either send on T_DATA_INDIVIDUAL or T_DATA_CONNECTED
 | 
			
		||||
            if (isConnected())
 | 
			
		||||
            {
 | 
			
		||||
                _transportLayer->dataConnectedRequest(getConnectedTsasp(), SystemPriority, request.apdu());
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                // Send encrypted SyncResponse message using T_DATA_INDIVIDUAL
 | 
			
		||||
                _transportLayer->dataIndividualRequest(AckType::AckDontCare, NetworkLayerParameter, SystemPriority, dstAddr, request.apdu());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Addr toAddr = _syncReqBroadcastOutgoing ? (Addr)GrpAddr(0) : (Addr)IndAddr(dstAddr);
 | 
			
		||||
        _pendingOutgoingSyncRequests.insertOrAssign(toAddr, challenge);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SecureApplicationLayer::sendSyncResponse(uint16_t dstAddr, bool dstAddrIsGroupAddr, bool toolAccess, uint64_t remoteNextSeqNum)
 | 
			
		||||
{
 | 
			
		||||
    uint64_t ourNextSeqNum = nextSequenceNumber(toolAccess);
 | 
			
		||||
@ -606,7 +650,7 @@ void SecureApplicationLayer::sendSyncResponse(uint16_t dstAddr, bool dstAddrIsGr
 | 
			
		||||
                                                      // Note: additional TPCI byte is already handled internally!
 | 
			
		||||
 | 
			
		||||
    uint8_t tpci = 0;
 | 
			
		||||
    if (!_syncReqBroadcast)
 | 
			
		||||
    if (!_syncReqBroadcastIncoming)
 | 
			
		||||
    {
 | 
			
		||||
        tpci = _transportLayer->getTPCI(dstAddr); // get next TPCI sequence number for MAC calculation from TL
 | 
			
		||||
    }
 | 
			
		||||
@ -620,16 +664,22 @@ void SecureApplicationLayer::sendSyncResponse(uint16_t dstAddr, bool dstAddrIsGr
 | 
			
		||||
        println("SyncResponse: ");
 | 
			
		||||
        response.apdu().printPDU();
 | 
			
		||||
 | 
			
		||||
        if (_syncReqBroadcast)
 | 
			
		||||
        if (_syncReqBroadcastIncoming)
 | 
			
		||||
        {
 | 
			
		||||
            _transportLayer->dataBroadcastRequest(AckType::AckDontCare, HopCountType::NetworkLayerParameter, Priority::SystemPriority, response.apdu());
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            //TODO: either send on T_DATA_INDIVIDUAL or T_DATA_CONNECTED depending on reception
 | 
			
		||||
 | 
			
		||||
            // Send encrypted SyncResponse message using T_DATA_INDIVIDUAL
 | 
			
		||||
            _transportLayer->dataIndividualRequest(AckType::AckDontCare, NetworkLayerParameter, SystemPriority, dstAddr, response.apdu());
 | 
			
		||||
            // either send on T_DATA_INDIVIDUAL or T_DATA_CONNECTED
 | 
			
		||||
            if (isConnected())
 | 
			
		||||
            {
 | 
			
		||||
                _transportLayer->dataConnectedRequest(getConnectedTsasp(), SystemPriority, response.apdu());
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                // Send encrypted SyncResponse message using T_DATA_INDIVIDUAL
 | 
			
		||||
                _transportLayer->dataIndividualRequest(AckType::AckDontCare, NetworkLayerParameter, SystemPriority, dstAddr, response.apdu());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -646,29 +696,34 @@ void SecureApplicationLayer::receivedSyncRequest(uint16_t srcAddr, uint16_t dstA
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Remember challenge for securing the sync.res later
 | 
			
		||||
    //stashSyncRequest(srcAddr, challenge); // TODO: save challenge in a map to handle multiple requests
 | 
			
		||||
    sixBytesFromUInt64(challenge, _challenge);
 | 
			
		||||
    _pendingIncomingSyncRequests.insertOrAssign(IndAddr(srcAddr), challenge);
 | 
			
		||||
 | 
			
		||||
    _syncReqBroadcast = (dstAddr == 0x0000) && dstAddrIsGroupAddr;
 | 
			
		||||
    _syncReqBroadcastIncoming = (dstAddr == 0x0000) && dstAddrIsGroupAddr;
 | 
			
		||||
 | 
			
		||||
    uint16_t toAddr = _syncReqBroadcast ? dstAddr : srcAddr;
 | 
			
		||||
    bool toIsGroupAddress = _syncReqBroadcast;
 | 
			
		||||
 | 
			
		||||
    _challengeSrcAddr = toAddr;
 | 
			
		||||
    _isChallengeValid = true;
 | 
			
		||||
    uint16_t toAddr = _syncReqBroadcastIncoming ? dstAddr : srcAddr;
 | 
			
		||||
    bool toIsGroupAddress = _syncReqBroadcastIncoming;
 | 
			
		||||
 | 
			
		||||
    sendSyncResponse(toAddr, toIsGroupAddress, toolAccess, nextSeqNum);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SecureApplicationLayer::receivedSyncResponse(uint16_t remoteAddr, bool toolAccess, uint8_t* plainApdu)
 | 
			
		||||
{
 | 
			
		||||
//    final var request = pendingSyncRequests.get(remote);
 | 
			
		||||
//    if (request == null)
 | 
			
		||||
//        return;
 | 
			
		||||
    if (_challengeSrcAddr != remoteAddr)
 | 
			
		||||
    // TODO: check if _syncReqBroadcastOutgoing is true
 | 
			
		||||
    if (_syncReqBroadcastOutgoing)
 | 
			
		||||
    {
 | 
			
		||||
        println("receivedSyncResponse(): Did not find matching challenge for remoteAddr!");
 | 
			
		||||
        return;
 | 
			
		||||
        if (_pendingOutgoingSyncRequests.get(GrpAddr(0)) == nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            println("Cannot handle sync.res without pending sync.req! (broadcast)");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        if (_pendingOutgoingSyncRequests.get(IndAddr(remoteAddr)) == nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            println("Cannot handle sync.res without pending sync.req!");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Bytes 0-5 in the "APDU" buffer contain the remote sequence number
 | 
			
		||||
@ -689,7 +744,7 @@ void SecureApplicationLayer::receivedSyncResponse(uint16_t remoteAddr, bool tool
 | 
			
		||||
        updateSequenceNumber(toolAccess, localSeq);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //syncRequestCompleted(request);
 | 
			
		||||
    _pendingOutgoingSyncRequests.erase(IndAddr(remoteAddr));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool SecureApplicationLayer::decrypt(uint8_t* plainApdu, uint16_t plainApduLength, uint16_t srcAddr, uint16_t dstAddr, bool dstAddrIsGroupAddr, uint8_t tpci, uint8_t* secureAsdu)
 | 
			
		||||
@ -762,21 +817,21 @@ bool SecureApplicationLayer::decrypt(uint8_t* plainApdu, uint16_t plainApduLengt
 | 
			
		||||
    }
 | 
			
		||||
    else if (syncRes)
 | 
			
		||||
    {
 | 
			
		||||
        // TODO: fetch challenge depending on srcAddr to handle multiple requests (would use std::unordered_map normally)
 | 
			
		||||
        //final var request = pendingSyncRequests.get(src);
 | 
			
		||||
        //if (request == null)
 | 
			
		||||
        //    return null;
 | 
			
		||||
        if (_challengeSrcAddr != srcAddr)
 | 
			
		||||
        // fetch challenge depending on srcAddr to handle multiple requests
 | 
			
		||||
        uint64_t *challenge = _pendingOutgoingSyncRequests.get(IndAddr(srcAddr));
 | 
			
		||||
        if (challenge == nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            println("Did not find matching challenge for source address!");
 | 
			
		||||
            println("Cannot find matching challenge for source address!");
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        uint8_t _challengeSixBytes[6];
 | 
			
		||||
        sixBytesFromUInt64(*challenge, _challengeSixBytes);
 | 
			
		||||
        // in a sync.res, seq actually contains our challenge from sync.req xored with a random value
 | 
			
		||||
        // extract the random value and store it in seqNum to use it for block0 and ctr0
 | 
			
		||||
        for (uint8_t i = 0; i < sizeof(seqNum); i++)
 | 
			
		||||
        {
 | 
			
		||||
            seqNum[i] ^= _challenge[i];
 | 
			
		||||
            seqNum[i] ^= _challengeSixBytes[i];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -946,7 +1001,7 @@ bool SecureApplicationLayer::secure(uint8_t* buffer, uint16_t service, uint16_t
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const uint8_t* key = toolAccess ? toolKey(_syncReqBroadcast ? _deviceObj.induvidualAddress() : dstAddr) : securityKey(dstAddr, dstAddrIsGroupAddr);
 | 
			
		||||
    const uint8_t* key = toolAccess ? toolKey(_syncReqBroadcastIncoming ? _deviceObj.induvidualAddress() : dstAddr) : securityKey(dstAddr, dstAddrIsGroupAddr);
 | 
			
		||||
    if (key == nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        print("Error: No key found. toolAccess: ");
 | 
			
		||||
@ -997,32 +1052,30 @@ bool SecureApplicationLayer::secure(uint8_t* buffer, uint16_t service, uint16_t
 | 
			
		||||
    else if (syncRes)
 | 
			
		||||
    {
 | 
			
		||||
        // use random number in SyncResponse
 | 
			
		||||
        uint64_t randomNumber = 0x000102030405; // TODO: generate random number
 | 
			
		||||
        uint64_t randomNumber = getRandomNumber();
 | 
			
		||||
        sixBytesFromUInt64(randomNumber, seq);
 | 
			
		||||
 | 
			
		||||
        // TODO: maybe implement something like std::map for pending SyncRequests?
 | 
			
		||||
        //final var request = pendingSyncRequests.remove(dst);
 | 
			
		||||
        //if (request == null)
 | 
			
		||||
        //    throw new KnxSecureException("sending sync.res without corresponding .req");
 | 
			
		||||
        if (_isChallengeValid && (_challengeSrcAddr == dstAddr))
 | 
			
		||||
        // Get challenge from sync.req
 | 
			
		||||
        uint64_t *challenge = _pendingIncomingSyncRequests.get(IndAddr(dstAddr));
 | 
			
		||||
        if (challenge == nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            // Invalidate _challengeSrcAddr
 | 
			
		||||
            _challengeSrcAddr = 0;
 | 
			
		||||
            _isChallengeValid = false;
 | 
			
		||||
            println("Cannot send sync.res without corresponding sync.req");
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            println("sending sync.res without corresponding .req");
 | 
			
		||||
            _pendingIncomingSyncRequests.erase(IndAddr(dstAddr));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //printHex("Decrypted challenge: ", _challenge, 6);
 | 
			
		||||
        uint8_t challengeSixBytes[6];
 | 
			
		||||
        sixBytesFromUInt64(*challenge, challengeSixBytes);
 | 
			
		||||
        //printHex("Decrypted challenge: ", challengeSixBytes, 6);
 | 
			
		||||
 | 
			
		||||
        // Now XOR the new random SeqNum with the challenge from the SyncRequest
 | 
			
		||||
        uint8_t rndXorChallenge[6];
 | 
			
		||||
        pushByteArray(seq, 6, rndXorChallenge);
 | 
			
		||||
        for (uint8_t i = 0; i < sizeof(rndXorChallenge); i++)
 | 
			
		||||
        {
 | 
			
		||||
            rndXorChallenge[i] ^= _challenge[i];
 | 
			
		||||
            rndXorChallenge[i] ^= challengeSixBytes[i];
 | 
			
		||||
        }
 | 
			
		||||
        pBuf = pushByteArray(rndXorChallenge, 6, pBuf);
 | 
			
		||||
    }
 | 
			
		||||
@ -1130,3 +1183,14 @@ uint8_t SecureApplicationLayer::getFromFailureLogByIndex(uint8_t index, uint8_t*
 | 
			
		||||
    println(index);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint64_t SecureApplicationLayer::getRandomNumber()
 | 
			
		||||
{
 | 
			
		||||
    return 0x000102030405; // TODO: generate random number
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SecureApplicationLayer::loop()
 | 
			
		||||
{
 | 
			
		||||
    // TODO: handle timeout of outgoing sync requests
 | 
			
		||||
    //_pendingOutgoingSyncRequests
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,7 @@
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include "knx_types.h"
 | 
			
		||||
#include "apdu.h"
 | 
			
		||||
#include "bits.h"
 | 
			
		||||
 | 
			
		||||
class DeviceObject;
 | 
			
		||||
class SecurityInterfaceObject;
 | 
			
		||||
@ -18,6 +19,46 @@ class BusAccessUnit;
 | 
			
		||||
 */
 | 
			
		||||
class SecureApplicationLayer :  public ApplicationLayer
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
  public:
 | 
			
		||||
    /**
 | 
			
		||||
     * The constructor.
 | 
			
		||||
     * @param assocTable The AssociationTable is used to translate between asap (i.e. group objects) and group addresses.
 | 
			
		||||
     * @param bau methods are called here depending of the content of the APDU
 | 
			
		||||
     */
 | 
			
		||||
    SecureApplicationLayer(DeviceObject& deviceObj, SecurityInterfaceObject& secIfObj, AssociationTableObject& assocTable, BusAccessUnit& bau);
 | 
			
		||||
 | 
			
		||||
    void setSecurityMode(bool enabled);
 | 
			
		||||
    bool isSecurityModeEnabled();
 | 
			
		||||
    void clearFailureLog();
 | 
			
		||||
    void getFailureCounters(uint8_t* data);
 | 
			
		||||
    uint8_t getFromFailureLogByIndex(uint8_t index, uint8_t* data, uint8_t maxDataLen);
 | 
			
		||||
 | 
			
		||||
    // from transport layer
 | 
			
		||||
    virtual void dataGroupIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu) override;
 | 
			
		||||
    virtual void dataGroupConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap,
 | 
			
		||||
                                  APDU& apdu, bool status) override;
 | 
			
		||||
    virtual void dataBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu) override;
 | 
			
		||||
    virtual void dataBroadcastConfirm(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, bool status) override;
 | 
			
		||||
    virtual void dataSystemBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu) override;
 | 
			
		||||
    virtual void dataSystemBroadcastConfirm(HopCountType hopType, Priority priority, APDU& apdu, bool status) override;
 | 
			
		||||
    virtual void dataIndividualIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu) override;
 | 
			
		||||
    virtual void dataIndividualConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, bool status) override;
 | 
			
		||||
    virtual void dataConnectedIndication(Priority priority, uint16_t tsap, APDU& apdu) override;
 | 
			
		||||
    virtual void dataConnectedConfirm(uint16_t tsap) override;
 | 
			
		||||
 | 
			
		||||
    void loop();
 | 
			
		||||
 | 
			
		||||
  protected:
 | 
			
		||||
    // to transport layer
 | 
			
		||||
    virtual void dataGroupRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu) override;
 | 
			
		||||
    virtual void dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu) override;
 | 
			
		||||
    virtual void dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu) override;
 | 
			
		||||
    virtual void dataIndividualRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t destination, APDU& apdu) override;
 | 
			
		||||
    virtual void dataConnectedRequest(uint16_t tsap, Priority priority, APDU& apdu) override; // apdu must be valid until it was confirmed
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
 | 
			
		||||
    template <typename K, typename V, int SIZE>
 | 
			
		||||
    class Map
 | 
			
		||||
    {
 | 
			
		||||
@ -27,11 +68,6 @@ class SecureApplicationLayer :  public ApplicationLayer
 | 
			
		||||
            static_assert (SIZE <= 64, "Map is too big! Max. 64 elements.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void setInvalidValue(V value)
 | 
			
		||||
        {
 | 
			
		||||
            _invalidValue = value;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void clear()
 | 
			
		||||
        {
 | 
			
		||||
            _validEntries = 0;
 | 
			
		||||
@ -107,7 +143,7 @@ class SecureApplicationLayer :  public ApplicationLayer
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        V operator[](K key) const
 | 
			
		||||
        V* get(K key)
 | 
			
		||||
        {
 | 
			
		||||
            // Try to find the key
 | 
			
		||||
            for (uint8_t i = 0; i < SIZE; i++)
 | 
			
		||||
@ -118,38 +154,11 @@ class SecureApplicationLayer :  public ApplicationLayer
 | 
			
		||||
                    // Key found?
 | 
			
		||||
                    if (keys[i] == key)
 | 
			
		||||
                    {
 | 
			
		||||
                        return values[i];
 | 
			
		||||
                        return &values[i];
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return _invalidValue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        V &operator[](K key)
 | 
			
		||||
        {
 | 
			
		||||
            // Try to find the key
 | 
			
		||||
            for (uint8_t i = 0; i < SIZE; i++)
 | 
			
		||||
            {
 | 
			
		||||
                // Check if this array slot is occupied
 | 
			
		||||
                if ((_validEntries >> i) & 0x01)
 | 
			
		||||
                {
 | 
			
		||||
                    // Key found?
 | 
			
		||||
                    if (keys[i] == key)
 | 
			
		||||
                    {
 | 
			
		||||
                        return values[i];
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Key was not found, so add key and value
 | 
			
		||||
            uint8_t index = getNextFreeIndex();
 | 
			
		||||
            if (index != noFreeEntryFoundIndex)
 | 
			
		||||
            {
 | 
			
		||||
                _validEntries |= 1 << index;
 | 
			
		||||
                keys[index] = key;
 | 
			
		||||
                return values[index];
 | 
			
		||||
            }
 | 
			
		||||
            return _invalidValue;
 | 
			
		||||
            return nullptr;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
@ -170,45 +179,15 @@ class SecureApplicationLayer :  public ApplicationLayer
 | 
			
		||||
        K keys[SIZE];
 | 
			
		||||
        V values[SIZE];
 | 
			
		||||
        static constexpr uint8_t noFreeEntryFoundIndex = 255;
 | 
			
		||||
        V _invalidValue;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
  public:
 | 
			
		||||
    /**
 | 
			
		||||
     * The constructor.
 | 
			
		||||
     * @param assocTable The AssociationTable is used to translate between asap (i.e. group objects) and group addresses.
 | 
			
		||||
     * @param bau methods are called here depending of the content of the APDU
 | 
			
		||||
     */
 | 
			
		||||
    SecureApplicationLayer(DeviceObject& deviceObj, SecurityInterfaceObject& secIfObj, AssociationTableObject& assocTable, BusAccessUnit& bau);
 | 
			
		||||
    enum class AddrType : uint8_t
 | 
			
		||||
    {
 | 
			
		||||
        group,
 | 
			
		||||
        individual,
 | 
			
		||||
        unknown
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    void setSecurityMode(bool enabled);
 | 
			
		||||
    bool isSecurityModeEnabled();
 | 
			
		||||
    void clearFailureLog();
 | 
			
		||||
    void getFailureCounters(uint8_t* data);
 | 
			
		||||
    uint8_t getFromFailureLogByIndex(uint8_t index, uint8_t* data, uint8_t maxDataLen);
 | 
			
		||||
 | 
			
		||||
    // from transport layer
 | 
			
		||||
    virtual void dataGroupIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu) override;
 | 
			
		||||
    virtual void dataGroupConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap,
 | 
			
		||||
                                  APDU& apdu, bool status) override;
 | 
			
		||||
    virtual void dataBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu) override;
 | 
			
		||||
    virtual void dataBroadcastConfirm(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, bool status) override;
 | 
			
		||||
    virtual void dataSystemBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu) override;
 | 
			
		||||
    virtual void dataSystemBroadcastConfirm(HopCountType hopType, Priority priority, APDU& apdu, bool status) override;
 | 
			
		||||
    virtual void dataIndividualIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu) override;
 | 
			
		||||
    virtual void dataIndividualConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, bool status) override;
 | 
			
		||||
    virtual void dataConnectedIndication(Priority priority, uint16_t tsap, APDU& apdu) override;
 | 
			
		||||
    virtual void dataConnectedConfirm(uint16_t tsap) override;
 | 
			
		||||
 | 
			
		||||
  protected:
 | 
			
		||||
    // to transport layer
 | 
			
		||||
    virtual void dataGroupRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu) override;
 | 
			
		||||
    virtual void dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu) override;
 | 
			
		||||
    virtual void dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu) override;
 | 
			
		||||
    virtual void dataIndividualRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t destination, APDU& apdu) override;
 | 
			
		||||
    virtual void dataConnectedRequest(uint16_t tsap, Priority priority, APDU& apdu) override; // apdu must be valid until it was confirmed
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
    enum class DataSecurity
 | 
			
		||||
    {
 | 
			
		||||
        none,
 | 
			
		||||
@ -216,6 +195,37 @@ class SecureApplicationLayer :  public ApplicationLayer
 | 
			
		||||
        authConf
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct Addr
 | 
			
		||||
    {
 | 
			
		||||
        Addr() = default;
 | 
			
		||||
        Addr(uint8_t addr) : addr{addr} {}
 | 
			
		||||
 | 
			
		||||
        uint16_t addr;
 | 
			
		||||
        AddrType addrType{AddrType::unknown};
 | 
			
		||||
 | 
			
		||||
        bool operator ==(const Addr &cmpAddr) const
 | 
			
		||||
        {
 | 
			
		||||
            if ((cmpAddr.addrType == AddrType::unknown) || (addrType == AddrType::unknown))
 | 
			
		||||
            {
 | 
			
		||||
                println("Unknown address type detected!");
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            return (cmpAddr.addr == addr) && (cmpAddr.addrType == addrType);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct GrpAddr : Addr
 | 
			
		||||
    {
 | 
			
		||||
        GrpAddr() {addrType = AddrType::group;}
 | 
			
		||||
        GrpAddr(uint8_t addr) : Addr{addr} {addrType = AddrType::group;}
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct IndAddr : Addr
 | 
			
		||||
    {
 | 
			
		||||
        IndAddr() { addrType = AddrType::individual; }
 | 
			
		||||
        IndAddr(uint8_t addr) : Addr{addr} { addrType = AddrType::individual; }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct SecurityControl
 | 
			
		||||
    {
 | 
			
		||||
        bool toolAccess;
 | 
			
		||||
@ -248,6 +258,9 @@ class SecureApplicationLayer :  public ApplicationLayer
 | 
			
		||||
    uint64_t lastValidSequenceNumber(bool toolAcces, uint16_t srcAddr);
 | 
			
		||||
    void updateLastValidSequence(bool toolAccess, uint16_t remoteAddr, uint64_t seqNo);
 | 
			
		||||
 | 
			
		||||
    uint64_t getRandomNumber();
 | 
			
		||||
 | 
			
		||||
    void sendSyncRequest(uint16_t dstAddr, bool dstAddrIsGroupAddr, bool toolAccess);
 | 
			
		||||
    void sendSyncResponse(uint16_t dstAddr, bool dstAddrIsGroupAddr, bool toolAccess, uint64_t remoteNextSeqNum);
 | 
			
		||||
    void receivedSyncRequest(uint16_t srcAddr, uint16_t dstAddr, bool dstAddrIsGroupAddr, bool toolAccess, uint8_t* seq, uint64_t challenge);
 | 
			
		||||
    void receivedSyncResponse(uint16_t remoteAddr, bool toolAccess, uint8_t* plainApdu);
 | 
			
		||||
@ -263,13 +276,13 @@ class SecureApplicationLayer :  public ApplicationLayer
 | 
			
		||||
 | 
			
		||||
    bool _securityModeEnabled {false};
 | 
			
		||||
 | 
			
		||||
    bool _syncReqBroadcast;
 | 
			
		||||
    bool _syncReqBroadcastIncoming{false};
 | 
			
		||||
    bool _syncReqBroadcastOutgoing{false};
 | 
			
		||||
    uint32_t _lastSyncRes;
 | 
			
		||||
    uint8_t _challenge[6];
 | 
			
		||||
    uint16_t _challengeSrcAddr;
 | 
			
		||||
    bool _isChallengeValid {false};
 | 
			
		||||
 | 
			
		||||
    Map<uint16_t, SecurityControl, 8> _pendingRequests;
 | 
			
		||||
    Map<Addr, SecurityControl, 1> _pendingDataRequests;
 | 
			
		||||
    Map<Addr, uint64_t, 1> _pendingOutgoingSyncRequests;
 | 
			
		||||
    Map<Addr, uint64_t, 1> _pendingIncomingSyncRequests;
 | 
			
		||||
 | 
			
		||||
    SecurityInterfaceObject& _secIfObj;
 | 
			
		||||
    DeviceObject& _deviceObj;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user