Skip to content

Device Access Control

The device access control list (/auth/at) and the certificate trust list (/auth/crts) control which peers can access device resources. The access control list stores credentials and permission scopes. The trust list stores trusted CA certificates for (D)TLS authentication. A Management and Commissioning Client (MaC) with if.sec scope configures both resources during commissioning.

Access Token Configuration

The MaC installs access tokens during the PASE handshake and configuration download phases. See Device Bootstrapping for the full commissioning sequence.

Before any access decision, the device authenticates the peer by matching an OSCORE pre-shared key or by validating an X.509 certificate chain with the trust list. The device then checks whether the access token scope covers the requested resource.

Access Token Table (/auth/at)

A MaC writes access tokens during onboarding and configuration download. KNX IoT supports two credential types (X.509 support is optional):

  • OSCORE (cnf → OSCORE key material): pre-shared key context for application-layer encryption. Used for group communication (multicast and unicast S-Mode), datapoint read/write, MaC administrator access, etc.
  • X.509 (cnf → certificate reference in /auth/crts): identity-based access using a peer certificate signed by a trusted CA. Used for the same purposes as OSCORE but authenticated via TLS instead of a pre-shared key.

Each access token entry carries a scope that limits which Group Addresses (GAs) or device interfaces the credentials cover.

The at field in /fp/r and /fp/p references an access token by its id. Both at and access token id are text strings (for example at='1a' in /fp/r pairs with the access token whose id is '1a').

Access Token CBOR Keys

CBOR Key Name Type M/O Description
0 id text string [m] Access token ID (ASCII, numbers and lowercase letters, max 32 bytes). Unique on a device, should be unique in an installation.
4 exp unsigned [o] Expiration time (epoch-based NumericDate, RFC 8392). If missing, the token does not expire.
5 nbf unsigned [o] Not-before time (epoch-based NumericDate, RFC 8392). If missing, the token is valid immediately.
8 cnf map [m] Confirmation claim containing either osc (key 4) or kid (key 3). See cnf tables below.
9 scope string array or unsigned array [m] Interface-name strings (e.g, tool keys) or GA integers (group tokens)
38 profile unsigned [m] 2 = coap_oscore, 254 = coap_tls, 255 = coap_pase.

OSCORE cnf CBOR Keys (cnf → osc = 4)

The cnf map contains a single osc entry with key 4. Its value is a map with the following fields:

CBOR Key Name Type M/O Description
0 id (osc-id) byte string [m] OSCORE input material ID, 1–7 bytes. Request sender/recipient ID, placed in the kid header field.
1 version unsigned [o] OSCORE version. Default: 1. Counting starts at 1.
2 ms (master secret) byte string [m] OSCORE master secret (16-32 bytes). Shared by all peers as HKDF input; default algorithms require at least 16 bytes of entropy.
4 alg unsigned [o] AEAD algorithm. Default: AES-CCM-16-64-128 (10).
5 hkdf negative / unsigned [o] HKDF algorithm. Default: HKDF-SHA-256 (-10).
6 contextId byte string [m]* OSCORE ID Context, a sender-specific salt. *Mandatory for every device that sends with this token.
35 salt byte string [o] OSCORE master salt. Default: empty.

The osc-id names one direction only. The client uses it as its request sender ID, the server as its request recipient ID. For responses the roles reverse and the server's sender ID is always the empty byte string (h''), which is why osc-id must not be empty.

The contextId is unique per sending device, so several devices can share one master secret and salt and still derive distinct sender keys. It applies to the device's own request sender context only. For incoming requests the device derives the recipient context from the kid_context of the received message, which carries the peer's contextId. Group access tokens are typically used in both directions, so a device both sends with its own contextId and maintains recipient contexts for its peers. Reconfiguring a device with the same keying material but a new contextId produces different AEAD keys, which lets the device restart its sequence number at 0. Peers treat it as a new sender: they build a fresh recipient context and re-establish the replay window with an Echo challenge.

X.509 Access Token

For X.509 access tokens the device authenticates the peer via (D)TLS instead of OSCORE. X.509 access tokens share the id, cnf, and scope fields with OSCORE tokens. The structure differs in two ways: the cnf map carries a certificate reference instead of key material, and the access token adds a sub claim and a different profile value. The table below lists only the changed and added fields.

CBOR Key Name Type M/O Description
2 sub text string [m] Client certificate SAN (URI knx://…) the device authorises.
38 profile unsigned [m] ACE profile. 254 = coap_tls.

X.509 cnf CBOR Keys (cnf → kid = 3)

The cnf map has a kid value (RFC 8747, CWT Confirmation Method key 3) set to the certificate thumbprint of a CA entry in /auth/crts. The kid matches the thumbprint to find the trust anchor for certificate-chain validation and SAN matching.

CBOR Key Name Type M/O Description
3 kid byte string [m] References a X.509 certificate in /auth/crts (trust anchor).

Scope Values

Scope type Value example Use
Group access token [2304, 2305, 2306, 2307] Covers all listed GAs (multicast or unicast group).
Single-GA access token [2305] Covers one GA only (cross-device unicast).
Tool-key access token ["if.c","if.p","if.d","if.sec","if.swu","if.g.s"] Full device access (onboarding tool key).
Config-admin access token ["if.sec"] Security scope only (PASE rkey, or restricted MaC).

Multicast Group Access Token Example

Shared credentials for all devices in a multicast group. Both the sender (publisher, fp/p) and all receivers (fp/r) hold the same access token. Each publisher adds its own unique contextId so that every sender derives a different AEAD key. Two senders sharing a contextId would derive the same key and lose confidentiality protection.

# POST to /auth/at — group access token covering GAs 2304-2307 (sender side, with contextId)
[{0: h'3',                                       # id: access token identifier
  8: {4: {0: h'0c00fa10020700',                  # sender_id (7 bytes)
          2: h'ff112233445566778899aabbccddeeff', # master_secret (16 bytes)
          6: h'55cf25777e'}},                    # contextId (publisher-unique)
  9: [2304, 2305, 2306, 2307],                   # scope (Group Addresses)
  38: 2}                                         # profile = OSCORE
]

For matching /fp/r and /fp/p multicast entries, see Function Point Tables (no at field—the kid in the OSCORE header identifies the token).

Unicast Access Token Example

Pairwise credentials for direct unicast or endpoint subscription. Each recipient pair has a unique master secret. The at field in /fp/r or /fp/p references this access token by its id. This unicast token covers one exchanged Group Address only.

# POST to /auth/at — unicast access token for status to light switch (GA 2305)
[{0: h'1a',                                       # id: access token identifier
  8: {4: {0: h'0101',                             # sender_id (2 bytes)
          2: h'fc0cde2339cdeaee109129ef0852de91', # master_secret (16 bytes)
          6: h'20000633ce07'}},                   # contextId (publisher-unique)
  9: [2305],                                      # scope (single GA)
  38: 2}                                          # profile = OSCORE
]

For the fp/r entry that references this token via at='1a', see Unicast Example. For a subscription fp/p entry, see Endpoint Subscription Example.

Tool Key Access Token Example

The MaC installs this token during IA configuration (PASE flow). It grants full device access to the MaC. A MaC can use the sender ID bytes as the access token id. Only the PASE-generated token requires this convention.

# POST to /auth/at — tool key with full interface scope
[{0: '0c00fa10h0207',                            # id: sender_id text string
  8: {4: {0: h'0c00fa100207',                    # sender_id (6 bytes)
          2: h'a1b2c3d4e5f60718293a4b5c6d7e8f90'}}, # master_secret (16 bytes)
  9: ["if.c", "if.p", "if.d", "if.sec", "if.swu", "if.g.s"],  # full scope
  38: 2}                                         # profile = OSCORE
]

Certificate Trust List (/auth/crts)

Each entry is an X.509 v3 DER-encoded certificate. The MaC writes entries here before (or together with) any X.509 access tokens that reference them via kid. A device shall support at least three CA certificates (for example, MaC, Registrar, and KDC). For the (D)TLS onboarding flow and LDevID enrollment, see Device Bootstrapping with TLS.

Certificate Entry CBOR Keys

Each item in /auth/crts/<cert-id> represents an X.509 certificate:

CBOR Key Name Type M/O Description
0 id text string [m] X.509 certificate thumbprint. Used as the kid value in the corresponding /auth/at access token entry.

Trust Anchor Selection

When a peer presents its certificate during the TLS handshake the device:

  1. Looks up the access token in /auth/at whose cnf.kid matches a value in /auth/crts.
  2. Uses the certificate stored at that /auth/crts entry as the trust anchor to validate the peer's certificate chain, or the peer certificate itself when the entry contains the peer's self-signed certificate.
  3. Checks that the peer certificate Subject Alternative Name matches the sub claim of the access token.
  4. Grants access only if all three checks pass and the access token scope covers the requested resource.

X.509 Access Token Example

The corresponding X.509 access token in /auth/at:

# POST to /auth/at — X.509 tool key (coap_tls profile)
[{0: h'tool-ca',                              # id: access token identifier
  2: "knx://security-zone-1/tool",           # sub: authorised certificate SAN
  8: {3: h'b52e8fa1c3d4e607192a3b4c5d6e7f8091a2b3c4d5e6f708192a3b4c5d6e7f80'},  # cnf.kid: CA thumbprint → /auth/crts
  9: ["if.c", "if.p", "if.d",
      "if.sec", "if.swu", "if.g.s"],         # scope: full device access
  38: 254}                                  # profile = coap_tls
]