# 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 n2n version 2.9 development.

## Implementation

n2n 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 `tools/n2n-keygen` utility. The such generated public key gets depoisted at the supernode.

#### Supernode Preparation

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

```bash
[user@machine n2n]$ tools/n2n-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 `-c community.list` parameter.

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 port 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 <IP address>` 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 port as outlined above.

With a view to the detailed explanations below, your supernode(s) should have a non-default federation name given by the `-F <federation name>` command line parameter, e.g. `-F secretFed`. Alternatively, it can be passed through the environment variable `N2N_FEDERATION`. It is used to derive a private key at the supernode side and is only to be shared among supernodes.


#### Edge

The edge takes the username with the already present, identifying command line parameter `-I <username>`. The password goes into `-J <password>`. Continuing the given example, the edge is invoked by

```
[user@host n2n]$ sudo ./edge -l <supernode:port> -c netleo -I logan -J 007 <your 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, `-A4` for ChaCha20 or `-A5` for 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 command line parameter `-P <public key>`. It can be generated from the federation name by using the `tools/n2n-keygen` utility as well:

```bash
[user@host n2n]$ tools/n2n-keygen -F secretFed
-P opIyaWhWjKLJSNOHNpKnGmelhHWRqkmY5pAx7lbDHp4
```

Considering all this, our example expands to

```
[user@host n2n]$ sudo ./edge -l <supernode:port> -c netleo -I logan -J 007 -A5 -k mySecretKey -P opIyaWhWjKLJSNOHNpKnGmelhHWRqkmY5pAx7lbDHp4
```

You might want to consider the use of [`.conf` files](https://github.com/ntop/n2n/blob/dev/doc/ConfigurationFiles.md) to accomodate all the command line parameters more easily. Alternatively, the `N2N_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](https://github.com/ntop/n2n/blob/dev/doc/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](https://github.com/ntop/n2n/blob/dev/doc/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.
