Mac OS X VPN and static routing

Problem

The VPN client built into Mac OS X has a checkbox saying “Send all traffic over VPN connection”. Turning this on causes all traffic to get routed over the VPN. Turning this off means that only the VPN IP block will get routed over the VPN. If there are additional IP networks behind the VPN gateway, they won’t be reachable unless you manually add static routes.

Solution

Mac OS X uses a program called pppd to negotiate a point-to-point connection. pppd is in charge of performing mutual authentication and creating a ppp network interface. pppd is used, at least, by PPTP and L2TP over IPSec VPNs in Mac OS X.

When a PPP connection is established, the pppd program will look for a script named /etc/ppp/ip-up and, if it exists and is executable, will run it. This file does not exist in a default, clean installation of Mac OS X, but it can easily be created and customized to add static routes whenever a VPN connection is established,

When pppd executes this script, it passes several pieces of information onto the command line. The following sample script describes them:

$ cat /etc/ppp/ip-up
#!/bin/sh
#
# This script is called with the following arguments:
#
# $2: VPN interface name (e.g. ppp0)
# $3: 0
# $4: local VPN address (e.g. 10.0.0.1)
# $5: remote VPN gateway (e.g. 10.255.255.0)
# $6: local gateway used to reach the remote VPN gateway
#
# Example:
#
# $ ifconfig ppp0
# ppp0: flags=8051 mtu 1280
#  inet 10.0.0.1 --> 10.255.255.0 netmask 0xfffffc00 

if [ "$5" = "10.255.255.0" ]; then
  # Add static routes to Hetzner OST3 environment
  /sbin/route add -net 192.0.2.0/24 -interface ppp0
  /sbin/route add -net 192.168.253.0/24 -interface ppp0
fi

Automating Cisco AnyConnect Secure Mobility Client on Mac OS X

Do you hate having to manually enter the password in order to connect to a Cisco VPN? Well, I do. And I have found that instead of relying on the Cisco AnyConnect Security Mobility Client GUI application, one can use the command-line counterpart to automate VPN login.

Provided that you can log into your VPN using the graphical client, you can automate VPN login by using the following shell script:

cat > start_vpn.sh
#!/bin/bash
/opt/cisco/anyconnect/bin/vpn -s << EOF
connect https://your.cisco.vpn.hostname/vpn_name
here_goes_your_username
here_goes_your_passwordy
EOF
^D
# chmod +x start_vpn.sh

To connect:

# ./start_vpn.sh
Cisco AnyConnect Secure Mobility Client (version 3.1.05152) .

Copyright (c) 2004 - 2013 Cisco Systems, Inc.  All Rights Reserved.


  >> state: Disconnected
  >> state: Disconnected
  >> notice: Ready to connect.
  >> registered with local VPN subsystem.
  >> contacting host (https://your.cisco.vpn.hostname/vpn_name) for login information...
  >> notice: Contacting https://your.cisco.vpn.hostname/vpn_name.

  >> notice: Please respond to banner.

Welcome to VPN.

  >> state: Connecting
  >> notice: Establishing VPN session...
  >> notice: Checking for profile updates...
  >> notice: Checking for product updates...
  >> notice: Checking for customization updates...
  >> notice: Performing any required updates...
  >> state: Connecting
  >> notice: Establishing VPN session...
  >> notice: Establishing VPN - Initiating connection...
  >> notice: Establishing VPN - Examining system...
  >> notice: Establishing VPN - Activating VPN adapter...
  >> notice: Establishing VPN - Configuring system...
  >> notice: Establishing VPN...
  >> state: Connected
VPN> goodbye...
  >> note: VPN Connection is still active.

To disconnect:

# /opt/cisco/anyconnect/bin/vpn/disconnect

Cisco AnyConnect Web security module (acwebsecagent) in Mac OS X

The Cisco AnyConnect Client on Mac OS X seems to install two components: the VPN client and a Web security module. Based on my experience, the Web security module is always running (as a process named acwebsecagent) and consuming network bandwidth. If you don’t need the Web security module, you can uninstall it by running:

To uninstall the Web security module, just run:

sudo /opt/cisco/anyconnect/bin/websecurity_uninstall.sh

Credit for this: No to Cisco Web Security

OpenVPN Server and OpenVPN Client on Android

The OpenVPN server configuration:

# cat /etc/openvpn/server.conf
port 1194
proto udp
dev tun

ca /etc/openvpn/open-rsa/keys/ca.crt
cert /etc/openvpn/open-rsa/keys/server.crt
key /etc/openvpn/open-rsa/keys/server.key
dh /etc/openvpn/open-rsa/keys/dh1024.pem

server 10.8.0.0 255.255.255.0
push "dhcp-option DNS 8.8.8.8"
push "dhcp-option DNS 8.8.4.4"

keepalive 10 60
comp-lzo
persist-key
persist-tun
status 1194.log
verb 3

client-config-dir ccd

The client-specific configuration, which specifies which subnets are accessible on the client:

# cat /etc/openvpn/ccd/android
iroute 10.42.242.0 255.255.255.0

Enable IP forwarding

# grep ip_forward /etc/sysctl.conf
net.ipv4.ip_forward=1
# sysctl -p

Enable NAT

# iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE
# service iptables save

Export the client certificate and private key using PKCS12 in order to then import them into the OpenVPN Client for Android:

# openssl pkcs12 -export -in /etc/openvpn/open-rsa/keys/android.crt -inkey /etc/openvpn/open-rsa/keys/android.key -certfile /etc/openvpn/open-rsa/keys/ca.crt -name android -out /tmp/android.p12

The resulting android.p12 file can be sent to the Android device, and from there have it imported into the OpenVPN Client for Android.

IPSec transport mode with X.509 certificates

Scenario

This article describes how to create a secure network-level transport between two hosts. All traffic sent between both hosts will be encrypted automatically as in enters the TCP/IP stack at the network (IP) level by using IPSec Encapsulating Security Payload (ESP) protocol.

For more details about IPSec, read IPSec pilot between glass and teapot.

Security Policy Database (SPD) configuration

The Security Policy Database (SPD) defines which IP traffic flows are to be affected by IPSec. Any traffic protected by IPSec can be protected by two different security mechanisms:

  • Confidentiality.

    Is achieved by using IPSec Encapsulating Security Payload (ESP) protocol.

    The IPSec ESP protocol cyphers the contents of the payload to be transported over IP. ESP, optionally, offers authentication and integrity, but it is considered weak since it does only affect the payload but not the header of the encapsulating IP datagram.

  • Authentication and Integrity.

    Is achieved by using IPSec Authentication Header (AH) protocol.

    The IPSec AH protocol protects that payload and any unmutable field of the encapsulating IP header.

By configuring the SPD, it is possible to use:

  • IPSec Transport Mode to protect all the traffic sent between two hosts.
  • IPSec Tunnel Mode to protect all the traffic sent between to networks.
For the machine ipsec-a:

Create the file /etc/racoon/setkey.sh with the following lines:

#!/sbin/setkey -f spdflush ; spdadd 192.168.0.40 192.168.0.41 any -P out ipsec esp/transport//require ; spdadd 192.168.0.41 192.168.0.40 any -P in ipsec esp/transport//require ;

This file should be marked executable and will be executed before launching racoon in order to populate the SPD with the proper entries.

For the machine ipsec-b:

Create the file /etc/racoon/setkey.sh with the following lines:

#!/sbin/setkey -f spdflush ; spdadd 192.168.0.41 192.168.0.40 any -P out ipsec esp/transport//require ; spdadd 192.168.0.40 192.168.0.41 any -P in ipsec esp/transport//require ;

This file should be marked executable and will be executed before launching racoon in order to populate the SPD with the proper entries.

Racoon configuration

racoon is a user-space daemon in charge of negotiating and establishing the Security Associations (SA) between two peer.

When the kernel sees an IP datagram, affected by a SPD rule, for which there is no SA yet established, the kernel will invoke racoon in order to negotiate and set it up with the corresponding peer defined in the SPD.

The peers can authenticate using some of the following:

  • Pre-Shared Keys (PSK)

    Both peers mutually agree on a shared secret, which is manually configured by the administrator and stored in the file /etc/racoon/psk.txt.

  • RSA Signature

    Each peer has an associated private key and public key X.509 certificate. Authentication takes place by exchanging certificates between peers and validating them, while RSA is used for authentication.

  • GSSAPI

    Kerberos is used for authentication of both peers.

In out scenario, RSA Signature using X.509 public key certificates will be used for authentication between the peers so, in first place, we need to generate private keys and their corresponding certificates for each peer. The steps used to generate the certificates are described in Setting up Certificate Authority (CA) using OpenSSL.

The configuration for both peers is identical, so we will use the same racoon configuration file. However, the private key and public key certificate for each peer is different, so we should take this into consideration.

The peer private key must be installed into /etc/racoon/certs/key.pem, the peer signed public key certificate into /etc/racooon/certs/cert.pem and the CA public key certificate into /etc/racoon/certs/cacert.pem.

This is the /etc/racoon/racoon.conf configuration file:

path include "/etc/racoon"; path pre_shared_key "/etc/racoon/psk.txt"; path certificate "/etc/racoon/certs"; remote anonymous { # Some IPSec implementations have been found to # be vulnerable when used in aggressive exchange # mode exchange_mode main ; # Allow for the extension described in RFC 2407 # called Domain of Interpretation which allows # negotiation of the traditional 32-bit sequence # numbers or extended 64-bit sequence numbers doi ipsec_doi ; # Local identifier is taken from the Subject field # of the X.509 certificate (Distinguised Name) my_identifier asn1dn ; # Remote identifier is taken from the Subject field # of the X.509 certificate presented by the remote # peer (Distinguised Name) peers_identifier asn1dn ; # Checks that the oeer identity that appears in the # ID payload matches the identity specified in the # peers_identifier option verify_identifier on ; # Specifies the path to the certificate and private # key files, encoded in PEM, relative to the # "path certificate" option specified above certificate_type x509 "cert.pem" "key.pem" ; # Specifies the path to the CA certificate file, # encoded in PEM, relative to the "path certificate" # option specified above ca_type x509 "cacert.pem" ; # Configures the size of the nonce in bytes, which # must be no less than 8 and no more than 256 nonce_size 16 ; # Lifetime the Phase 1 SA proposal lifetime time 24 hour ; proposal { # Encryption algorithm for phase 1 encryption_algorithm 3des ; # Hash algorithm for phase 1 hash_algorithm sha1 ; # RSA Signature authentication authentication_method rsasig ; # Diffie-Hellman group for phase 1 dh_group 2 ; } } sainfo anonymous { # Diffie-Hellman group for phase 2 pfs_group 2; # Lifetime for the SA lifetime time 12 hour ; # Encryption algorithms to be used in the SA encryption_algorithm 3des, blowfish, des, rijndael ; # Authentication algorithms to be used in the SA authentication_algorithm hmac_sha1, hmac_md5 ; # Use deflate compression (IPComp) compression_algorithm deflate ; }

Starting peers

For every peer, we need to launch racoon. For testing purpouses, we will launch racoon in foreground, so all messages are dumped to the screen:

/usr/sbin/racoon -F

racoon will dump the following messages to the console:

INFO: @(#)ipsec-tools 0.5 (http://ipsec-tools.sourceforge.net)
INFO: @(#)This product linked OpenSSL 0.9.7f 22 Mar 2005 
      (http://www.openssl.org/)
INFO: 127.0.0.1[500] used as isakmp port (fd=7)
INFO: 127.0.0.1[500] used for NAT-T
INFO: 192.168.0.41[500] used as isakmp port (fd=8)
INFO: 192.168.0.41[500] used for NAT-T
INFO: ::1[500] used as isakmp port (fd=9)
INFO: fe80::20c:29ff:fea1:d55c%eth0[500] used as isakmp port (fd=10)

Next, we need to initialize the SPD:

/etc/racoon/setkey.sh

Testing connectivity

To trigger the SA establishment we can ping the other host. The kernel will apply the SPD policy and will ask racoon to negotiate and set up the proper SA between both peers. racoon should dump something like this to the console:

INFO: IPsec-SA request for 192.168.0.40 queued due to no phase1 found.
INFO: initiate new phase 1 negotiation: 
      192.168.0.41[500]192.168.0.40[500]
INFO: begin Identity Protection mode.
INFO: received Vendor ID: DPD
WARNING: unable to get certificate CRL(3) at depth:0 SubjectName:
         /C=ES/ST=Madrid/O=Software AG/OU=IT/CN=ipsec-a
WARNING: unable to get certificate CRL(3) at depth:1 SubjectName:
         /C=ES/ST=Madrid/L=Madrid/O=Software AG/OU=IT/CN=ca-server
INFO: ISAKMP-SA established 192.168.0.41[500]-192.168.0.40[500] 
      spi:2698c81446191f6c:9b9127e3b6956065
INFO: initiate new phase 2 negotiation: 192.168.0.41[0]192.168.0.40[0]
INFO: IPsec-SA established: ESP/Transport 192.168.0.40->192.168.0.41 
      spi=78608282(0x4af779a)
INFO: IPsec-SA established: ESP/Transport 192.168.0.41->192.168.0.40 
      spi=118550227(0x710eed3)

SSL/TLS VPN with stunnel

From the stunnel manual page:

The stunnel program is designed to work as SSL encryption wrapper between remote clients and local (inetd-startable) or remote servers. The concept is that by having non-SSL aware daemons running on your system you can easily set them up to communicate with clients over secure SSL channels.

stunnel can be used to add SSL functionality to commonly used inetd daemons like POP-2, POP-3, and IMAP servers, to standalone daemons like NNTP, SMTP and HTTP, and in tunneling PPP over network sockets without changes to the source code.

I will use stunnel to encapsulate PPP frames into the SSL tunnel, in order to create an SSL VPN between two peers. Both peers will have two network interfaces each:

  • a eth0, or eth0-like interface, which is the native, physical, non-tunneled network interface, used by each peer to directly reach the other via a WAN, insecure connection, like the Internet or a Wireless network.

    Traffic sent directly between peers through eth0 is assumed to be sent in the clear, without confidentiality, authentication or integrity.

  • a ppp0 network interface which acts as a Layer 2 interface, using PPP framing to tunnel traffic between both peers over an insecure network connection. PPP frames will get wrapped inside an SSL/TLS session between both peers and delivered via the real eth0 interface.

    Thus, traffic sent to the ppp0 interface will get wrapped inside a PPP frame, then transported over an SSL/TLS tunnel through the eth0 insecure interface to the other peer.

    SSL/TLS adds confidentiality, authentication and integrity by means of an SSL/TLS session.

Configuring the server

The configuration file for the stunnel server will be stored in the /root/stunnel-server.conf file:

# The CA certificate file CAfile = /root/cacert.pem # The server public key certificate cert = /root/server.pem # The server private key key = /root/server.key # Name of server PID file pid = /root/server.pid # Verify peer certificate verify = 2 # The directory where all the certificates can be found # Only used when verify = 3 # CApath = /root # Some debugging stuff debug = 7 # output = /root/server.log # Use it for client mode client = no foreground = yes # Protocol Specific options # We need to specify DES-CBC3-SHA since there are some AES # ciphers that, when used with RSA, can't be decoded by ssldump ciphers = DES-CBC3-SHA:IDEA-CBC-MD5 # Service-level configuration [vpn] # incoming port number accept = 9871 # argv[0] for the PPP server exec = /usr/bin/pppd # argv[0], argv[1], ... argv[n] for the PPP server execargs = /usr/sbin/pppd debug noauth noaccomp noccp nodeflate nopcomp novj novjccomp 192.168.1.1:192.168.1.2 # Use a pty, since the PPP server will write PPP frames to a pty pty = yes

Some of the options used in this configuration file are described in the next paragraphs:

  • CAfile, cert and key point to the location of the PEM-encoded CA certificate file, PEM-encoded server public certificate and PEM-encoded server private key, respectively.
  • verify defines the level of peer certificate verification:
    1. verify peer certificate, if present
    2. always verify peer certificate
    3. verify peer with locally installed certificate

    If no verify option is supplied, no peer certificate verification is performed.

  • client = no tells stunnel this side will act as the server.
  • foreground =yes requests stunnel not to fork off and log to stderr instead of using syslog.
  • ciphers = DES-CBC3-SHA:IDEA-CBC-MD5 configures the ciphers preferred list for the server when negotiating a cipher and MAC protocol with the client.

    I have chosen DES-CBC3-SHA in first place and IDEA-CBC-MD5 in second place cause if no cipher list is supplied, OpenSSL tends to select RSA-AES-256-SHA which ssldump is, at the time of this writing, is unable to decode.

  • accept defines the port stunnel will listen to.
  • exec specifies the program to execute in order to set up the PPP server used to encapsulate traffic inside the SSL/TLS tunnel.

    In this case, we use /usr/sbin/pppd.

  • execargs defines the arguments, starting at argv[0], that will be supplied to the command specified by the exec option (in this case, /usr/sbin/pppd):
    • debug, enables debugging information
    • noauth, disables any form of PPP authentication
    • noccp novj novjccomp noaccomp, disables any form of compression.

      noaccomp disables address/control compression in both directions.
      noccp disables CCP (Compression Control Protocol) negotiation.
      nodeflate disables Deflate compression support.
      nopcomp disables protocol field compression negotiation, in both the receive and the transmit direction.
      novj disables Van Jacobson style TCP/IP header compression in both the transmit and receive direction.
      novjccomp disables the connection-ID compression option in the Van Jacobson style TCP/IP header compression.

      This will be useful when using ssldump to decode traffic between the client and the server.

    • 192.168.1.1:192.168.1.2, tells the PPP server the remote peer ppp0 interface will get assigned IP 192.168.1.2, while the server, local ppp0 interface will get assigned IP 192.168.1.1.
  • pty = yes tells stunnel to allocate a pseudo-terminal used for the exec program.

    stunnel will get traffic from the remote peer through the SSL/TLS tunnel, will decrypt it using the private key and the resulting PPP frame will be written to this pseudo-tty so the PPP server can process it and send it back to the TCP/IP stack for further processing.

    Any time the local machine sends traffic to the ppp0 interface, the PPP server capture it and encapsulate it into a PPP frame that will get written to the pseudo-tty. stunnel will see that PPP frame, will send it to the remote peer trough the SSL/TLS tunnel.

Launching the server

To make things easier, create a shell-script called launch-server.sh with the following lines:

#!/bin/sh /usr/sbin/stunnel /root/stunnel.conf

Configuring the client

The configuration file for the stunnel client will be stored in the /root/stunnel-client.conf file:

# The CA certificate file CAfile = /root/cacert.pem # The client public key certificate cert = /root/client.pem # The client private key key = /root/client.key # Name of client PID file pid = /root/client.pid # Verify peer certificate verify = 2 # The directory where all the certificates can be found # Only used when verify = 3 # CApath = /root # Some debugging stuff debug = 7 #output = /root/client.log # Use it for client mode client = yes foreground = yes # Service-level configuration # host and port where stunnel server peer is listening connect = stunnel-server:9871

Some of the options used in this configuration file are described in the next paragraphs:

  • CAfile, cert and key point to the location of the PEM-encoded CA certificate file, PEM-encoded client public certificate and PEM-encoded client private key, respectively.
  • verify defines the level of peer certificate verification:
    1. verify peer certificate, if present
    2. always verify peer certificate
    3. verify peer with locally installed certificate

    If no verify option is supplied, no peer certificate verification is performed.

  • client = yes tells stunnel this side will act as the client.
  • foreground =yes requests stunnel not to fork off and log to stderr instead of using syslog.
  • connect is used when client = yes and tells stunnel which host and port to connect to.

Launching the client

To make things easier, create a shell-script called launch-client.sh with the following lines:

#!/bin/sh /usr/sbin/pppd noauth debug dump passive noaccomp noccp nodeflate nopcomp novj novjccomp nodetach pty "/usr/sbin/stunnel /root/stunnel.conf"

This will launch the PPP client, pppd, using an SSL/TLS tunnel supplied by stunnel as the encapsulating Layer 2 tunneling protocol.

  • noccp novj novjccomp noaccomp, disables any form of compression.

    noaccomp disables address/control compression in both directions.
    noccp disables CCP (Compression Control Protocol) negotiation.
    nodeflate disables Deflate compression support.
    nopcomp disables protocol field compression negotiation, in both the receive and the transmit direction.
    novj disables Van Jacobson style TCP/IP header compression in both the transmit and receive direction.
    novjccomp disables the connection-ID compression option in the Van Jacobson style TCP/IP header compression.

    This will be useful when using ssldump to decode traffic between the client and the server.

  • debug, enables debugging information
  • noauth, disables any form of PPP authentication
  • passive, enables the passive option in the LCP.

    With this option, pppd will attempt to initiate a connection. If no reply is received from the peer, pppd will then just wait passively for a valid LCP packet from the peer, instead of exiting, as it would do without this option.

  • nodetach, tells pppd to not detach from the controlling terminal. Useful to keep pppd in the foreground, so it can get stopped with a SIGINT signal.
  • pty, specifies the command script used to communicate rather than a specific terminal device. pppd will allocate itself a pseudo-tty master/slave pair and use the slave as its terminal device. The script will be run in a child process with the pseudo-tty master as its standard input and output.

    The command script is just the invocation to stunnel, in order to encapsulate all the PPP frames generated by pppd inside the SSL/TLS tunnel.

Testing connectivity

After launching the client, a new ppp0 interface should be automatically configured with the following parameters:

ppp0      Link encap: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:3 errors:0 dropped:0 overruns:0 frame:0
          TX packets:3 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:3
          RX bytes:30 (30.0 b)  TX bytes:30 (30.0 b)

A simply ping 192.168.1.1 command executed from the client should suffice to trigger traffic through the SSL/TLS tunnel and test connectivity.

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.