n2n/doc/Authentication.md
2021-10-26 03:31:01 +05:45

9.8 KiB
Raw Permalink Blame History

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:

[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:

[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 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 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 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.