SSLTunnel

SSLTunnel is a beautiful piece of software used to create an SSL/TLS VPN between two hosts, usually a client host and a VPN concentrator or server. Inside this tunnel, the traffic between the client and the server gets encapsulated inside PPP frames which are encapsulated inside the SSL/TLS tunnel. The tunnel itself is built using kernel PPP support, which materializes in the form of a ppp0 network interface.

SSLTunnel requires the following:

  • PPP daemon (tested with ppp-2.4.3-6)
  • PPP kernel support, like a ppp0 interface (minimally ppp_generic, ppp_async, ppp_deflate kernel modules)
  • OpenSSL (tested with openssl-0.9.8a-1)

This describes roughly how SSLTunnel works:

  • the server listens on port 443 of the destination machine
  • the client connects himself (if need be, through a relay like Squid, ISA-Server, the proxy does not have *ANY* mean to check if it is a navigator HTTPS Web server session, because the beginning of the not crypted session and the SSL negotiation are exactly identical)
  • at the establishment of the connection, the server forks
  • the server sends its certificate, the client checks that it is well signed by an authority it trusts
  • the client sends his certificate
  • the server checks this certificate and seeks if it corresponds to a certificate declared in its base
  • the crypted session starts
  • the server sends its banner with its version number and its protocol version
  • the client receives the banner, checks and sends his
  • the client forks, opens a pty, launches pppd in client mode on this pty, without specifying which IP address it wants
  • the server gets PPP parameters from the user file, changes its identity, opens a pty, forks and launches pppd on this pty with the options given by the file
  • the PPP session is established between the two ends, the program at each end cyphers/uncyphers and reads/sends the data in the pty connected to pppd.

Server

The following section describes how to get the source code for SSLTunnel, how to compile and patch it, how to configure it and how to set it up.

Server compilation

At the moment of this writing, the last stable version of SSLTunnel is 1.15, which can be obtained from here.

Before compiling the server components of SSLTunnel, I applied the following patch to SSLTunnel 1.15:

--- ssltunnel-1.15/server/main.c.old 2005-11-13 18:45:56.000000000 +0000 +++ ssltunnel-1.15/server/main.c 2005-11-13 18:29:14.000000000 +0000 @@ -796,7 +796,7 @@ ctx=SSL_CTX_new(meth); /* Load our keys and certificates*/ - if(!(SSL_CTX_use_certificate_chain_file(ctx, certfile))) + if(!(SSL_CTX_use_certificate_file(ctx, certfile, SSL_FILETYPE_PEM))) berr_exit("Can't read certificate file"); if(!(SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM)))

This patch essentially allows using a PEM-encoded X.509 certificate file for the server certificate instead of a PKCS#12-encoded chain of certificates, which eases the configuration and certificate generation a lot.

tar xvfz ssltunnel-.tar.gz
cd ssltunnel-
./configure --disable-client
make
make install

This will install the following files:

  • /usr/local/libexec/pppserver

    The VPN server daemon.

  • /usr/local/etc/ssltunnel/tunnel.conf

    pppserver configuration file.

  • /usr/local/etc/ssltunnel/tunnel.conf.default

    Default configuration file.

  • /usr/local/sbin/pppwho

    Used to query the utmp(3) file mantained by pppserver with the list of currently established tunnels.

Server certificate generation

Once the server components of SSLTunnel are built and installed, the pppserver certificate and its corresponding private key must be created. For information on how to create a CA using OpenSSL and generating server and client certificates, read Setting up Certificate Authority (CA) using OpenSSL.

Server configuration

The CA certificate will be installed as /usr/local/etc/ssltunnel/cacert.pem. The pppserver signed certificate will be installed as /usr/local/etc/ssltunnel/server.pem. The VPN private key will be installed as /usr/local/etc/ssltunnel/server.key and will be properly protected (0600 permission mask).

The pppserver configuration is stored in /usr/local/etc/ssltunnel/tunnel.conf, and should look like this:

keyfile        /usr/local/etc/ssltunnel/server.key
certfile       /usr/local/etc/ssltunnel/server.pem
cacertfile     /usr/local/etc/ssltunnel/cacert.pem
userfile       /usr/local/etc/ssltunnel/users
wtmp           /var/log/ssltunnel.wtmp
pidfile        /var/run/pppserver.pid
timeout        20
maxusers       10
port           443
#listenaddr    192.168.0.1,192.168.1.1
lockdir        /var/lock/ssltunnel

Following is a brief description of every configuration option:

  • keyfile points to the VPN server private key.
  • certfile points to the VPN server certificate.
  • cacertfile points to the CA certificate.
  • userfile points to the file that defines which users are allowed to request a tunnel to be established.
  • wtmp points to a utmp(3) file that is maintained by pppserver. This file stores information about currently established tunnels and can be queried by using the pppwho command.
  • pidfile points to the file that holds the PID of the currently pppserver daemon.
  • timeout defines how much time must be elapsed for a tunnel request to be declared unsatisfiable.
  • maxusers defines the maximum number of simultaneous tunnels that can be established.
  • port defines the port used by the SSL/TLS tunnel.
  • listenaddr is an optional comma-separated list of IP addresses that can be used to tell the VPN server which interfaces it should listen to.
  • lockdir points to the directory used to store pppserver locks.

Finally, the /usr/local/etc/ssltunnel/users file must be modified in order to declare which users should be recognized by pppserver and allowed to establish an SSL/TLS tunnel.

The format of this file consists of one or more user blocks, each one referencing a remote user and its related options. Each user block is separated from the following one by a blank line.

A user block consists of several options:

  • user

    The user option holds the X.509 distinguised name of the client certificate for which its owner is allowed to establish an SSL/TLS tunnel. The following command extracts the distinguised name from the X.509 client certificate:

    openssl x509 -nout -subject < client.cert

    For example:

    user /C=ES/O=felipe-alfaro.org/OU=IT/cn=Felipe Alfaro
  • fingerprint 

    The optional fingerprint option specifies the fingerprint for the client certificate associated with this user. It can be calculated with the following command:

    openssl x509 -noout -fingerprint < certificat_client

  • command

    The command option holds the path to the PPP daemon executable. This is usually /usr/sbin/pppd.

  • pty

    The pty option defines the pseudo-terminal number that will be used by the PPP daemon. This is usually 1.

  • args

    The args option defines the additional arguments that will be supplied when invoking the PPP server specified by the command option.

    At least one argument must be supplied to the PPP server. This argument defines the local IP address for the tunnel interface and the remote IP address for the tunnel interface, separated by a colon.

    For example, if the local IP address for the tunnel, on the VPN server machine, is 192.168.1.1, and the remote IP address for the tunnel, on the VPN client, is 192.168.1.2, the args option will look like this:

    args 192.168.1.1:192.168.1.2

  • uid
    gid

    Allows to change Unix identity before running pppd: permits to reduce the privileges. Attention, it will be necessary that used user and group have the right to run pppd! Obviously, that also implies that pppd is setuid root, so that it can set up routes, handle ARP table, etc.

    If these lines aren’t present, everything will be executed as root.

The resulting /usr/local/etc/ssltunnel/users file should look like this:

user /C=ES/O=felipe-alfaro.org/OU=IT/cn=Felipe Alfaro
command /usr/sbin/pppd
pty 1
args 192.168.1.1:192.168.1.2

user /C=ES/…

Server start

Once the configuration user files have been modified, the pppserver VPN server daemon can be started with the following command:

/usr/local/libexec/pppserver /usr/local/etc/ssltunnel/tunnel.conf

There should be a new process named pppserver. pppserver uses the syslog local6 facility to log errors, so in case the daemon does not start properly, check /var/log/messages to see why it failed to start.

Client

The following section enumerates the steps used to build, compile, configure and run the VPN client software.

Client compilation

Before building the client software, it is recommended to apply the following patch:

--- ssltunnel-1.15/client/main.c.old 2005-11-13 18:46:59.000000000 +0000 +++ ssltunnel-1.15/client/main.c 2005-11-13 18:38:47.000000000 +000 @@ -626,7 +626,7 @@ ctx=SSL_CTX_new(meth); /* Load our keys and certificates*/ - if(!(SSL_CTX_use_certificate_chain_file(ctx, certfile))) + if(!(SSL_CTX_use_certificate_file(ctx, certfile, SSL_FILETYPE_PEM))) berr_exit("Can't read certificate file"); if(!(SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM)))

This patch allows using a PEM-encoded certificate for the VPN client instead of a PKCS#12-encoded certificate chain, which makes things a lot easier.

The commands used to extract, build and install the VPN client are the following:

tar xvfz ssltunnel-.tar.gz
cd ssltunnel-
./configure --disable-server
make
make install

This will install the following files:

  • /usr/local/man/man5/ssltunnelrc.5

    The manual page for the VPN client configuration file.

  • /usr/local/man/man1/pppclient.1

    The manual page for the pppclientVPN client.

  • /usr/local/bin/pppclient

    The VPN client.

Client certificate generation

Once the client components of SSLTunnel are built and installed, the pppclient X.509 user certificate and its corresponding private key must be created. For information on how to generate the client certificate, read Setting up Certificate Authority (CA) using OpenSSL.

Client configuration

The CA certificate will be installed as /home/user/cacert.pem. The pppclient signed user certificate will be installed as /home/user/client.pem. The client private key will be installed as /home/user/client.key and will be properly protected (0600 permission mask).

The VPN client configuration file is usually stored in the /home/user/.stunnelrc, although it can be overridden when invoking pppclient, and should look like this:

verbose         1
remotehost      192.168.0.20
port            443
localppp        /usr/sbin/pppd
ipparam         tunnel
#bsdppp         0
#peer           tunnelserver
localproxyarp   0
#useproxy       0
#proxy          A.B.C.D
#proxyport      8080
#proxyuser      user
#proxypass      pass
localechoint    10
localechofail   10
localdebug      1
timeout         20
cacertfile      /home/user/cacert.pem
keyfile         /home/user/client.key
certfile        /home/user/client.pem
daemon          0
autoreconnect   0
logfile         /home/user/pppclient.log

Following is a brief description of every configuration option:

  • verbose, when set to 1, increases the level of verbosity. Setting it to 0 makes pppclient to be quiet.
  • remotehost specifies the IP address of the VPN server machine (the one running pppserver
  • port specifies the port used by pppserver to negotiate and establish the SSL/TLS tunnel.
  • localppp points to the PPP daemon executable.
  • ipparam specifies a tag which is passed to PPP to determine which configuration rules should be obeyed in order to set up routes, update ARP entries and so on.
  • bsdppp, when set to 1 specifies whether to use userland PPP support in *BSD.
  • peer defines which PPP peer to call as defined in /etc/ppp/peers/peer
  • localproxyarp, when set to 1 specifies that ARP proxying should be performed.
  • useproxy, when set to 1 specifies that the client must pass through a HTTP proxy before reaching the VPN server.
  • proxyport specifies the proxy port number, if any.
  • proxyuser specifies the username used to authenticate against the proxy server, if any.
  • proxypass specifies the password used to authenticate against the proxy server, if any.
  • localechoint defines the local echo internal, in seconds, used as a keepalive.
  • localechofail specifies the number of failed echo retries that would trigger the SSL/TLS tunnel down at the client.
  • localdebug, when set to 1 forces the PPP daemon to be launched in debug mode.
  • timeout the maximum amount of time used to established the SSL/TLS tunnel. If this time is exceeded, the VPN client will give up.
  • keyfile points to the VPN client private key.
  • certfile points to the VPN client certificate.
  • cacertfile points to the CA certificate.
  • daemon, when set to 1 request pppclient to daemonize itself and detach from the terminal.
  • autoreconnect, when set to 1 request pppclient to re-establish the tunnel if it is broken down by any unexpected reason.
  • logfile points to the log file where pppclient will log its errors or debug messages.

There is a sample pppclient file located inside the SSLTunnel source code, named client/tunnel.conf.

Client start

Once the pppclient configuration has been created, the pppclient VPN client daemon can be started with the following command:

/usr/local/bin/pppserver [optional path to configuration file]

The pppclient VPN client should chat like this with the VPN server:

22:52:47 Connecting to 192.168.0.20
22:52:47 Connected
22:52:48 SSL connect successful
22:52:48 Server version : 1.15
22:52:48 Server Protocol version : 1.0
22:52:48 forking ppp
22:52:48   45    45
22:52:48   46 < -----
22:52:51   45    96
22:52:51   17    17
22:52:51   66    21
22:52:51              ----->   21
22:52:51   21    89
22:52:00   89    13
22:52:01   13 < -----

To check the SSL/TLS tunnel has been set up by checking the state of the ppp0 network interface:

ppp0      Link ecanp:Point-to-Point Protocol
          inet addr:192.168.1.2  P-t-P:192.168.1.1  Mask:255.255.255.255
          UP POINTOPOINT RUNNING NOARP MULTICAST  MTU:1500  Metric:1
          RX packets:5 errors:0 dropped:0 overruns:0 frame:0
          TX packets:5 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:3
          RX bytes:66 (66.0 b)  TX bytes:72 (72.0 b)

If everything has gone right, it should be possible to ping our remote VPN peer:

ping 192.168.1.1

Acknowledgements

This document has been created based on the information contained in the README file from the SSL Tunnel documentation.

4 thoughts on “SSLTunnel

  1. Hi,
    Really appreciated your tutorial. But can’t fix routes on client.
    Indeed, got this :
    Destination Passerelle Genmask Indic Metric Ref Use Iface
    192.168.1.1 * 255.255.255.255 UH 0 0 0 ppp0

    with no way of pinging interface on other side (192.168.1.1). I feel it’s because of netmask (255.255.255.255) instead of 255.255.255.0 but even by modifiying routes (deletion of existing one and manual creation of new one with appropriate netmask), doesn’t work. I really feel desesparated. Please help o/
    Thx in adv.

  2. The netmask 255.255.255.255 means that route is a host route, or said in a different way, that particular route is meant to reach a single host (and not a network).

    The route looks okay to me. It means that in order for an IP datagram to reach host 192.168.1.1, it has to go over the ppp0 interface. The ppp0 interface should be properly configured as a point-to-point interface. Use ifconfig ppp0 to show what the local IP and the remote (peer) IP addresses are for ppp0. The ppp0 point-to-point interface will take the IP datagram it receives, wrap around PPP, then again over SSL/TCP/IP and send the resulting datagram to its peer. So, make sure ppp0 has the correct peer configured and that the peeri is reachable and does not discard either PPP or SSL (port 443) traffic.

  3. So who’s working on the parabolic microphone version (just aim it at someone’s pocket from 1/2 mile away)? We need an excuse to recycle the plastic and go back to cash, right?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s