@ -8,7 +8,7 @@ n2n implements two different authentication schemes the user can chose from.
### Identity Based Scheme
A very basic authentication scheme based on a uniqe 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 tranmitted to the supernode which remembers it from the first REGISTER_SUPER and can compare it to all the following ones. It is a verfication 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.
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.
@ -55,18 +55,18 @@ 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 simultanious 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.
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`. It is used to derive a priavte key at the supernode side and is only to be shared among supernodes.
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`. 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 paramater `-I <username>`. The password goes into `-J <password>`. Continuing the given example, the edge is invoked by
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
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 paramters more easily.
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.
#### 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 appplied to all the other packets, especially the data packets (PAKET) 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 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-autheticated edge, i.e. without corresponding entry at the supernode or valid credentials, will not receive a valid dynmic key for communication beyond registration.
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.
@ -102,4 +102,4 @@ In user-password scheme, the packets encrypted with the static key (REGISTER_SUP
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 intrerested in implementing or furthering these ideas.
Let us know if you are interested in implementing or furthering these ideas.
As communities designate virtual networks, they must be distingushable from each other. Its their name that makes them distinguishable and which therefore should be unique per network. The community name is composed of 19 byte-sized characters and it internally always is terminated by an additional zero character totalling up to 20 characters. Hence, the zero character cannot be part of the regular community name. There are some other characters that cannot be used, namely `. * + ? [ ] \`.
As communities designate virtual networks, they must be distinguishable from each other. Its their name that makes them distinguishable and which therefore should be unique per network. The community name is composed of 19 byte-sized characters and it internally always is terminated by an additional zero character totalling up to 20 characters. Hence, the zero character cannot be part of the regular community name. There are some other characters that cannot be used, namely `. * + ? [ ] \`.
To make full use of character space, hex values could be used, e.g. from Linux bash applying the `edge … -c $(echo -en '\x3a\x3b\x4a\x6a\xfa') …` command line syntax. If used with a configuration file, the bytes must be directly filled as characters into a corresponding `-c :;Jjþ` line.
@ -65,7 +65,7 @@ Also, as the `. * + ? [ ] \` characters indicate parts of regular expressions, w
By default, the community name is transmitted in plain witch each packet. So, a fixed-name community might keep your younger siblings out of your community (as long as they do not know the community name) but sniffing attackers will find out the community name. Using this name, they will be able to access it by just connecting to the supernode then.
[Header encryption](Crypto.md#header) can be enabled to prevent plain transmission. It is important to understand that header encryption, if enabled, only works on fixed-name communities. It will not work on communitiy names described by regular expressions.
[Header encryption](Crypto.md#header) can be enabled to prevent plain transmission. It is important to understand that header encryption, if enabled, only works on fixed-name communities. It will not work on community names described by regular expressions.
On the other hand, the provision of fixed-name communities blocks all other, non-listed communities. To allow a mixed operation of certain encrypted and hence fixed-name communities along with all other open communities, the following "trick" can be applied:
@ -70,4 +70,4 @@ Finally, the `.conf` file syntax also allows `=` between parameter and its optio
-l=supernode.ntop.org:7777
```
When used with `=`, there is no whitespace allowed between parameter, delimter (`=`), and option. So, do **not** put `-c = mynetwork` – it is required to be `-c=mynetwork`.
When used with `=`, there is no whitespace allowed between parameter, delimiter (`=`), and option. So, do **not** put `-c = mynetwork` – it is required to be `-c=mynetwork`.
@ -70,7 +70,7 @@ Its initialization relies on seeding with a value as random as possible. Various
### Pearson Block Hashing
For general purpose hashing, n2n employs [Pearson Block Hashing](https://github.com/Logan007/pearsonB) as it offers variable hash sizes and is said not to be too "collidy". However, this is not a cryptographically secure hashing function which by the way is not required here: The hashing is never applied in a way that the hash value shall publically prove the knowledge of a secret without showing the secret itself.
For general purpose hashing, n2n employs [Pearson Block Hashing](https://github.com/Logan007/pearsonB) as it offers variable hash sizes and is said not to be too "collidy". However, this is not a cryptographically secure hashing function which by the way is not required here: The hashing is never applied in a way that the hash value shall publicly prove the knowledge of a secret without showing the secret itself.
_Pearson hashing is tweakable by using your own block-sized permutation._ Here, we use a three-round xor-rotate-multiply permutation scheme on 64-bit wide integer numbers with constants discovered by [David Stafford](http://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html) (`mix13`, permission obtained via eMail) which, meanwhile, is better known as part of `splitmix64()`.
@ -124,7 +124,7 @@ In case of a PACKET-type, it is succeeded by the fields depicted below:
### Encryption
If enabled (`-H`), all fields but the payload (which is handled seperately as outlined above) get encrypted using SPECK in CTR mode. As packet headers need to be decryptable by the supernode and we do not want to add another key (to keep it a simple interface), the community name serves as key (keep it secret!) because it is already known to the supernode. The community name consists of up to 20 characters (well, 19 + `0x00`), so key size of 128 bit is a reasonable choice here.
If enabled (`-H`), all fields but the payload (which is handled separately as outlined above) get encrypted using SPECK in CTR mode. As packet headers need to be decryptable by the supernode and we do not want to add another key (to keep it a simple interface), the community name serves as key (keep it secret!) because it is already known to the supernode. The community name consists of up to 20 characters (well, 19 + `0x00`), so key size of 128 bit is a reasonable choice here.
The scheme applied tries to maintain compatibility with current packet format and works as follows:
@ -175,7 +175,7 @@ The scheme applied tries to maintain compatibility with current packet format an
Decryption checks all known communities (several in case of supernode, only one at edge) as keys. On success, the emerging magic number along with a reasonable header's length value will reveal the correct community whose name will be copied back to the original fields allowing for regular packet handling.
Thus, header encryption will only work with previously determined community names introduced to the supernode by `-c <path>` parameter. Also, it should be clear that header encryption is a per-community decision, i.e. all nodes and the supernode need to have it enabled. However, the supernode supports encrpyted and unencrypted communities in parallel, it determines their status online at arrival of the first packet. Use a fresh community name for encrypted communities; do not use a previously used one of former unecrpyted communities: their names were transmitted openly.
Thus, header encryption will only work with previously determined community names introduced to the supernode by `-c <path>` parameter. Also, it should be clear that header encryption is a per-community decision, i.e. all nodes and the supernode need to have it enabled. However, the supernode supports encrypted and unencrypted communities in parallel, it determines their status online at arrival of the first packet. Use a fresh community name for encrypted communities; do not use a previously used one of former unecrypted communities: their names were transmitted openly.
### Checksum
@ -183,7 +183,7 @@ The whole packet including the eventually present payload is checksummed using a
The single block-cipher step employs SPECK because it is quite fast and it offers a 128-bit block cipher version. The key is derived from the header key – a hash of the hash.
The checksum is calculated by the edges and the supernode. Changes to the payload will cause a different locally calculated checksum. Extracting the time stamp by exclusive-oring an errorneous checksum will lead to an invalid timestamp. So, checksum errors are indirectly detected when checking for a valid time stamp.
The checksum is calculated by the edges and the supernode. Changes to the payload will cause a different locally calculated checksum. Extracting the time stamp by exclusive-oring an erroneous checksum will lead to an invalid timestamp. So, checksum errors are indirectly detected when checking for a valid time stamp.
### Replay Protection
@ -199,7 +199,7 @@ The aforementioned 128-bit pre-IV can be depicted as follows:
```
The time stamp consists of the 52-bit microsecond value, a 8-bit counter in case of equal following time stamps and, a 4-bit flag field F (accuracy indicator in last bit). edge and supernode monitor their own time stamps for doublets which would indicate an accuracy issue. If the counter overflows on the same time stamp, the sub-second part of the time stamp will also become counter. In this case, the whole stamp carries the accurcy bit flag (lowest bit) set so other edges and supernodes can handle this stamp appropriately.
The time stamp consists of the 52-bit microsecond value, a 8-bit counter in case of equal following time stamps and, a 4-bit flag field F (accuracy indicator in last bit). edge and supernode monitor their own time stamps for doublets which would indicate an accuracy issue. If the counter overflows on the same time stamp, the sub-second part of the time stamp will also become counter. In this case, the whole stamp carries the accuracy bit flag (lowest bit) set so other edges and supernodes can handle this stamp appropriately.
Encrypting this pre-IV using a block cipher step will generate a pseudo-random looking IV which gets written to the packet and used for the header encryption.
@ -211,6 +211,6 @@ Upon receival, the time stamp as well as the checksum can be extracted from the
- Valid (remote) time stamps get stored as "last valid time stamp" seen from each node (supernode and edges). So, a newly arriving packet's time stamp can be compared to the last valid one. It should be equal or higher. However, as UDP packets may overtake each other just by taking another path through the internet, they are allowed to be 160 millisecond earlier than the last valid one. This limit is set with the `TIME_STAMP_JITTER` definition. If the accuracy flag is set, the time stamp will be allowed a jitter eight times as high, corresponding to 1.25 seconds by default.
- However, the systemic packets such as REGISTER_SUPER are not allowed any time stamp jitter because n2n relies on the actual sender's socket. A replay from another IP within any allowed jitter time frame would deviate the traffic which shall be prevented (even if it remains undecryptable). Under absolutely rare (!) circumstances, this might cause a re-registration requirement which happens automatically but might cause a small delay – security (including network availability) first! REGISTER packets from the local multicast environment are excempt from the very strict no-jitter requirement because they indeed regularily can show some deviation if compared to time stamps in packets received on the regular socket. As these packets are incoming on different sockets, their processing is more likely to no take place in the order these packets were sent.
- However, the systemic packets such as REGISTER_SUPER are not allowed any time stamp jitter because n2n relies on the actual sender's socket. A replay from another IP within any allowed jitter time frame would deviate the traffic which shall be prevented (even if it remains undecryptable). Under absolutely rare (!) circumstances, this might cause a re-registration requirement which happens automatically but might cause a small delay – security (including network availability) first! REGISTER packets from the local multicast environment are exempt from the very strict no-jitter requirement because they indeed regularly can show some deviation if compared to time stamps in packets received on the regular socket. As these packets are incoming on different sockets, their processing is more likely to no take place in the order these packets were sent.
The way the IV is used for replay protection and for checksumming makes enabled header encryption a prerequisite for these features.
@ -40,7 +40,7 @@ This command line can be put down as additional `ExecStartPost=` line (without `
### How to handle the error message "process_udp dropped a packet with seemingly encrypted header for which no matching community which uses encrypted headers was found"?
This error message means that the supernode is not able to identify a packet as unencrypted. It does check for a sane packet format. If it fails the header is assuemd encrypted (thus, "_seemingly_ encrypted header") and the supernode tries all communties that would make a key (some have already been ruled out as they definetly are unenecrypted). If no matching community is found, the error occurs.
This error message means that the supernode is not able to identify a packet as unencrypted. It does check for a sane packet format. If it fails the header is assumed encrypted (thus, "_seemingly_ encrypted header") and the supernode tries all communities that would make a key (some have already been ruled out as they definitely are unenecrypted). If no matching community is found, the error occurs.
If all edges use the same `-H` setting (all edges either with it or without it) and restarting the supernode does not help, most probably one of the components (an edge or the supernode) is outdated, i.e. uses a different packet format – from time to time, a lot of changes happen to the packet format in a very short period of time, especially in _dev_ branch.
@ -19,7 +19,7 @@ On the client side, the easiest way to configure routing is via the `-n` option.
10.0.0.1 is the IP address of the gateway to use to route the specified network. It should correspond to the IP address of the `server` within n2n. Multiple `-n` options can be specified.
As an alternative to the `-n` option, the `ip route` linux command can be manually used. See the [n2n_gateway.sh](doc/n2n_gateway.sh) script for an example. See also the follwing description of other use cases and in depth explanation.
As an alternative to the `-n` option, the `ip route` linux command can be manually used. See the [n2n_gateway.sh](doc/n2n_gateway.sh) script for an example. See also the following description of other use cases and in depth explanation.