[Show/Hide Left Column]


6. OpenVPN


6.1 Introduction

SSLVPN is common name for a VPN implementation based on the SSL/TLS protocol suite. An SSLVPN is implemented as a module executing in the ease-to-use user-space context instead of the kernel ring of the operating system. It is supposed to be more lightweight than IPSec.

6.2 Background

OpenVPN is an perfect ????? in what sense perfect??? implementation of SSLVPN. OpenVPN is an open source project, see 1. We start by giving a basic knowledge about SSL/TLS based VPN implementations.

6.2.1 SSL/TLS riding on UDP

Generally speaking, VPN is just providing a secure data tunnel, the reliable transport layer isn’t a favorite choice as in the IPSec case because of the poor performance and the potential worst situation thanks to the multi-layer time-out and retransmission mechanism needed by TCP.
When using the SSL/TLS protocol suite to set up a VPN, the first challenge is to switch the native required reliable transport layer of SSL/TLS protocol to the connectionless UDP beneath SSL/TLS. Just like the tricks in DTLS, OpenVPN used a similar technique to get through, which defines one control channel, a equivalent reliable transport layer needed by initial parameters exchange and identity authentication and another data channel, a connectionless UDP-based tunnel to carry VPN data. While IPSec uses two sessions respectively for IKE negotiation and data communication, OpenVPN simply has the control and data channels inside one UDP-based session.
Control channel
The Control channel acts both in the initial phase tasked with SSL/TLS handshake, including session starting, key exchange, cipher suite agreement, identity authentication, etc. and in the final phase of the connection, where some cleanups are necessary.
Because of the required connection-oriented transport layer of SSL/TLS handshake protocol, the Control channel itself must compensate for the disadvantage of the unreliable UDP transport layer by simply introducing packet acknowledgement, time-out and retransmission mechanism.. There are two message types in the OpenVPN Control channel, the P_CONTROL message type is a way to implement a TLS cipher packet needed to be encapsulated inside a reliability layer, and the reliability layer is implemented as a straightforward ACK and retransmit model implemented through the P_ACK message type.
Data channel
The Data channel, established after the SSL/TLS handshake, is a connectionless UDP tunnel where there is no retransmission and ACK mechanism. The P_DATA message type represents encrypted, encapsulated tunnel packets that tend to be either IP packets or Ethernet frames which are essentially the "payload" of the VPN.

6.2.2 TCP/UDP packet format

The following texts extracted from the ssl.h header file in the OpenVPN source code is the constructed packet formats to help understand the practice about SSL/TLS riding on UDP.
OpenVPN can run either on TCP or UDP. 
1. Packet length (16 bits, unsigned) 
   TCP only, always sent as plaintext. Since TCP is a stream protocol, the packet length words 
   define the packetization of the stream.
2. Packet opcode/Key_id (8bits)
   TLS only, not used in pre-shared secret mode.
   P_* constant (high 5 bits)
      Packet message type.
   Key_id (low 3 bits)
      The key_id refers to an already negotiated TLS session. OpenVPN seamlessly renegotiates 
      the TLS session by using a new key_id for the new session. Overlap (controlled by user 
      definable parameters) between old and new TLS sessions is allowed, providing a seamless
      transition during tunnel operation.
3. Payload (n bytes)
     which may be a P_CONTROL, P_ACK, or P_DATA.

Message types:
1. P_CONTROL_HARD_RESET_CLIENT_V1
   Key method 1, initial key from client, forget previous state.
2. P_CONTROL_HARD_RESET_SERVER_V1
   Key method 2, initial key from server, forget previous state.
3. P_CONTROL_SOFT_RESET_V1
   New key, with a graceful transition from old to new key in the sense that a transition window 
   exists where both the old or new key_id can be used. OpenVPN uses two different forms of key_id.
   The first form is 64 bits and is used for all P_CONTROL messages. P_DATA messages on the other 
   hand use a shortened key_id of 3 bits for efficiency reasons since the vast majority of OpenVPN 
   packets in an active tunnel will be P_DATA messages. The 64 bit form is referred to as a session_id,
   while the 3 bit form is referred to as a key_id.
4. P_CONTROL_V1 
   Control channel packet (usually TLS ciphertext).
5. P_ACK_V1
   Acknowledgement for P_CONTROL packets received.
6. P_DATA_V1
   Data channel packet containing actual tunnel data ciphertext.
7. P_CONTROL_HARD_RESET_CLIENT_V2
   Key method 2, initial key from client, forget previous state.
8. P_CONTROL_HARD_RESET_SERVER_V2
   Key method 2, initial key from server, forget previous state.


Payload:
1. P_CONTROL* and P_ACK Payload
   The P_CONTROL message type indicates a TLS ciphertext packet which
   has been Encapsulated inside of a reliability layer. The reliability
   layer is implemented as a straightforward ACK and retransmit model.
2. P_DATA payload: 
   represents encrypted, encapsulated tunnel packets which tend to be 
   either IP packets or Ethernet frames. This is essentially the "payload"
   of the VPN.

Payload Packet format:
1. P_CONTROL message format:
   Local session_id 
     random 64 bit value to identify TLS session
   HMAC signature of entire encapsulation header for integrity check 
     Valid only if --tls-auth is specified (usually 16 or 20 bytes).
   Packet-id for replay protection 
     4 or 8 bytes, includes sequence number and optional time_t timestamp
   P_ACK packet_id array length (1 byte)
   P_ACK packet-id array (if length > 0)
   P_ACK remote session_id (if length > 0)
   Message packet-id (4 bytes)
   TLS payload ciphertext (n bytes, only for P_CONTROL)

Once the TLS session has been initialized and authenticated, the TLS channel is used to exchange random key material for the bidirectional cipher and HMAC keys which will be used to secure the actual tunneled data packets. OpenVPN currently implements two key methods. Key method 1 directly derives keys using random bits obtained from the RAND_bytes OpenSSL function. Key method 2 mixes random key material from both sides of the connection using the TLS PRF mixing function. Key method 2 is the preferred method and is the default for OpenVPN 2.0.
TLS plaintext packet content:
  if key_method == 1
     Cipher key length in bytes (1 byte).
     Cipher key (n bytes).
     HMAC key length in bytes (1 byte).
     HMAC key (n bytes).
     Options string (n bytes, null terminated, client/server options string should match).
  if key_method == 2
     Literal 0 (4 bytes).
     key_method type (1 byte).
     key_source structure (pre_master only defined for client ->server).
     options_string_length, including null (2 bytes).
     Options string (n bytes, null terminated, client/server options string must match).
     [The username/password data below is optional, record can end at this point.]
     username_string_length, including null (2 bytes).
     Username string (n bytes, null terminated).
     password_string_length, including null (2 bytes).
     Password string (n bytes, null terminated).
2. P_DATA message content:
     HMAC of ciphertext IV + ciphertext (if not disabled by --auth none).
     Ciphertext IV (size is cipher-dependent, if not disabled by --no-iv).
     Tunnel packet ciphertext.


   P_DATA plaintext:
     Packet_id (4 or 8 bytes, if not disabled by --no-replay).
       a. In SSL/TLS mode, 4 bytes are used because the implementation can force a TLS
          renegotation before 2^32 packets are sent.
       b. In pre-shared key mode, 8 bytes are used (sequence number and time_t value) to
          allow long-term key usage without packet_id collisions.
     User plaintext (n bytes).

Notes:
1. ACK messages can be encoded in either the dedicated P_ACK record or they can be prepended to a P_CONTROL message.
2. P_DATA and P_CONTROL/P_ACK use independent packet-id sequences because P_DATA is an unreliable channel while P_CONTROL/P_ACK is a reliable channel. Each use their own independent HMAC keys.
3. Note that when --tls-auth is used, all message types are protected with an HMAC signature, even the initial packets of the TLS handshake. This makes it easy for OpenVPN to throw away bogus packets quickly, without wasting resources on attempting a TLS handshake which will ultimately fail.

6.3 OpenVPN’s tunnel mechanism

OpenVPN has used a technique called TUN/TAP virtual network driver, which emulates a network device in software attached to the specific user-space application. The packet sent by the operating system network stack to the TAP/TUN network device can be directly transferred to the specific user-space program instead of network cable or the packetS from the specific program can directly write their data --IP packets, to the TUN/TAP network device, which later will be forwarded to the operating system network stack and finally arrived to its belonging of user-space application.
The TAP simulates an Ethernet device, operating in layer 2 with Ethernet frames whereas TUN, operates in layer 3 with IP packets. In a VPN implementation, TAP is used to create a network bridge while TUN is used with routing.
The handling process of TUN/TAP is as follows:

Architecture for OpenVPN using TUN/TAP

Data from Applications to Ethernet Cable(sending)
The new emerging device TUN/TAP is fully transparent for applications and the Operating System native network stack. The user-space data sent from applications is handled in the way as before. The data, is first segmented and encapsulated into IP packets, and is then routed to the path of TUN/TAP NIC and is finally transferred by the TUN/TAP driver to the data area of OpenVPN in user-space. These arriving OpenVPN data, IP packets in itself, possibly encrypted here, fed into the network stack to be segmented and encapsulated again to form a new IP packet, and further this new packet will be routed to the hardware Ethernet device.
OpenVPN, which features direct communications with TUN/TAP driver in the kernel, has no privileged role compared to other common user-space applications. The decision of selecting the traffic path is up to the route table in the operating system. Therefore, when configuring OpenVPN,, the VPN network topology must be explicit in the configuration files for obtaining propper VPN operation. Note , that is similar to IPSec where the policy must be specified in advance.

Packets from Ethernet Cable to Applications(receiving)
This handling process is exact the reverse of the above. The packets, which in principle are UDP packets, are passed to the destined applications according to the port numbers they belong in the TCP/UDP Header. The packets bound to OpenVPN, possibly reassembled in IP layer or OpenVPN internal, are first decrypted and then transferred to the data area allocated under the operating system kernel for TUN/TAP driver. These decrypted data, still in IP packets format, then will be forwarded to the network stack again and finally arrive to its corresponding user-space applications according to the port number in the TCP/UDP header.

6.4 Example

For this example we reuse for our, network topology the same setup as used for the NAT-based IPsec VPN example. In fact, the NAT box , which featured NAT-based IPSec, doesn’t play any role in the next example and there is no problematic issue with it in OpenVPN as it was in IPSec. The simple reason is that OpenVPN benefits from its user-space application implementation.

6.4.1 Scenario

Although OpenVPN supports a peer-to-peer model, we present here only the client-server model as our example.

Network topology for the OpenVPN example

6.4.2 Configuration

Gateway:
  OS: fedora
  IP: 130.235.203.249
  Default OpenVPN configured files:
    /usr/local/openvpn/server.ovpn
  Root CA:
    /usr/local/openvpn/ca.crt
  Gateway certification:
    /usr/local/openvpn/sslvpn-server.crt
  Gateway key(private key):
     /usr/local/openvpn/sslvpn-server.key
  Diffie hellman parameters:
     /usr/local/openvpn/dh1024.pem

Client:
  OS: windows XP
  IP: 10.10.10.5
  Directory of OpenVPN program installed:
    Root: c:\Program Files\OpenVPN
  Directory of OpenVpn log:
    Root\log
  Default Configured files:
    Root\config\client.ovpn
    Root CA: (the same with the Root CA in gateway)
    Root\config\ca.crt
  Client certification:
    Root\config\client.crt
  Client key(private key):
    Root\config\client.key

6.4.3 Test steps:

on the gateway
  run the following command (on the gateway)
  # cd  /usr/local/openvpn/
  # ./openvpn ./server.ovpn

on the client
  1.check the existing route table entries
    c:> route print
  2.double click the OpenVPN GUI icon on the destop to run program.
    the program icon will slip at the right-bottom corner in the desktop.
  3.right click the OpenVPN icon in the running and selects the option “Edit
    Config” to alter the configure file as needed.
  4.right click the icon again to tap the option “Connect” and starts running.
  5.test the connectivity with the private network behind the gateway
    c:> ping 192.168.2.2 or http://192.168.2.2 (external link) in the browser
  6.check the new added route table entries and the ones changed.
    c:> route print

6.4.4 Explanation of some config items:

For Gateway config (in server mode)

File server.ovpn:
# Which TCP/UDP port should OpenVPN listen on? 
  port 1194
# TCP or UDP server? The default is UDP.
  ; proto tcp
  proto udp
# "dev tun" will create a routed IP tunnel,
# "dev tap" will create an Ethernet tunnel.
  ;dev tap
  dev tun
# SSL/TLS root certificate (ca), certificate(cert), and private key (key).
  ca ca.crt
  cert sslvpn-server.crt
  key sslvpn-server.key
# Diffie hellman parameters. 
# Openvpn2.x uses DHE_RSA key exchange algorithm complied 
# with tls 1.0.
  dh dh1024.pem
# Configure server mode and supply a VPN subnet for OpenVPN to 
# draw client addresses from. The server will take 10.8.0.1 for itself, the
# rest will be made available to clients. Each client will be able to reach 
# the server on 10.8.0.1.
  server 10.8.0.0 255.255.255.0
# Push routes to the client to allow it to reach other private subnets 
# behind the server.  
  push "route 192.168.2.0 255.255.255.0"
# The maximum number of concurrently connected clients we want to 
# allow.
  ;max-clients 100
# Select a cryptographic cipher. This item must be copied to the client 
# config file as well.
  ;cipher BF-CBC        # Blowfish (default)
  ;cipher AES-128-CBC   # AES
  ;cipher DES-EDE3-CBC  # Triple-DES

For Client config (in client mode)

File client.ovpn:
# Specify that we are a client and that we will be pulling certain config 
# file directives from the server.
  Client
# Use the same setting of tun/tap as in the server.
  ;dev tap
  dev tun
# Are we connecting to a TCP or UDP server? 
  ;proto tcp
  proto udp
# The hostname/IP and port of the server.
  remote 130.235.203.249 1194
# root certificate (ca), client certificate (cert), and client private key (key)
  ca ca.crt
  cert client.crt
  key client.key
# Select a cryptographic cipher. If the cipher option is used on the server
# then you must also specify it here.
  ;cipher x


6.5 PMTU under OpenVPN

OpenVPN is ready to encrypt the incomming TUN/TAP virtual network packets, as they are again forwarded to network protocol stack and repackaged into a new UDP or TCP packet before leaving the real network interface. There will be some additional overhead in the new packets, such as padding resulting from encryption, packet encapsulated headers and other newly introduced packet fields by OpenVPN . While switching to OpenVPN, the PMTU value between applications secured over VPN tunnel should be adjusted to be smaller than the original one. However OpenVPN is a user-space application and basically is depending on UDP for the carrier layer. Therefore it is hard for OpenVPN to be aware of the ICMP ‘fragment needed’ message generated among the devices with small MTU between OpenVPN peers, which should be responsible to forward such ‘packet too large’ message to the end application as it is done in IPSec. For this reason OpenVPN uses instead its own mechanism(s) to handle these kind of PMTU problems. Below we discuss how in four different cases.

6.5.1 --proto tcp

If the option --proto tcp is checked in the config file, OpenVPN will use the TCP protocol as the carrier layer for its encrypted payloads. PMTU discovery between applications under the tunnel acts as there is no presence of OpenVPN, i.e., the overhead(s) imposed by the OpenVPN peers have no effect whatsoever on the applications. This is because the PMTU problem between OpenVPN peers is solved by TCP protocol and thus it is transparent to the application sitting on top of OpenVPN.

6.5.2 --proto udp

A TCP based VPN has poor performance and some other problems, such as disorder in multi-level retransmission timeout, Instead UDP is an ideal carrier protocol for VPN. For normal UDP based applications, the problem of determining the PMTU value is up to the application itself to solve. This is also the case for UDP based OpenVPN. If there is no specified parameter referring to MTU in config file, the encrypted data from OpenVPN are simply dropped to the UDP stack and encapsulated into a UDP packet. Then these UDP packets are passed down to the IP layer and sent out. Now a possibly fragmentation of OpenVPN UDP packets which are carried by the IP layer might occur at a device with small MTU along the path between the OpenVPN peers. The fragmented IP packets arrive at the OpenVPN peer where they are reassembled to intact UDP packets by IP layer,and then transferred to the OpenVPN application. The fragment and assembly are implemented by native IP layer of the operating system, so whether for an application using the tunnel or OpenVPN itself, one does not have to take care about PMTU problems between OpenVPN peers. However, in practice, there might be some intermediate devices blocking such kind of IP fragment packets getting through due to some security considerations (implemented for example in firewall rules). For this purpose OpenVPN offers the --fragment max and -- mssfix max options to cope with fragment problems.

--fragment max
Enable internal datagram fragmentation so that no UDP datagrams are sent which are larger than max bytes. Here the UDP size refers to the length after encryption overhead, not including the UDP header itself. This option adds 4 bytes of overhead per datagram, meaning the internal datagram fragment need to be reorganized into a full unit before decrypted in another OpenVPN peer and the assembly is done by the OpenVPN instead of network stack. We quote here the comments from the OpenVPN documentation: “This option is not meant to replace UDP fragmentation at the IP stack level. It is only meant as a last resort when path MTU discovery is broken. Using this option is less efficient than fixing path MTU discovery for your IP link and using native IP fragmentation instead.”
--mssfix max
MSS, Maximum Segment Size, is an option of the TCP specification that claims the maximum receive segment size at the TCP which sends this segment. This option field must only be sent in the initial TCP handshake requests with SYN control bit set. The field value, in typical Ethernet based circumstance, is 1460 bytes not including IP and TCP header, respectively 20 bytes overheads. Due to additional overheads presence, OpenVPN utilizes the TCP MSS mechanism to prevent TCP session packets from being fragmented by hijacking the initial TCP handshake requests running over the tunnel and lowering the TCP MSS to a value below -- mssfix max. Apparently -- mssfix only applies to TCP session applications sitting on top of the OpenVPN tunnel.

“In practice, -- fragment and -- mssfix can be ideally used together, where -- mssfix will try to keep TCP from needing packet fragmentation in the first place, and if big packets come from protocols other than TCP, -- fragment will internally fragment them. Both -- fragment and -- mssfix are designed to work around cases where Path MTU discovery is broken on the network path between OpenVPN peers. If -- fragment and -- mssfix are used together, -- mssfix will take its default max parameter from the -- fragment max option. Therefore, one could lower the maximum UDP packet size to 1300 (a good first try for solving MTU-related connection problems) with the following options: -- tun-mtu 1500 -- fragment 1300 -- mssfix ” -----from OpenVPN documents.

However, there is still a distinction between them, where -- mssfix contributes to PMTU discovery for the applications running over the tunnel while -- fragment doesn’t, as the fragment and assembly are just done by the OpenVPN peers.


Menu [toggle]