SPDX-License-Identifier: GPL-3.0-only
SPDX-FileCopyrightText: Copyright Logan oos Even
SPDX-FileCopyrightText: Copyright Hamish Coleman

# Edge Authentication

From a discussion on how to prevent MAC address spoofing, the need of edge authentication became evident. In fact, the REGISTER_SUPER type messages already have shown a so far unused `auth` field which gets used for the first time starting in the course of n3n version 2.9 development.

## Implementation

n3n implements two different authentication schemes the user can chose from.

### Identity Based Scheme

A very basic authentication scheme based on a unique identification number is put in place. This ID is randomly generated during edge start-up and remains unchanged until the edge terminates. With every REGISTER_SUPER, it is transmitted to the supernode which remembers it from the first REGISTER_SUPER and can compare it to all the following ones. It is a verification based on "showing the ID". The supernode accepts REGISTER_SUPER (and thus changed MAC address or internet socket) and UNREGISTER type messages only if verification passes.

This does not only prevent UNREGISTER attacks but also MAC spoofing even in case of several federated supernodes because each REGISTER_SUPER message is forwarded to all other supernodes. If a new edge (un)intentionally tries to claim a MAC address which already has been in use by another edge, this would be detected as unauthorized MAC change because the new edge presents a different authentication ID. The supernode which rejects it (based on a failed comparison) sends a REGISTER_SUPER_**NAK** type message to the new edge as well as the supernode through which the new edge tried to register. The REGISTER_SUPER_NAK will cause the edge to output an ERROR message, it does not stop the edge anymore to prevent de-auth attacks.

As opposed to the MAC address which is sent out with each packet also between edges, the ID remains between the edge and the supernode. Other edges do not become aware of it and thus are not able to spoof.

A somewhat hurdling network sniffing attack aimed at observing the authentication ID could break this scheme. Thus, further development towards a more sophisticated crypto-based authentication scheme is intended.

In case of edges unexpectedly shutting down with no opportunity for a clean exit, this auth scheme prevents re-connection to the supernode until it internally is removed from the list (after some 90 seconds or so). Although `-M` command line option at the supernode can disable authentication ID comparison to circumvent this situation, usage of user / password based authentication scheme is highly recommended instead.

### User / Password Based Authentication

A more advanced scheme relies on username and especially password. Public key
cryptography, namely Curve25519, ensures safety. Basically, the password along
with the mixed in user name, serve as private key. The corresponding public key
is generated by the `edge tools keygen` utility. The such generated public key
gets deposited at the supernode.

#### Supernode Preparation

To generate a public key for the user `logan` and her very secret password
`007`, the `edge tools keygen` utility would be called with username and
password as command line parameter:

```bash
[user@machine n3n]$ edge tools keygen logan 007
* logan nHWum+r42k1qDXdIeH-WFKeylK5UyLStRzxofRNAgpG
```

The generated output line of format `* <username> <public key>` needs to be copied to the supernode's community list file, e.g. to the  exemplary `community.list` file.

```
#
# List of allowed communities
# ---------------------------
#
#      these could either be fixed-name communities such as the following lines ...
#
mynetwork
netleo
* logan nHWum+r42k1qDXdIeH-WFKeylK5UyLStRzxofRNAgpG
* sister HwHpPrdMft+38tFDDiunUds6927t0+zhCMMkQdJafcC
#
#      ... or regular expressions that a community name must fully match
#      such as ntop[0-1][0-9] for communities from "ntop00" through "ntop19"
# 
ntop[0-1][0-9]

   ...
```

This example also lists another user `sister` (with the same secret password
`007`). The users become part of the preceding community name, `netleo` in this
case. The public keys are cryptographically tied only to the user name, not to
the community name. That way, to switch a user from one community to another,
her line can easily be copied from one community section to another. By the
way, do not forget to provide the `community.list` file to the supernode
through the `supernode.community_file` option.

Current supernode behavior does not limit the simultaneous usage of usernames,
i.e. one username can be used from several edges at the same time. However, it
is recommended to use a distinct username and password for each edge or
computer. Your management output will be much more meaningful then with the
`HINT` column showing the related username. Also, the auto IP address feature,
(i.e. not using a static ip at the edge) will more likely assign unique
addresses as those depend on the username.

If a user chooses a new password or needs to be excluded from accessing the community (stolen edge scenario), the corresponding line of the `community.list` file can be replaced with a newly generated one or be deleted respectively. Restarting the supernode or issuing the `reload_communities` command to the management port is required after performing changes to make the supernode(s) read in this data again.

When using this feature federation-wide, i.e. across several supernodes, please
make sure to keep all supernodes' `community.list` files in sync. So, if you
delete or change a user one supernode (or add it), you need to do it at all
supernodes. There is no built-in sync for the `community.list` files across the
federation. External tools such as _Syncthing_ or your very own script-driven
scp-based-file-distribution might be of assistance. Also, with every change,
you need to restart the supernode or issue the `reload_communites` command to
the management API as outlined above.

With a view to the detailed explanations below, your supernode(s) should have a
non-default federation name given by the `supernode.federation` config option.
It is used to derive a private key at the supernode side and is only to be
shared among supernodes.


#### Edge

The edge uses the `connection.description` option as the username.  This option
defaults to the local host name, which may not be the right value for your
environment.  The maximum length for the username is 15 characters.
The password is set with the `auth.password` options.

Continuing the given example, the edge could be invoked by:

```
[user@host n3n]$ sudo ./n3n-edge \
    start \
    -l <supernode:port> \
    -c netleo \
    -Oconnection.description=logan \
    -Oauth.password=007 \
    <any additional parameters>
```

Note that header encryption already is enabled automatically as this
authentication scheme heavily relies on it. Also, currently only the stream
ciphers work with this authentication scheme reliably in terms of security. So,
`-Ocommunity.cipher=ChaCha20` or `-Ocommunity.cipher=Speck` along with a key
`-k <key>` are required as additional parameters.

The edges need to know the public key of the supernode. By default, the edges
assume the default federation name, or more specific, the corresponding public
key. In case the supernode is given a custom federation name which is highly
recommended, the supernode's public key is provided to the edges via the
`auth.pubkey` config option. It can be generated from the federation name by
using the `edge tools keygen` utility as well:

```bash
[user@host n3n]$ n3n-edge tools keygen secretFed
auth.pubkey=opIyaWhWjKLJSNOHNpKnGmelhHWRqkmY5pAx7lbDHp4
```

Considering all this, our example expands to:

```
[user@host n3n]$ sudo ./n3n-edge \
    start \
    -l <supernode:port> \
    -c netleo \
    -Oconnection.description=logan \
    -Oauth.password=007 \
    -Oauth.pubkey=opIyaWhWjKLJSNOHNpKnGmelhHWRqkmY5pAx7lbDHp4 \
    -Ocommunity.cipher=Speck \
    -k mySecretKey
```

You might want to consider the use of [`.conf` files](ConfigurationFiles.md) to
accomodate all the command line parameters more easily. Alternatively, the
`N3N_PASSWORD` environment variable can be used to set the password without
having it show up as part of the command line.


#### How Does It Work?

In order to make this authentication scheme work, the existing header
encryption scheme is split into using two keys: a _static_ and a _dynamic_
one. The static key remains unchanged and is the [classic header encryption
key](../internals/Crypto.md#header) derived from the community name. It
only is applied to the very basic registration traffic between edge and
supernode (REGISTER_SUPER, REGISTER_SUPER_ACK, REGISTER_SUPER_NAK). The
dynamic key is derived (among others) from the federation name – keep it
secret! – and applied to all the other packets, especially the data packets
(PACKET) and peer-to-peer building packets (REGISTER), but also the ping and
peer information (QUERY_PEER, PEER_INFO). An edge not provided with a valid
dynamic key is not able to participate in the further communication.

In regular header encryption mode, static key and dynamic key are equal. With activated user-password scheme, the supernode generates and transmits a dynamic key with the REGISTER_SUPER for further use. This happens in a secure way based on public key cryptography. A non-authenticated edge, i.e. without corresponding entry at the supernode or valid credentials, will not receive a valid dynmic key for communication beyond registration.

In user-password scheme, the packets encrypted with the static key (REGISTER_SUPER, REGISTER_SUPER_ACK, useless for REGISTER_SUPER_NAK) are "signed" with an encrypted outer hash using the shared secret which is only known to the federated supernodes and that specific edge.

#### Possible Extensions

Tools for automizing [`.conf` file](ConfigurationFiles.md) generation for deployment ot delivery to freshly registered and approved users could greatly enhance this ecosystem; a user would not have to mess around with command line parameters but just copy a `.conf` file into a specified directory.

Let us know if you are interested in implementing or furthering these ideas.
