This pages describes our usage of HMAC message to secure our re6st network.
Introduction
Re6st is a collaborative mesh network. Each node is sharing to the other nodes the neighbours it can contact and with what latency. Based on this, each node calculates the best route to reach any given node. As a collaborative network, re6st is very sensitive to any malicious nodes. For example, a node could give erroneous information regarding latency to force other nodes to go through it. Worse, a malicious re6st node could filter/drop the IPv6 traffic going through it. Therefore, we need to guarantee that only legit nodes are exchanging information and we introduced the use of HMAC to secure the communication between nodes.
You can read more about re6st architecture here. In order to read this article you just need to know that each node is sharing information with other nodes to determine the best routes and more specifically, it is babel routing protocol that is used to do this.
HMAC in re6st
Since 2021, babel daemon is officially able to use HMAC authentication for all its messages but the work started a few years before in 2019. As soon as babel introduced this new feature we tested it and we started to integrate it in re6st. We gave feedback to the author of the feature.
Role of Babel for Re6st
Babel is the routing protocol used by re6st-nodes.
The daemon Babeld communicates with other Babeld and decide the best routes (i.e lowest metrics) to install in the kernel for each node, therefore, it's up to Babel to calculate efficient routes in Re6st.
Re6st uses the routes installed by Babel to route its traffic. The Re6st nodes can be connected through openvpn tunnels (Re6st will continuously open and close tunnels between nodes) or through physical LAN connection.
HMAC for Babel
HMAC (key-hashed message authentication code) consists of adding a key to every Babel message exchanged mainly to ensure that Babel communication is only made between two legit machines of the same Re6st network.
Without HMAC, nodes on a same LAN but not in the same re6st network could establish Babel communication through local links.
The goal is to be able to share a common HMAC signatures between all Re6st nodes. We also need to be able to change the HMAC key if it has been compromised or if we want to force a node to exit the network (in this case, we regenerate a new HMAC key and we make sure this node don't get the new version).
When a network is created, a HMAC key is randomly generated on 16 bytes, a notification is then propagated to all nodes and the new key is communicated to them when they ask for network parameters.
The Re6st registry manages this key and can update it whenever it wants via the RPC updateHMAC
, that modifies the database of the registry and changes the version of network parameters.
Because it's Re6st that launches Babel, it will restart it upon receiving new HMAC changes to take it into account by modifying the babeld process call.
If a node was down when the parameters were propagated, the node will get them when restarting because nodes check their versions of network parameters every 5 minutes.
The database of the registry can contain 3 different values for HMAC: babel_hmac0, babel_hmac1, babel_hmac2
, it's this database that dictates the HMAC state on a Re6st network and nodes should stay synchronized with it.
The HMAC configuration follows this cycle of changes that allows us to perform steps that do not block communication (state N is compatible with state N-1):
Because we only need to store a maximum of two keys at the same time, we can just have two variables stored in the database of nodes: babel_hmac_sign
and babel_hmac_accept
, the logic is always that the lowest index of babel_hmac
stored on the registry will be assigned to babel_hmac_sign
, and the second index will be assigned to babel_hmac_accept
.
When a key is assigned to babel_hmac_sign
, babel will use that key to sign outgoing packets, and will also accept incoming packets signed with it.
When a key is assigned to babel_hmac_accept
, babel will simply accept incoming packets signed with this key.
To introduce HMAC on a Re6st network that does not use HMAC for Babel yet, a trick was added in Babel: we jump directly from nothing related to HMAC in the database of the registry to state 2 (where babel_hmac1
will be our new key and babel_hmac2
will be an empty string)
This empty strings means that the nodes will ignore packets that don't carry a HMAC key, this way even the introduction of the first key on a network that does not use HMAC for Babel will not block any communication with a possibly heterogeneous update to state 2 (where we can have on the same networks machines that sign with the new HMAC key and machines that don't sign packets with HMAC yet)
Release HMAC in production
Releasing HMAC in production is tricky because we first need to make sure that all nodes in a network are able to understand the HMAC signed packets. In order to overcome this kind of problem we have the min-protocol option of re6st. Nevertheless, it is a great effort to make sure that all nodes are up to date.
We first tried HMAC in our trial network in 2021 after all nodes were upgraded. But in the meantime the HMAC option of babel was reworked and some options in re6st needed to be adjusted.
We are now ready to retry HMAC in our trial network and this should happen before the end of June 2024. Then if everything works fine, we will upgrade both our ptoduction networks before the end of 2024.