Lightweight and secure IoT communications library

C2 specification

C2 (command-and-control) is the host that manages clients’ keys remotely, by sending commands to clients over MQTT.

E4's C2 holds client keys and topic keys, and manages clients by sending them commands.

C2 internal state

C2's state is composed of:

  • clientkeys, a map from client identities (as 16-byte strings) to their keys (symmetric keys or public keys, depending on the mode).

  • topickeys, a map from topics (as strings) to 32-byte topics keys.

This state is typically stored as a database.

Unlike clients whose actions are triggered by events (commands received, messages going in and out), C2's actions can be triggered by an operator, via a web UI or command-line interface, or by another service via C2's HTTP or gRPC APIs, for example by E4's automation engine.


Operations performed by C2 are of three types

  • Operations modifying the local state (local clientkeys and topickeys tables)

  • Operations modifying clients’ states (remote key value and topickeys table), by sending a command as an MQTT messages (with QoS 2).

  • Operations modifying both the local state and clients’ states

This is just the minimal set of functionalities that the C2 API can implement, via HTTP and/or gRPC interfaces.

Other helper endpoints can be added, as needed by other components (command-line client, automation engine, etc.).

The API might also be extended by having endpoints supporting batch commands (for example, to reset multiple clients with a single request).

new_client(id, key) [local]

Adds (id, key) to clientkeys; overwrite the existing key if id already exists. Depending on the mode, key is either a symmetric key or a public key.

remove_client(id) [local]

Removes id from C2's clientkeys map; fails if id does not exist.

new_topic_client(id, topic) [remote]

Sends the key of topic to the id using a SetTopicKey command; fails if no key is known for topic or for id.

remove_topic_client(id, topic) [remote]

Removes the given topic from the client's topickeys table using a RemoveTopic command.

reset_client(id) [remote]

Resets the topickeys table of the given client, using a ResetTopics command.

new_topic(topic) [local]

A random key is generated for topic, erasing any previous entry in topickeys. The key is then distributed to all clients that have the key for this topic.

remove_topic(topic) [local]

If the given topic is in topickeys, then the topic and its key are removed from it; fails if topic does not exist.

new_client_key(id) [local & remote, SK mode]

If id exists, random key is generated for id and sent to it using a SetIdKey command. The (id, key) pair is then added to C2's clientkeys.

A risk when updating the client key is the client being “in the dark” if it did not receive the key update.

Here there is no need for the client to retain the old key.

However, C2 may need to retain the previous key, but this only shifts the DoS problem to the next generation of key update, unless C2 can get a confirmation that the client registered the new key.

Depending on the use case and associated risk, we can implement a failure recovery mechanism, whereby clients can recover from desynchronized keys.

reset_client_pubkeys(id) [remote, PK mode]

Resets the clientkeys table of the given client, using a ResetPubKeys command.

send_client_pubkey(iddst, idsrc) [remote, PK mode]

Sends the public key of idsrc to iddst, to add it to its clientkeys table.

Note that when a client is added to a topic, other devices from this topic don't automatically receive the client's public key. This would be necessary when emulating group messaging (many-to-many communications), but not in many-to-one network. In the former case, public key sharing can be automated through simple scripts. This behavior may be modified according to the users’ needs.

remove_client_pubkey(iddst, idsrc) [remote, PK mode]

Remove the public key of idsrc to iddst, to add it to its clientkeys table.

new_c2_key() [local & remote, PK mode]

A random key pair is generated for C2 and its public key is sent to all clients using a SetC2Key command. The new key pair is then used by C2 and replaces the previous one.

C2 human interface

C2 human interfaces can be command-line clients or a web-based GUI, using the API to translate user actions into C2 operations.

To facilitate manual operation, the following user-friendly mechanisms can be implemented:

  • id can be generated from a string alias, as a hash of the alias

  • The key or key pair can be derived from a passphrase, using a password-based key derivation function