knxultimate
Version:
KNX IP protocol implementation for Node. This is the ENGINE of Node-Red KNX-Ultimate node.
124 lines (95 loc) • 5.53 kB
Markdown
# KNX Secure Tunneling Workflow
This document summarizes the end‑to‑end flow used by KNX/IP Secure over TCP (TunnelTCP) for: session setup, tunneling, and KNX Data Secure payload protection. It also explains how sequence numbers are managed at each layer.
## Overview
- Transport: TCP to KNX/IP gateway on port 3671
- Protection layers:
- KNX IP Secure Session (Secure Wrapper, 0x0950)
- KNX Data Secure (SecureAPDU with APCI_SEC 0x03F1 + SCF 0x10)
- KNX/IP Tunneling for bus frames (0x0420/0x0421)
Note on interface selection and sender identity
- If `secureTunnelConfig.tunnelInterfaceIndividualAddress` is unset/empty, the client auto‑selects a usable interface from the ETS keyring and retries candidates until authentication/connect succeed. The chosen IA is applied at runtime.
- In TunnelTCP, the gateway assigns a tunnel IA in CONNECT_RESPONSE; bus frames use that IA as cEMI source. Data Secure, however, authenticates as the interface IA from the ETS keyring (not the dynamic tunnel IA).
## Session Establishment (KNX IP Secure)
1) TCP connect → gateway
2) Session Request (0x0951)
- Client sends: HPAI + X25519 public key (32B)
- Frame: `0610 | 0951 | len | HPAI | client_pubkey32`
3) Session Response (0x0952)
- Gateway replies with: `sessionId` + server X25519 public key (32B)
4) Session Key Derivation
- ECDH: `secret = X25519(client_priv, server_pub)`
- `sessionKey = SHA256(secret)[0..15]` (128-bit AES key)
5) Session Authenticate (0x0953) [wrapped]
- User key derivation: `userPasswordKey = PBKDF2(password, "user-password.1.secure.ip.knx.org", 65536, 16, sha256)`
- AdditionalData: header(0953) + `00` + `userId` + XOR(client_pubkey, server_pubkey)
- CBC‑MAC over `[block0=16 zeroes] + TL(additionalData) + additionalData` (no padding bytes in MAC; tail of CBC)
- Transform MAC via AES‑CTR with a fixed IV (see `AUTH_CTR_IV`)
- Send 0x0953 inside Secure Wrapper using `sessionKey`
6) Session Status (0x0954) [wrapped]
- Expect status `0` (OK). If OK, proceed to tunneling
## Tunneling Channel (KNX/IP)
7) CONNECT_REQUEST (0x0205) [wrapped]
- Body: HPAI control + HPAI data + CRD (link‑layer)
8) CONNECT_RESPONSE (0x0206) [wrapped]
- Returns `channelId` and (often) the tunnel‑assigned Individual Address (IA) in CRD
## Data Phase (KNX Data Secure over Tunneling)
Send path:
- Build plain APDU (e.g., GroupValueRead 0x0000, GroupValueWrite 0x0080 | value)
- Build SecureAPDU:
- Use per‑sender 48‑bit Data Secure sequence (`seq48`, persisted)
- Block0 for CBC‑MAC consists of:
- `seq48(6)` + `srcIA(2)` + `dstGA(2)`
- `00` + `(control2 & 0x8F)` + `((TPCI_DATA << 2) + 0x03)` + `0xF1` + `00` + `len(payload)`
- MAC‑CBC over `SCF(0x10) + payload` with `block0`; take 4 bytes
- CTR counter0: `seq48 + srcIA + dstGA + 00 00 00 00 01 00`
- Encrypt payload with CTR, transform MAC4 with CTR
- SecureAPDU = `[0x03, 0xF1] + [0x10] + seq48 + encPayload + encMac4`
- Pack into cEMI L_DATA_REQ and KNX/IP TUNNELING_REQUEST (with connection header)
- Send inside Secure Wrapper (0x0950)
Implementation notes:
- In TunnelTCP, cEMI `ack=0` (no KNX bus ACK requested). The KNX/IP Tunneling ACK (0x0421) still flows at the IP layer.
- The Data Secure sender IA (`srcIA`) is the interface IA from the keyring; `cEMI.srcAddress` is updated accordingly for consistency.
Receive path:
- On inbound TUNNELING_REQUEST: send TUNNELING_ACK
- Extract cEMI → if SecureAPDU:
- Derive `counter0` and decrypt payload/mac
- Rebuild `block0` and recompute 4‑byte MAC; verify
- Parse APCI (e.g., Read/Response/Write) and value (1‑bit for DPT_Switch)
## Sequence Numbers
- Secure Wrapper sequence (6 bytes, per session):
- Purpose: forms nonces/IVs for encrypting Secure Wrapper content
- Scope: increments per wrapped frame; not persisted; resets on new session
- Tunneling sequence (1 byte):
- Purpose: correlates TUNNELING_REQUEST with TUNNELING_ACK
- Scope: per channel, wraps at 256
- Data Secure sender sequence `seq48` (6 bytes, persisted):
- Purpose: anti‑replay and cryptographic nonce for Data Secure
- Used in MAC‑CBC `block0` and CTR `counter0`
- Persisted across runs; monotonic increasing
- Initialization: time‑based (ms since 2018‑01‑05) if no persisted store exists
## Timeouts (defaults)
- Session Response wait: 5s
- Session Status wait: 5s
- Connect Response wait: 15s
## ASCII Flow
```
Client Gateway
|------------------ TCP connect ------------------>|
| 0951 SECURE_SESSION_REQUEST (HPAI + pubkey) |
|<----- 0952 SECURE_SESSION_RESPONSE (sid + pk) ---|
| -- derive sessionKey via ECDH + SHA256 -- |
| wrap(0953 SECURE_SESSION_AUTHENTICATE) --------->|
|<---- wrap(0954 SECURE_SESSION_STATUS=OK) --------|
| wrap(0205 CONNECT_REQUEST) --------------------->|
|<--- wrap(0206 CONNECT_RESPONSE, channelId, IA) --|
| |
| wrap(0420 TUNNELING_REQUEST: cEMI L_DATA_REQ |
| SecureAPDU(seq48, encPayload, mac4)) --------->|
|<-------- wrap(0421 TUNNELING_ACK, seq8) ---------|
|<-- wrap(0420 TUNNELING_REQUEST: incoming cEMI ---|
| wrap(0421 TUNNELING_ACK) ----------------------->|
```
## Notes and Code Anchors
- Implementation lives inline in the client: `src/KNXClient.ts` (search for "KNX/IP Secure")
- Crypto/constants: `src/secure/secure_knx_constants.ts`, `src/secure/security_primitives.ts`
- Keyring parsing: `src/secure/keyring.ts`