feat(gateway): implement KNX security features including secure session handling and factory certificate management
Signed-off-by: Tony <tonylu@tony-cloud.com>
This commit is contained in:
@@ -35,6 +35,12 @@ constexpr uint16_t kServiceDisconnectResponse = 0x020a;
|
||||
constexpr uint16_t kServiceTunnellingRequest = 0x0420;
|
||||
constexpr uint16_t kServiceTunnellingAck = 0x0421;
|
||||
constexpr uint16_t kServiceRoutingIndication = 0x0530;
|
||||
constexpr uint16_t kServiceSecureWrapper = 0x0950;
|
||||
constexpr uint16_t kServiceSecureSessionRequest = 0x0951;
|
||||
constexpr uint16_t kServiceSecureSessionResponse = 0x0952;
|
||||
constexpr uint16_t kServiceSecureSessionAuth = 0x0953;
|
||||
constexpr uint16_t kServiceSecureSessionStatus = 0x0954;
|
||||
constexpr uint16_t kServiceSecureGroupSync = 0x0955;
|
||||
constexpr uint8_t kKnxNetIpHeaderSize = 0x06;
|
||||
constexpr uint8_t kKnxNetIpVersion10 = 0x10;
|
||||
constexpr uint8_t kKnxNoError = 0x00;
|
||||
@@ -42,6 +48,8 @@ constexpr uint8_t kKnxErrorConnectionId = 0x21;
|
||||
constexpr uint8_t kKnxErrorConnectionType = 0x22;
|
||||
constexpr uint8_t kKnxErrorNoMoreConnections = 0x24;
|
||||
constexpr uint8_t kKnxErrorSequenceNumber = 0x04;
|
||||
constexpr uint8_t kKnxSecureStatusAuthFailed = 0x01;
|
||||
constexpr uint8_t kKnxSecureStatusUnauthenticated = 0x02;
|
||||
constexpr uint8_t kKnxConnectionTypeTunnel = 0x04;
|
||||
constexpr uint8_t kKnxTunnelLayerLink = 0x02;
|
||||
constexpr uint8_t kTpUartResetRequest = 0x01;
|
||||
@@ -507,6 +515,20 @@ bool ParseKnxNetIpHeader(const uint8_t* data, size_t len, uint16_t* service,
|
||||
return *total_len >= 6 && *total_len <= len;
|
||||
}
|
||||
|
||||
bool IsKnxNetIpSecureService(uint16_t service) {
|
||||
switch (service) {
|
||||
case kServiceSecureWrapper:
|
||||
case kServiceSecureSessionRequest:
|
||||
case kServiceSecureSessionResponse:
|
||||
case kServiceSecureSessionAuth:
|
||||
case kServiceSecureSessionStatus:
|
||||
case kServiceSecureGroupSync:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsExtendedTpFrame(const uint8_t* data, size_t len) {
|
||||
return len > 0 && (data[0] & 0xD3) == 0x10;
|
||||
}
|
||||
@@ -1875,6 +1897,10 @@ void GatewayKnxTpIpRouter::handleUdpDatagram(const uint8_t* data, size_t len,
|
||||
}
|
||||
const uint8_t* body = data + 6;
|
||||
const size_t body_len = total_len - 6;
|
||||
if (IsKnxNetIpSecureService(service)) {
|
||||
handleSecureService(service, body, body_len, remote);
|
||||
return;
|
||||
}
|
||||
switch (service) {
|
||||
case kServiceRoutingIndication:
|
||||
if (config_.multicast_enabled) {
|
||||
@@ -2001,6 +2027,34 @@ void GatewayKnxTpIpRouter::handleDisconnectRequest(const uint8_t* body, size_t l
|
||||
sendDisconnectResponse(channel_id, status, remote);
|
||||
}
|
||||
|
||||
void GatewayKnxTpIpRouter::handleSecureService(uint16_t service, const uint8_t* body,
|
||||
size_t len, const sockaddr_in& remote) {
|
||||
#if defined(CONFIG_GATEWAY_KNX_IP_SECURE_SUPPORTED)
|
||||
switch (service) {
|
||||
case kServiceSecureSessionRequest:
|
||||
case kServiceSecureSessionAuth:
|
||||
ESP_LOGW(kTag, "KNXnet/IP Secure service 0x%04x rejected: secure sessions are not provisioned", service);
|
||||
sendSecureSessionStatus(kKnxSecureStatusAuthFailed, remote);
|
||||
break;
|
||||
case kServiceSecureWrapper:
|
||||
ESP_LOGW(kTag, "KNXnet/IP Secure wrapper rejected: no authenticated secure session");
|
||||
sendSecureSessionStatus(kKnxSecureStatusUnauthenticated, remote);
|
||||
break;
|
||||
case kServiceSecureGroupSync:
|
||||
ESP_LOGD(kTag, "KNXnet/IP Secure group sync ignored until secure routing is provisioned");
|
||||
break;
|
||||
default:
|
||||
ESP_LOGD(kTag, "KNXnet/IP Secure service 0x%04x ignored", service);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
(void)service;
|
||||
(void)body;
|
||||
(void)len;
|
||||
(void)remote;
|
||||
#endif
|
||||
}
|
||||
|
||||
void GatewayKnxTpIpRouter::sendTunnellingAck(uint8_t channel_id, uint8_t sequence,
|
||||
uint8_t status, const sockaddr_in& remote) {
|
||||
const std::vector<uint8_t> body{0x04, channel_id, sequence, status};
|
||||
@@ -2008,6 +2062,12 @@ void GatewayKnxTpIpRouter::sendTunnellingAck(uint8_t channel_id, uint8_t sequenc
|
||||
SendAll(udp_sock_, packet.data(), packet.size(), remote);
|
||||
}
|
||||
|
||||
void GatewayKnxTpIpRouter::sendSecureSessionStatus(uint8_t status, const sockaddr_in& remote) {
|
||||
const std::vector<uint8_t> body{status, 0x00};
|
||||
const auto packet = KnxNetIpPacket(kServiceSecureSessionStatus, body);
|
||||
SendAll(udp_sock_, packet.data(), packet.size(), remote);
|
||||
}
|
||||
|
||||
void GatewayKnxTpIpRouter::sendTunnelIndication(const uint8_t* data, size_t len) {
|
||||
if (!tunnel_connected_ || udp_sock_ < 0 || data == nullptr || len == 0) {
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user