Fork me on GitHub



What is SSF?

Secure Socket Funneling (SSF) is a network tool and toolkit.
It provides simple and efficient ways to forward data from multiple sockets (TCP or UDP) through a single secure TLS link to a remote computer.

Motivations

The initial aim of SSF was to provide an easy way for users and developers to multiplex and demultiplex various network data flows. It was designed to:

  • be cross platform (Windows XP-10, Linux, OS X, Raspberry Pi)
  • be lightweight and standalone
  • be easily extensible
  • provide modern (TLS 1.2) secure point-to-point communication with the strongest cipher-suites
  • provide high performance communications using the benefits of modern multi-core / multi-threaded architecture

These requirements excluded SSH which showed limitations on all items (particularly in performance, but also by the lack of server side application on Windows). Classic VPN software was also excluded because the requirement of administrator rights was too limiting.

Specific features

  • One feature which was not present in any another equivalent network tool was UDP forwarding. UDP is nonetheless widely used in real-time services (VoIP, online gaming, ...) and for DNS. Therefore, SSF is able to forward both TCP and UDP from the client to the server (options -L and -U) as well as from the server to the client (options -R and -V)

  • SSF also allows dynamic port forwarding with a SOCKS server from the client to the server (option -D just like SSH) and from the server to the client (option -F which SSH does not allow)

  • Basic shell support on Windows (cmd or Powershell), Linux and OS X. This feature must be activated on client or server prior to use. This is the first draft and we plan to improve it over time. Feel free to contribute!

  • The circuit feature simply allows to forward the traffic from one point to another, through a list of intermediary relay servers

DevOps friendly

SSF command-line was designed as a drop-in replacement for SSH (on equivalent features, such as port forwarding or SOCKS), so that you can benefit of the performance and security gain with minimal - or even, not a single - update for your scripts and tools.

How to configure SSF

SSF provides a simple way to route an SSF connection between a client and a server through a list of SSF relay servers without protocol or cryptographic overhead. At this point, the traffic is decrypted as it is received by a relay and re-encrypted to be sent to the next relay or final destination. This means that the data will be encrypted between each relay but will transit unencrypted on the relay itself. It is therefore essential that the relay servers be secure and controlled by the owner of the data.

If users were to express the need, future versions could add a second cryptographic layer between the client and the destination server so that the data remained encrypted by this layer on every relay.

Required files

With default options, the following files and folders should be in the directory of execution of a client or a server (see the Security features section if you do not know how to generate them):

  • ./certs/dh4096.pem
  • ./certs/certificate.crt
  • ./certs/private.key
  • ./certs/trusted/ca.crt

Where :

  • dh4096.pem contains the Diffie-Hellman parameters needed for the establishment of session keys
  • certificate.crt and private.key are the certificate and the private key of the SSF server or client
  • ca.crt is the concatenated list of root certificates trusted by the SSF server or client
The certificate and the private key should be unique to each SSF client or server.

Moreover, a client will be able to connect to a server if two conditions are fulfilled:

  • One of the certification authority which signed the server certificate is present in the trusted list of the client
  • One of the certification authority which signed the client certificate is present in the trusted list of the server

In order to customize the paths and file names, the command line accepts a configuration file option -c.
An example is given below.

Configuration file

The configuration file is JSON format file in which several options can be specified. At this point, only security options relative to TLS use can be customized. See below an example of configuration file. For more information about TLS and SSF security see the Security features section.

{
  "ssf": {
    "arguments": "",
    "circuit": [],
    "tls" : {
      "ca_cert_path": "./certs/trusted/ca.crt",
      "cert_path": "./certs/certificate.crt",
      "key_path": "./certs/private.key",
      "key_password": "",
      "dh_path": "./certs/dh4096.pem",
      "cipher_alg": "DHE-RSA-AES256-GCM-SHA384"
    },
    "http_proxy" : {
      "host": "",
      "port": "",
      "user_agent": "",
      "credentials": {
        "username": "",
        "password": "",
        "domain": "",
        "reuse_ntlm": "true",
        "reuse_nego": "true"
      }
    },
    "services": {
      "datagram_forwarder": { "enable": true },
      "datagram_listener": {
        "enable": true,
        "gateway_ports": false
      },
      "stream_forwarder": { "enable": true },
      "stream_listener": {
        "enable": true,
        "gateway_ports": false
      },
      "copy": { "enable": false },
      "shell": {
        "enable": false,
        "path": "/bin/bash|C:\\windows\\system32\\cmd.exe",
        "args": ""
      },
      "socks": { "enable": true }
    }
  }
}
arguments
use configuration arguments instead of given CLI arguments
circuit
relay chain servers used to establish the connection to the remote server
tls.ca_cert_path
relative or absolute path to the CA certificate file
tls.cert_path
relative or absolute path to the instance certificate file
tls.key_path
relative or absolute path to the private key file
tls.key_password
the password protecting the private key (if any)
tls.dh_path
relative or absolute path to the Diffie-Hellman file
tls.cipher_alg
List of allowed SSL cipher suite (see OpenSSL documentation for more information)
http_proxy.host
HTTP proxy host
http_proxy.port
HTTP proxy port
http_proxy.user_agent
User agent in CONNECT request
http_proxy.credentials.username
proxy username credentials
http_proxy.credentials.password
proxy password credentials
http_proxy.credentials.domain
user domain (NTLM and Negotiate auth on Windows only)
http_proxy.credentials.reuse_ntlm
reuse current computer user credentials to authenticate with proxy NTLM auth (SSO)
http_proxy.credentials.reuse_kerb
reuse current computer user credentials (Kerberos ticket) to authenticate with proxy Negotiate auth (SSO)
services.*.enable
enable/disable local microservice
services.*.gateway_ports
enable/disable gateway ports
services.shell.path
binary path used for process creation
services.shell.args
binary arguments used for process creation

For an SSF server, if the private key is encrypted but no password was provided with the configuration file, all connections will fail.
However, for an SSF client, a password prompt will be presented to the user. It will give him the opportunity to enter the password, if needed.

Microservices

SSF is using microservices to build its features (TCP forwarding, remote SOCKS, ...) There are 7 microservices:

  • stream_forwarder
  • stream_listener
  • datagram_forwarder
  • datagram_listener
  • copy
  • socks
  • shell
Each feature is the combination of at least one client side microservice and one server side microservice.
This table sums up how each feature is assembled:

ssf feature microservice client side microservice server side
-L: TCP forwarding stream_listener stream_forwarder
-R: remote TCP forwarding stream_forwarder stream_listener
-U: UDP forwarding datagram_listener datagram_forwarder
-V: remote UDP forwarding datagram_forwarder datagram_listener
-D: SOCKS stream_listener socks
-F: remote SOCKS socks stream_listener
-X: shell stream_listener shell
-Y: remote shell shell stream_listener

This architecture makes it easier to build remote features: they use the same microservices but on the opposite side.
ssf and ssfd come with pre-enabled microservices. Here is the default microservices configuration:

"ssf": {
  "services": {
    "datagram_forwarder": { "enable": true },
    "datagram_listener": { "enable": true },
    "stream_forwarder": { "enable": true },
    "stream_listener": { "enable": true },
    "socks": { "enable": true },
    "copy": { "enable": false },
    "shell": { "enable": false }
  }
}

To enable or disable a microservice, set its enable option to true or false.
Trying to use a feature requiring a disabled microservice will result in an error message.

How to use the command line

Standard command line options

Client command line

  ssf[.exe] [OPTION...] server_address

  -h, --help                    Show help message
  -v, --verbosity arg           Verbosity:
                                critical|error|warning|info|debug|trace (default: info)
  -q, --quiet                   Do not print logs
  -c, --config arg              Specify configuration file. If not set,
                                'config.json' is loaded from the current working
                                directory
  -p, --port arg                Remote port (default: 8011)
  -m, --max-connect-attempts arg
                                Max unsuccessful connection attempts before
                                stopping (default: 1)
  -t, --reconnect-delay arg     Time to wait before attempting to reconnect
                                (default: 60)
  -n, --no-reconnect            Do not attempt to reconnect after loosing a
                                connection
  -g, --gateway-ports           Enable gateway ports
  -S, --status                  Display microservices status

 Services options:
  -Y, --remote-shell [bind_address:]port
                                Enable remote shell service
  -F, --remote-socks [bind_address:]port
                                Enable remote SOCKS service
  -R, --remote-tcp-forward [bind_address:]port:remote_host:remote_port
                                Enable remote TCP port forwarding service
  -V, --remote-udp-forward [bind_address:]port:remote_host:remote_port
                                Enable remote UDP port forwarding service
  -X, --shell [bind_address:]port
                                Enable client shell service
  -D, --socks [bind_address:]port
                                Enable client SOCKS service
  -L, --tcp-forward [bind_address:]port:remote_host:remote_port
                                Enable client TCP port forwarding service
  -U, --udp-forward [bind_address:]port:remote_host:remote_port
                                Enable client UDP port forwarding service

Server command line

  ssfd[.exe] [OPTION...]

  -h, --help              Show help message
  -v, --verbosity arg     Verbosity: critical|error|warning|info|debug|trace
                          (default: info)
  -q, --quiet             Do not print logs
  -c, --config arg        Specify configuration file. If not set,
                          'config.json' is loaded from the current working directory
  -p, --port arg          Local port (default: 8011)
  -R, --relay-only        The server will only relay connections
  -l, --bind-address arg  Server bind address
  -g, --gateway-ports     Enable gateway ports
  -S, --status            Display microservices status

Examples

For instance, this command line will start SSF as a server on default port 8011:

./ssfd

And this command will connect SSF client to the server listening on localhost and port 8011 and start a SOCKS server listening on port 10000 of the client side:

./ssf -D 10000 127.0.0.1

Copy command line options

  ssfcp[.exe] [options] [host@]/absolute/path/file [[host@]/absolute/path/file]

  -h, --help           Show help message
  -v, --verbosity arg  Verbosity: critical|error|warning|info|debug|trace
                       (default: info)
  -q, --quiet          Do not print logs
  -c, --config arg     Specify configuration file. If not set, 'config.json'
                       is loaded from the current working directory
  -p, --port arg       Remote port (default: 8011)

 Copy options:
  -t, --stdin-input        Use stdin as input
      --resume             Attempt to resume operation if the destination
                           file exists
      --check-integrity    Check file integrity
  -r, --recursive          Copy files recursively
      --max-transfers arg  Max transfers in parallel (default: 1)

Examples

Copy local files to remote directory

This command will copy the file /tmp/test.txt in the remote directory D:\test of server 10.0.0.1

ssfcp /tmp/test.txt 10.0.0.1@D:/test

This command will copy all local files matching the pattern /tmp/test*.txt in the remote directory D:\test of 10.0.0.1

ssfcp /tmp/test*.txt 10.0.0.1@D:/test

Copy client stdin into remote file

This command will pipe the resulting archive into the file D:\test\test.tar of 10.0.0.1

tar cf - /tmp/test | ssfcp -t 10.0.0.1@D:/test/test.tar

Copy remote files to local directory

This command will copy the file D:/test/test.txt of 10.0.0.1 into the local directory /tmp

ssfcp 10.0.0.1@D:\test\test.txt /tmp

This command will copy all files of 10.0.0.1 matching D:/test/test*.txt into the local directory /tmp

ssfcp 10.0.0.1@D:/test/test*.txt /tmp

How to use the relay servers (the bouncing feature)

SSF provides a simple way to route SSF connection between a client and a server through a list of SSF relay servers without protocol or cryptographic overhead. At this point, the traffic is decrypted as it is received by a relay and re-encrypted to be sent to the next relay or final destination.

New 2.1.0
A second cryptographic layer between the client and the destination server is added.



Circuit configuration

The circuit is a JSON array containing the circuit servers and ports which will be used to establish the connection. They are listed as follow:

{
  "ssf": {
    "circuit": [
      {"host": "SERVER1", "port":"PORT1"},
      {"host": "SERVER2", "port":"PORT2"},
      {"host": "SERVER3", "port":"PORT3"}
    ]
  }
}

For the configuration above, the relay chain will be CLIENT <-> SERVER1:PORT1 <-> SERVER2:PORT2 <-> SERVER3:PORT3 <-> DESTINATION

Example

In this example, a client located in the 10.0.1.* subnet wants to connect to the SSF server on 10.0.6.1:5000. However for this example, firewalls will only allow each subnet to communicate with the next one through a single address. For instance, in a subnet A.B.C.*, only A.B.C.1 can communicate with A.B.C-1.* and A.B.C+1.*. Therefore, to reach 10.0.6.1, the client has to go through 10.0.1.1, 10.0.2.1, ... and 10.0.6.1.

  • It is expected that a server is running on each of the six addresses on port 5000 using a command line similar to:
    ./ssfd -p 5000
  • Use the following configuration file config.json:
    {
      "ssf": {
        "circuit": [
          {"host": "10.0.1.1", "port":"5000"},
          {"host": "10.0.2.1", "port":"5000"},
          {"host": "10.0.3.1", "port":"5000"},
          {"host": "10.0.4.1", "port":"5000"},
          {"host": "10.0.5.1", "port":"5000"}
        ]
      }
    }
  • Connect the client to 10.0.6.1:5000 through all the relay servers using the following command line:
    ./ssf -c config.json -p 5000 10.0.6.1

How to use the SOCKS feature

Local SOCKS

The SSF client -D port option opens the given port on the SSF client machine and forward SOCKS requests to the SSF target server.
The SSF server will act as the SOCKS server.



Remote SOCKS

The SSF client -F port option opens the given port on the SSF target server machine and forward SOCKS requests to the SSF client.
The SSF client will act as the SOCKS server.



Command line

No circuit feature

  • Launch SSF_SERVER on a port (10000 in this example)
    ./ssfd -p 10000
  • Connect the SSF client to the SSF server, initialize a SOCKS server on the SSF server side and open port 9000 on the SSF client side to communicate to the SOCKS server
    ./ssf -D 9000 -p 10000 127.0.0.1
    Use -F instead of -D to have the SOCKS server on the SSF client side and open the port 9000 on the SSF server side

With circuit feature

  • Launch SSF_SERVER_1 on a port (10000 in this example)
    ./ssfd -p 10000
  • Launch SSF_SERVER_2 on a port (10001 in this example)
    ./ssfd -p 10001
  • Create the configuration file config.json
    {
      "ssf": {
        "circuit": [
          {"host": "10.0.0.1", "port":"10000"}
        }
      }
    }
    
    The client will connect to SSF_SERVER_2 with one hop on SSF_SERVER_1
  • Connect the SSF client to SSF_SERVER_2 with one hop, initialize a SOCKS server on SSF_SERVER_2 and open port 9000 on SSF client side to communicate to SOCKS server
    ./ssf -c config.json -D 9000 -p 10001 127.0.0.1
    Use -F instead of -D to have the SOCKS server on the SSF client side and open the port 9000 on the SSF_SERVER_2 side

How to use the TCP port forwarding feature

No circuit feature

  • Launch the SSF server on a port (10000 in this example)
    ./ssfd -p 10000
  • Connect the SSF client to the SSF server
    ./ssf -L 9000:127.0.0.1:80 -p 10000 127.0.0.1
    Use -R instead of -L to forward to the the SSF client side and open the port 9000 on the SSF server side

With circuit feature

  • Launch SSF_SERVER_1 on a port (10000 in this example)
    ./ssfd -p 10000
  • Launch SSF_SERVER_2 on a port (10001 in this example)
    ./ssfd -p 10001
  • Create the configuration file config.json
    {
      "ssf": {
        "circuit": [
          {"host": "127.0.0.1", "port":"10000"}
        }
      }
    }
    
    The SSF client will connect to SSF_SERVER_2 with one hop on SSF_SERVER_1
  • ./ssf -c config.json -L 9000:127.0.0.1:80 -p 10001 127.0.0.1
    Use -R instead of -L to forward to the SSF client side and open the port 9000 on the SSF_SERVER_2 side

How to use the UDP port forwarding feature

No circuit feature

  • Launch the SSF server on a port (10000 in this example)
    ./ssfd -p 10000
  • Connect the SSF client to the SSF server
    ./ssf -U 9000:127.0.0.1:80 -p 10000 127.0.0.1
    Use -V instead of -U to forward to the SSF client side and open the port 9000 on the SSF server side

With circuit feature

  • Launch SSF_SERVER_1 on a port (10000 in this example)
    ./ssfd -p 10000
  • Launch SSF_SERVER_2 on a port (10001 in this example)
    ./ssfd -p 10001
  • Create the configuration config.json
    {
      "ssf": {
        "circuit": [
          {"host": "127.0.0.1", "port":"10000"}
        }
      }
    }
    
    The SSF client will connect to SSF_SERVER_2 with one hop on SSF_SERVER_1
  • ./ssf -c config.json -U 9000:127.0.0.1:80 -p 10001 127.0.0.1
    Use -V instead of -U to forward to the SSF client side and open the port 9000 on the SSF_SERVER_2 side

How to use SSF shell

SSF provides basic shell support on Windows, Linux and OS X with -X and -Yoptions.
Default shell is cmd.exe on Windows and /bin/bash on Linux or OS X. The shell is fully configurable by modifying ssf.services.shell configuration file section (e.g. you can set Powershell as the default shell on Windows, see below).

The shell feature of SSF is quite different from SSH at the moment. Instead of having direct interaction with a shell instance, SSF shell option will open a listening TCP socket locally (-X) or instruct the server to open one remotely (-Y). Each connection to that socket will then launch a shell on the other side with its I/O forwarded.

Shell microservice must be enabled prior to use (configuration file)

{
    "ssf": {
        "services": {
            "shell": {
                "enable": true
            }
        }
    }
}
-X option will require the shell microservice to be enabled on the server
-Y option will require the shell microservice to be enabled on the client

This is the first draft and we plan to improve it over time. Actually, you may have some ideas to improve this feature so feel free to suggest or even implement them. We will be honored to review and accept pull requests.

Example

  • Launch server on ssf.example.com
    ./ssfd
  • Connect client to server
    ./ssf -X 10000 -Y 11000 ssf.example.com
    -X: client opens a listening socket on the given port (10000). Each connection to that socket (using netcat for example) will launch a shell on the server side.
    -Y: client orders the server to open a listening socket on the given port (11000). Each connection to that socket (using netcat for example) will launch a shell on the client side.
    I/O are forwarded through the SSF tunnel from/to the shell instance.
  • You need to take into consideration some issues such as double echoing (both client and server display your input) or control command interpretation. We will provide a better way to handle this in a future version.
    Here are some workarounds according to your use case:
    • Interact with Linux or OS X shell: if you are using netcat in bash, you must change some options of the current terminal device with stty before establishing a connection:
      stty -echo -icanon -isig min 1
      -echo
      disable local echo
      -icanon
      disable canonical input
      -isig
      disable checking of special control characters (e.g. CTRL+C, CTRL+D)
      min 1
      read and process one character at a time
      All special interpretations will be done by the remote shell (TAB, CTRL+C, CTRL+D, etc.). After use, do not forget to reactivate terminal options device. Here is a oneliner:
      stty -echo -icanon -isig min 1; nc 127.0.0.1 10000; stty echo icanon isig;
    • Interact with Windows shell: if you are using netcat in bash, you can disable checking of control characters. Special characters sequence (TAB, UP, etc.) are disabled. We are still looking for a solution for setting the character input mode. Input will be processed one line at a time and you will notice double echoing.
      stty -isig; nc 127.0.0.1 10000; stty isig;
      If you are facing encoding issue (e.g. occidental accent), you may set your terminal encoding as Occidental (IBM850) on Ubuntu or Western (DOS Latin1) on OS X.

Set Powershell as the default shell on Windows

Here is a configuration file example for setting Powershell as the default shell on Windows platform:

{
    "ssf": {
        "services": {
            "shell": {
                "enable": true,
                "path": "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe",
                "args": "-File -"
            }
        }
    }
}
ssf.services.shell.enable
true to activate local shell microservice
ssf.services.shell.path
Powershell binary path. Modify the path according to your system.
ssf.services.shell.args
Powershell binary arguments. -File - is required for redirecting SSF I/O to stdin/stdout Powershell process.

Login user at connection on Linux or OS X

Client or server must be run as superuser

login can be used to login user on connection. Here is an example for setting it instead of /bin/bash:

{
    "ssf": {
        "services": {
            "shell": {
                "enable": true,
                "path": "/bin/login"
            }
        }
    }
}
ssf.services.shell.path
Login binary path. Modify the path according to your system (e.g. /bin/login on Ubuntu/Debian, /usr/bin/login on OS X).

How to copy file

Command line

ssfcp[.exe] [-c config_file] [-p port] [-t] [-r] [--resume] [--check-integrity] [--max-transfers arg] [host@]/absolute/path/file [[host@]/absolute/path/file]
-c config_file
config_file is the file containing configuration for SSF (TLS configuration)
-p port
port is the port of the remote SSF server
-t
input data from stdin
-r
recursive copy
--resume
try to resume file copy
--check-integrity
check file integrity after copy
--max-transfers arg
Max transfers in parallel (default: 1)

ssfcp is cross platform and its syntax is similar to scp command.
The main difference resides in the separator between host and path: @ for ssfcp instead of :

Since ssfcp is part of SSF framework, it is also fully compatible with the relay servers feature.

From Linux to Linux

Local to remote

This command will copy the file /home/doe/test.txt into the remote directory /tmp/test_dir of server 10.0.0.1

ssfcp /home/doe/test.txt 10.0.0.1@/tmp/test_dir

Local globbing to remote

This command will copy all local files matching /home/doe/*.txt into the remote directory /tmp/test_dir of server 10.0.0.1

ssfcp /home/doe/*.txt 10.0.0.1@/tmp/test_dir

stdin to remote

This command will send the tar archive of /tmp/test through client stdin into the remote file /tmp/test_dir/test.tar of server 10.0.0.1

tar cf - /tmp/test | ssfcp 10.0.0.1@/tmp/test_dir/test.tar

Remote to local

This command will copy the remote file /home/doe/test.txt of 10.0.0.1 into the local directory /tmp/test_dir

ssfcp 10.0.0.1@/home/doe/test.txt /tmp/test_dir

From Windows to Linux

Local to remote

This command will copy the file D:\test.txt into the remote directory /tmp/test_dir of server 10.0.0.1

ssfcp.exe D:/test.txt 10.0.0.1@/tmp/test_dir

Local globbing to remote

This command will copy all local files matching D:\*.txt into the remote directory /tmp/test_dir of server 10.0.0.1

ssfcp.exe D:/test.txt 10.0.0.1@/tmp/test_dir

stdin to remote

This command will send the tar archive of D:\test through client stdin into the remote file /tmp/test_dir/test.tar of server 10.0.0.1

tar.exe cf - D:/test | ssfcp.exe 10.0.0.1@/tmp/test_dir/test.tar

Remote to local

This command will copy the remote file D:\test.txt of 10.0.0.1 into the local directory /tmp/test_dir

ssfcp 10.0.0.1@D:/test.txt /tmp/test_dir

From Windows to Windows

Local to remote

This command will copy the file D:\test.txt into the remote directory E:\test_dir of server 10.0.0.1

ssfcp.exe D:/test.txt 10.0.0.1@E:/test_dir

Local globbing to remote

This command will copy all local files matching D:\*.txt into the remote directory E:\test_dir of server 10.0.0.1

ssfcp.exe D:/*.txt 10.0.0.1@E:/test_dir

stdin to remote

This command will send the tar archive of D:/test through client stdin into the remote file E:/test_dir/test.tar of server 10.0.0.1

tar.exe cf - D:/test | ssfcp.exe 10.0.0.1@E:/test_dir/test.tar

Remote to local

This command will copy the remote file D:/test.txt of 10.0.0.1 into the local directory E:/test_dir

ssfcp.exe 10.0.0.1@D:/test.txt E:/test_dir

How to browse the web securely and privately from everywhere

You are in a coffee shop or an hotel

and you are connected to its wifi network. You do not trust this connection or don't want the hotel's proxy / router or guy next to you to know what web page you visit.

You will need two things:

  • the server side: running, connected to Internet (for example, your home machine, running Windows, or Linux, or Mac)
  • the client side: running on your laptop when you want to browse Internet while being locally connected to an untrusted network (e.g. public wifi networks)



Configuring the server side (e.g. your home machine, up and running, connected to internet, even when you are not at home)

./ssfd -p port 10000

Now, your home server is listening on port 10000, and is waiting for an authenticated client. For this example, let's say that the public IP address of your server is "SERVER_IP"

Configuring the client side (e.g. your laptop): the simple way

./ssf -D 9000 -p 10000 SERVER_IP

Simply run this command, and configure your browser (firefox, IE, Chrome, Safari...), to use a socks server on address 127.0.0.1 port 9000

This command uses -D (server side socks resolution) option.

Advanced : Secure DNS resolution

./ssf -D 9000 -U 53:208.67.222.222:53 -p 10000 SERVER_IP

Someone in the wifi network could fake DNS resolution, and redirect you to malicious websites.

Change your DNS interface settings to 127.0.0.1, and, thanks to this command, every DNS request will go througt the secure SSF funnel, and public OpenDNS DNS server (208.67.222.222) will resolve them.
No DNS request will leak on the network (wifi) you're connected to, and from DNS server view (OpenDNS provider for this example), it's your Server (SERVER_IP) that is making the DNS request.

This command combines both -D (server side socks) and -U (UDP forward) options. OpenDNS DNS server is given as an example. You could use any DNS server

Coffee shop firewall restrictions

Sometimes, public Wifi uses firewall restrictions to allow only web-related outgoing port (generaly 80-http, or 443-https).

To comply with these restrictions and be able to browse securely using SSF, you should setup the SSF server to listen on port 80 or 443 (instead of 10000 in the basic example)

Binding SSF on a port below 1024 (e.g. 53, 80 or 443) will require administrative privileges. But as long as SSF runs on a machine that you control, this should not be an issue.

Download SSF

Archive content

  • Executables: ssfd, ssf, ssfcp
  • UPXed executables: upx-ssfd, upx-ssf, upx-ssfcp
  • Test certificates ( testing purpose only)

Version history

FAQ

Contact
You can post requests, feedback or issues in the Github repository.
You can also contact us more directly: ssf.developer [at] gmail [dot] com
Build issues
Send us your compilation logs and your build machine information (OS, Boost, OpenSSL and GTest version).
The project compilation is tested against Visual Studio 2013-2015 (32/64 bits), gcc >= 4.8.4 (32/64 bits) and OS X 10.10 with Xcode 6.4 (64bits). It requires C++ compiler which supports C++11 features.
Execution issues
Send us your use case and your application logs. We will try to reproduce it and provide a fix or a workaround.

Security features

TLS usage

SSF is based on Boost.Asio for all its networking and it uses Asio wrapper for OpenSSL. TLS connections support only certificate authentication and enforce mutual authentication.

TLS options

The following TLS options are hardcoded (see OpenSSL documentation for more information):

  • Connection fails in case of absence of certificate from a peer
  • No SSLv1, v2 or v3 and no TLSv1.0 or v1.1 therefore forcing TLSv1.2
  • Reuse of Diffie-Hellman is forbidden
  • No ticket extension allowed

TLS cipher suggestions

The default cipher suite used in SSF is DHE-RSA-AES256-GCM-SHA384

However, the configuration file allows for any SSL cipher suite usage (see the Configuration section to know how). Here are the guidelines which led to the choice of this cipher:

  • Use ephemeral Diffie-Hellman to ensure perfect forward secrecy. Indeed, in that case, public and private keys will only be used for authentication and a new key will be negotiated independently for each connection. Therefore, even if a user private key of a user gets compromised at some point, the previous communications remain secure.
  • Avoid elliptic curves to avoid fishy NIST curves. Therefore, RSA is used for authentication.
  • Use a strong symmetric algorithm in it strongest version. Most computers now have more than enough computing power to support AES256 (especially with AES ASM instructions) so why not use it?
  • Use a block cipher mode which both guaranty confidentiality and integrity: GCM mode.
  • Use a strong hashing function: SHA384.

Generate your own cryptographic elements

Cryptographic suggestions

It might be wise to protect private keys with passphrases, especially on client sides. On the server side, the passphrase will have to be specified in the configuration file (see the Configuration section to know how). However, with a client, if the passphrase is needed and not specified in a configuration file, the user will be prompted to enter the passphrase manually.

Here is the command to encrypt an unencrypted RSA private key with the passphrase "passphrase":

openssl rsa -in private.key -out private.key -aes256 -passout pass:passphrase

Here is the command to change the passphrase of an encrypted RSA private key from "passphrase" to "new_passphrase":

openssl rsa -in private.key -out private.key -aes256 -passin pass:passphrase -passout pass:new_passphrase

Here is the command to remove the passphrase of an encrypted RSA private key with passphrase equal to "passphrase":

openssl rsa -in private.key -out private.key -passin pass:passphrase

Generate elements for TLS connections

In order to use SSF, it will be necessary to generate private keys, certificates and Diffie-Hellman parameters:

Generating Diffie-Hellman parameters

openssl dhparam 4096 -outform PEM -out dh4096.pem

Generating a self-signed Certification Authority (CA) ca.crt and its private key ca.key

openssl req -x509 -nodes -newkey rsa:4096 -keyout ca.key -out ca.crt -days 3650

Then, create a file named extfile.txt containing the following lines:

[ v3_req_p ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment

[ v3_ca_p ]
basicConstraints = CA:TRUE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment, keyCertSign

It will permit to create intermediary CA if needed.

Generating an intermediary CA (ca_int.crt, ca_int.key) signed with a CA (ca.crt, ca.key)

First, generate a private key ca_int.key and a signing request ca_int.csr:

openssl req -newkey rsa:4096 -nodes -keyout ca_int.key -out ca_int.csr

Then, sign with the CA (ca.crt, ca.key) the signing request to get the intermediary CA certificate ca_int.crt:

openssl x509 -extfile extfile.txt -extensions v3_ca_p -req -sha1 -days 3650 -CA ca.crt -CAkey ca.key -CAcreateserial -in ca_int.csr -out ca_int.crt
cat ca.crt >> ca_int.crt

Generating a private key private.key and its certificate certificate.cst signed with a CA ca.crt

First, generate a private key private.key and a signing request certificate.csr:

openssl req -newkey rsa:4096 -nodes -keyout private.key -out certificate.csr

Then, sign with the CA (ca.crt, ca.key) the signing request to get the certificate certificate.crt:

openssl x509 -extfile extfile.txt -extensions v3_req_p -req -sha1 -days 3650 -CA ca.crt -CAkey ca.key -CAcreateserial -in certificate.csr -out certificate.crt
cat ca.crt >> certificate.crt

Perfomances

The goal with SSF was to provide a high performance network tool so it could be used on high bandwidth links.

When testing OpenSSH to establish a secure link between two servers over a low latency gigabit Ethernet connection, the bandwidth of a TCP tunnel was limited to about 125 Mbits/s.

SSF, with all its default configurations (including a higher security cipher suite than OpenSSH), reached 600 Mbits/s. It seems that the limitation comes from the underlying cryptographic library (OpenSSL). Indeed, when compiled with the special flag FORCE_TCP_ONLY, the gigabit Ethernet link was saturated.

Test typology

  • Low latency gigabit Ethernet connection
  • Two servers and one client running on different computers (>Intel Core i7-3770T, >16GB DDR3)
  • Client establishes a TCP port forwarding to the second server passing through the first server
  • Receive and send random data through the forwarding link during 5 minutes

Developer corner

C++

SSF is implemented using C++11 to support a wider range of standard compilers (e.g. Visual Studio 2015, g++-4.9 for Ubuntu 16.04). As soon as C++14, and later C++17 are easily accessible (native/default) on every build platforms, the code will be updated to evolve with these standards.

SSF relies on the Boost libraries, especially Asio, and was designed to be extended. A special effort was made to ease the build process: CMake is used to generate any dev environment (ex: Visual Studio, XCode, Make...). The building process for third party libraries (Boost, OpenSSL, GoogleTest) is made easy with custom scripts. SSF also comes with a set of unit tests so that you can fork and tweak the code, and test your changes easily.

Extensible microservice framework and toolkit

The features of SSF framework are designed as microservices, allowing an easy integration of new functionalities. Checkout the documentation to know how to add your own custom features. SSF networking is based on Boost.Asio and provide objects with an Asio compliant interface. This aspect will be extended in a near future to provide a wide network toolkit (still based on Asio) permitting to quickly and easily design complex network protocols and communications.

Contribute

Do not hesitate to fork, emit requests or fill issues using GitHub.

About the project

SSF is developed and maintained by two Belgians C++ enthusiasts which care about security and performances.

We think that OpenSource is the right way to make the project evolve in its next generation.

Do not hesitate to post any requests, feedback or issues in the Github repository. We will be glad to answer and make this project better.

To contact us more directly: ssf.developer [at] gmail [dot] com