Sunday, March 29, 2009

openvpn configuration

Introduction

This article will describe a configuration of Virtual Private Network connection by using an OpenVPN application. Firstly, you will be exposed to some basic theory behind Virtual Private Networks. Then, the article will guide you with step-by-step instructions on how to setup a OpenVPN virtual private network by using Symmetric Key Encryption and Public Key Encryption. This article is meant for everybody who possesses a basic knowledge of linux administration and networking.
Why VPN

If you work in IT industry, it is very common that you do not use only a single computer sitting on your work desk, but you also utilize other systems connected to the same local area network. As long as you are sitting on your office chair this approach should not be a problem. However, this situation can become complicated once you are in hurry, and therefore, you need to take some of your work home. You are able to take you company laptop with you, but to fully utilize company resources you would also need to be connected to the company's local area network.

The solution to this problem depends on what resources are needed to complete your job. If you need some shared files available on the company's network, you may just simply copy these file to your laptop's hard drive or to USB stick. In case you need to work on the system installed on your company's PC you can also use some virtualization tools such as VirtualBox or VMware. Soon enough you will realize that this approach is not as convenient as you would like it to be, and that you spent more time by copying files and synchronizing virtual systems than concentrating on your work.

The ideal solution in this case should allow employees to access company's local resources from an external network. This can be done by forwarding ports of the local services via firewall. Exposing local ports to the Internet is not entirely the safest approach. The more ports are exposed from your local network to an external network such as the Internet, the more vulnerable your local system will become.

The ideal approach in this situation could be a use of just single port for all services coupled with encryption and user authentication. This can be achieved, for example, by using a Virtual Private Network (VPN).
How does VPN works

VPN networks are often operated as client-server applications. Good example could be an implementation of MS Windows PPTP or OpenVPN on the Linux Platform. VPN server is directly running on a firewall, where it creates virtual network interface and additional virtual network subnet. VPN server is waiting for connections on the external network interface of the firewall where it performs authentication of a VPN client application. After successful VPN client authentication a VPN client is given an IP address from a virtual subnet. Consequently, an encrypted tunnel is created between VPN client and VPN server, which is used for safe transfer of packets between two distant networks via the Internet. Services, which a VPN client can connect to, can furthermore be defined by firewall rules. This way firewall ensures that VPN client can connect only to services it is allowed to connect.

If the previous couple sentences looked to you little difficult to understand, do not despair! Everything will become clearer once we see how encrypted tunnel works in an example.
VPN Encrypted Tunnel Fundamentals

VPN tunnels are generally considered as something mysterious and everybody who mentions them, is "cool" :-) However, there is nothing to be afraid about, in the fact principle of Virtual Private Network is very simple.

Data in IP networks are exchanged in packets. Information about destination and a source of the packet can be found in the packet's header. The actual user data are carried as a payload. Let’s imagine that ssh client wants to talk to ssh server over the Virtual Private Network. Packets leaving a host's network interface located on the local network are sent with a destination port number 22. When this packet reaches a VPN tunnel it is encapsulated into the VPN packet where original packet is now treated as a payload. If the VPN server listens on the port 443, the VPN packet will carry a destination port 443.

Image:vpn1.png

When looking at the previous figure it is apparent that this kind of network data transfer over the VPN is a waste of transfer rate because original packet has a smaller payload space just because it needs to fit into the VPN tunnel packet. In VPN analogical sense this can be considered as a drawback.
The theory behind Virtual Private Network

Let's imagine a small company network consisting just from a single subnet, in which all clients are connected to the Internet via company's gateway, which can also used as a firewall. How the connection is done, is not important, it is enough to mention that external gateway network interface uses external ip address. This scenario is visualized on the following figure:

Image:network1.png

In case that an employee wants to connect to some company's services from outside world, his/her attempt would be rejected by the firewall. Not just because this attempt is coming from completely different subnet but also because the ports to the particular services are not open.

Once the VPN server starts functioning on the gateway, it automatically creates a virtual network interface with subnet 192.168.2.0/24, which would then start accepting a connection from external network. Once employee passes VPN server's authentication, a VPN server will assign an IP address from a 192.168.2.0/24. For 192.168.1.0/24 hosts would be the systems on 192.168.2.0/24 network appear that they are located on the separate local subnet, but in fact the communication is done by encrypted VPN tunnel over the Internet.
VPN fundamentals

The following image will try to explain fundamental principles of VPN server-client communication. The gif animation will change every 14 seconds. The aim of this animation is to explain a logic behind a VPN communication in simplest form as possible. Please note, that there are many other factors behind the scenes which had been for the sake of simplicity omitted.

* 1/14: VPN Client establishes a connection with a VPN Server via external network interface.
* 2/14: VPN Server assigns IP address to a vpn client from a local virtual subnet 192.168.2.0/24.
* 3/14: VPN Client prepares a packet for a host 192.168.1.3 located within a private subnet 192.168.1.0/24.
* 4/14: VPN Client encrypts and hides an original packet inside the outer public packet.
* 5/14: The packet is dispatched by the VPN client via public network to the VPN Server.
* 6/14: A network packet acquired from the public network is decrypted and decapsulated by the vpn server. This way VPN server obtains a packet for the private network.
* 7/14: VPN Server handles a newly acquired packet as it was sent locally on a 192.168.1.0/24 subnet.
* 8/14: Packet is delivered to the host with destination IP address 192.168.1.3.
* 9/14: Host with IP address 192.168.1.3 creates a network packet with destination IP 192.168.2.2.
* 10/14: VPN Server receives a reply packet.
* 11/14: According to the VPN Server's routing table, this packet links up with the Virtual Private Network.
* 12/14: VPN server encrypts and hides an original packet inside the outer public packet.
* 13/14: The packet is dispatched by the VPN server via public network to the VPN client.
* 14/14: The network packet acquired from the public network is decrypted and decapsulated by the vpn Client. This way VPN client obtains a packet from the private network.

Static key vs. Certificates

One of the best characteristics of VPN solution is an encryption which leads to the client-server confidentiality communication enhancement. Once the connection between VPN Server and VPN Client is encrypted, an interceptor cannot read the message. Encryption is done on both sides of VPN transmission and thus creating so called VPN tunnel via public network such as the Internet. Encryption can be divided into two main groups:
Symmetric Key Encryption

This type of communication requires a one symmetric key which will be used on both sides to encrypt a message and this way preventing an interceptor to read a message. To do this, symmetric key needs to be produced and exchanged between both sides. This means that both sides will use the same encryption key to encrypt as well as to decrypt sent and received messages.
Public Key Encryption

When it comes to the public key encryption, each side has a public key and private key. There are four keys in total. Sender encrypts a message with a receiver's public key and receiver decrypts a message with its own private key. Since only the receiver has an access to its own private key only he can decrypt a message.

OpenVPN supports both ways of above mentioned encryptions. Symmetric encryption in terms of OpenVPN is regarded as a static key mode and public key encryption as a certificate mode. Before we put both types of encryption s into the test by showing a real configuration and testing examples, let's have a look on the following list which contains deliberately unsorted strengths and weaknesses for each solution:

Symmetric Key Encryption:

* symmetric encryption
* simple configuration
* no Certificate Authority ( CA ) is required
* server can serve only single client at the same time
* key must be stored in text file on the both systems which increases a risk that it will fall to the wrong hands
* difficult key exchange

Public Key Encryption:

* asymmetric encryption
* more complicated configuration
* Certificate Authority ( CA ) is required
* server can server many clients simultaneously

Examples of VPN connection

Now, that we have grasped a necessary theory about Virtual Private Networks, we can move on, and explore all mandatory steps for creating a VPN connection with Symmetric Key Encryption and Public Key Encryption. As a starting point in both cases there will be two computers with fresh Debian Linux installation. How the connection between those two PC's is created is not important. The connection can be done via cross-over cable, two bridged virtual machines or over the Internet. What is important, is that both PC's can ping each other and VPN Server will have 1194/UDP port open for connection from a VPN Client. In the further text we will refer to these systems as a VPN-Server ( IP Address: 10.1.1.3 ) and a VPN-Client ( IP Address: 10.1.1.4 ).

Image:vpn_example.png

A VPN tunell will be created as point-to-point 192.168.0.1 - 192.168.0.2. However, for VPN tunnel created with use of Public Key Encryption ( OpenVPN certification mode ) the client's IP address will differ and will be assigned from 192.168.0.0/16 subnet IP address pool. In our case the client will obtain a IP address 192.168.0.6.
Installation of OpenVPN

OpenVPN application consists only from one binary file which name is equal to the application name itself, thus openvpn. This binary file is used to start an OpenVPN server as well as OpenVPN client and therefore it is important to install the same OpenVPN packages on both sides. To be more precise, a difference between an OpenVPN Server and OPenVPN Client is just in how the configuration is carried out on both sides.

It is recommended to install OpenVPN packages from the official repository of your Linux Distribution you intent to use for this purpose. If, from some reason the packages for OpenVPN are not included in the official repository of your linux distribution feel free to install from source code. Both installations will be briefly covered in the following paragraphs. Repeat a following installation steps for vpn-server as well as a vpn-client.
Installation from official repository

Installation from the official Debian repository is simple as running a apt-get command:

linuxconfig.org:~# apt-get install openvpn
Reading package lists... Done
Building dependency tree... Done
The following extra packages will be installed:
liblzo2-2
Suggested packages:
openssl
The following NEW packages will be installed:
liblzo2-2 openvpn
0 upgraded, 2 newly installed, 0 to remove and 19 not upgraded.
Need to get 397kB of archives.
After unpacking 1114kB of additional disk space will be used.
Do you want to continue [Y/n]?

Apt-get will automatically fetch required prerequisites as in this case it is a liblzo2-2 package.
Installation from a source code

Installation of OpenVPN from source code involves steps like downloading a source code from OpenVPN Home page and compiling it with following sequence of commands:

linuxconfig.org:~$ wget http://openvpn.net/release/openvpn-2.0.9.tar.gz
linuxconfig.org:~$ tar xfz openvpn-2.0.9.tar.gz
linuxconfig.org:~$ cd openvpn-2.0.9
linuxconfig.org:~$ ./configure --prefix=/usr/local
linuxconfig.org:~$ make
linuxconfig.org:~# make install

What happens here, is that openvpn binary file will be created by the source code compilation and installed in a /usr/local/sbin directory.
Enabling a Virtual Network Interface

OpenVPN works with Virtual Network Interfaces TUN/TAP. TUN and TAP are virtual network kernel drivers and TUN ( TUNnel ) must be enabled in the kernel or at least as a module in order to virtual private network be able to function. TAP kernel driver can be found in the network interfaces section under the name "Universal TUN/TAP device driver support". To confirm that a TUN module is supported by your system check a config file created during a kernel compilation. As it was already mentioned previously, for this article a Linux Debian was used, and in Debian a TUN driver is supported by default in the form of a kernel module. This can by confirmed by the following command:

grep CONFIG_TUN= /boot/config-

eth0 interface directly represents a hardware device, which can be, for example a PCI network card. On the other hand, TUN/TAP devices represent a virtual network interface. Packets traveling via TUN/TAP interface are sent to the application before they reach eth0 network interface. This allows an application such as OpenVPN encrypt or decrypt packets before they reach a physical network.
VPN Connection and Symmetric Key Encryption
Setting up VPN Server

Almost all configuration settings can be passed to the OpenVPN application via command line. Another option is to create a configuration file which will be read during the OpenVPN initialization. Creating a configuration file is a clean way to maintain a Virtual Private Network connection settings, since the number of outgoing connections can grow where the only limits is just a robustness of your system. However, for sake of simplicity and transparency in the following example we will use command line parameters to configure an OpenVPN server.

linux_VPN_Server:~# /sbin/ifconfig eth0
eth0 Link encap:Ethernet HWaddr 00:0C:29:70:5A:F7
inet addr:10.1.1.3 Bcast:10.255.255.255 Mask:255.0.0.0
inet6 addr: fe80::20c:29ff:fe70:5af7/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:110 errors:0 dropped:0 overruns:0 frame:0
TX packets:85 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:11724 (11.4 KiB) TX bytes:13204 (12.8 KiB)
Interrupt:169 Base address:0x2000

Generate Static Symmetric Key

Before we can start a OpenVPN tunnel, a symmetric key neds to be generated and exchanged between server and client. To generate a Symmetric Key run a following command:

linux_VPN_Server:~# openvpn --genkey --secret staticVPN.key
linux_VPN_Server:~# cat staticVPN.key
#
# 2048 bit OpenVPN static key
#
-----BEGIN OpenVPN Static key V1-----
00e5dea65588eec9800f72607c6fb050
62a58ad4a44039d22635bdd817886c8b
69dbe38384eed05dcdca54c604e46d74
daec8f0e074f2a142db0efafe25520cb
a71a0c0314800be297275205bc6d18e3
852419caac500dc4135c2ce375c5020a
dd4ed783c1f47518e74c6b10124173ca
8ef3b52cfc297daf21683bb4f735856f
825c7ee868385dfcf4c3363d261e0e13
dfb60d3e3abc6a2075b8d243d3976eee
1afdff0e865d5973e2f6b6418f603aca
1923053d44ac0021ff74efbf00e60e3f
b928d4cc32f9d3d65566f8c1aaa5eb45
e1ebc134a1b060b6dde30ca5b9a54900
a1a5e0746ba7778285f163317433fb19
c0d5669677d9e921051c1fa6d3c75d47
-----END OpenVPN Static key V1-----

Start OpenVPN Server

At this stage a Static Symmetric Key can be used to start an OpenVPN server with will create a one side of a Virtual Private Network tunnel ready for connections:

linux_VPN_Server:~# openvpn --dev tun --ifconfig 192.168.0.1 192.168.0.2 --secret staticVPN.key
Wed Jan 28 03:48:09 2009 OpenVPN 2.0.9 i486-pc-linux-gnu [SSL] [LZO] [EPOLL] built on Sep 20 2007
Wed Jan 28 03:48:09 2009 IMPORTANT: OpenVPN's default port number is now 1194, based on an official port number assignment by IANA.
OpenVPN 2.0-beta16 and earlier used 5000 as the default port.
Wed Jan 28 03:48:09 2009 TUN/TAP device tun0 opened
Wed Jan 28 03:48:09 2009 ifconfig tun0 192.168.0.1 pointopoint 192.168.0.2 mtu 1500
Wed Jan 28 03:48:09 2009 UDPv4 link local (bound): [undef]:1194
Wed Jan 28 03:48:09 2009 UDPv4 link remote: [undef]

Parameter "--dev tun" instructs an OpenVPN application to use a virtual network interface TUN. The following parameter "--ifconfig 192.168.0.1 192.168.0.2" specifies IP addresses for both sides of virtual tunnel. OpenVPN consequently sets a virtual network interface tun0 to an IP address 192.168.0.1 and will enable a slot for a connection form a OpenVPN client on a IP address 192.168.0.2. Last parameter "--secret staticVPN.key" specifies a file with Static Symmetric Key created in the previous step.

Let's confirm a correctness of the previous statements with ifconfig command:

linux_VPN_Server:~# ifconfig tun0
tun0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
inet addr:192.168.0.1 P-t-P:192.168.0.2 Mask:255.255.255.255
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)

Setting up VPN Client

The procedure for setting up a OpneVPN client is very similar the the one which was used to set up a OpenVPN server. At this point we assume established connecton via 10.0.0.0 netowrk, client has installed and ready to use an OpenVPN application as well as a Symmetric key generated previously was copied over to the client by means of USB key or SCP. If this is the case nothing can stop us to start a OpenVPN client:

linux_VPN_Client:~# ifconfig eth0
eth0 Link encap:Ethernet HWaddr 00:0C:29:00:C1:42
inet addr:10.1.1.4 Bcast:10.255.255.255 Mask:255.0.0.0
inet6 addr: fe80::20c:29ff:fe00:c142/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:456 errors:0 dropped:0 overruns:0 frame:0
TX packets:293 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:434285 (424.1 KiB) TX bytes:28413 (27.7 KiB)
Interrupt:169 Base address:0x2000

Start Client

Following command an paramaters can be used to start a OpenVPN client with static symmetric key:

linux_VPN_Client:~# openvpn --remote 10.1.1.3 --dev tun --ifconfig 192.168.0.2 192.168.0.1 --secret staticVPN.key
Wed Jan 28 03:51:02 2009 OpenVPN 2.0.9 i486-pc-linux-gnu [SSL] [LZO] [EPOLL] built on Sep 20 2007
Wed Jan 28 03:51:02 2009 IMPORTANT: OpenVPN's default port number is now 1194, based on an official port number assignment by IANA.
OpenVPN 2.0-beta16 and earlier used 5000 as the default port.
Wed Jan 28 03:51:02 2009 TUN/TAP device tun0 opened
Wed Jan 28 03:51:02 2009 ifconfig tun0 192.168.0.2 pointopoint 192.168.0.1 mtu 1500
Wed Jan 28 03:51:02 2009 UDPv4 link local (bound): [undef]:1194
Wed Jan 28 03:51:02 2009 UDPv4 link remote: 10.1.1.3:1194

Parameter "--remote 10.1.1.3" speciefies a real IP address of the OpenVPN server which is waiting for a connection and therefore a OpenVPN client will connect to socket 10.1.1.3:1194/UDP. rest of the parameters has a exactly the same meaning as it was in case of OpenVPN server. The only difference is an order of IP addresses which are passed to the "--ifconfig" parameter. This way an OpenVPN application sets a local tun0 virtual network interface to 192.168.0.2 and will expect the OpenVPN Server to be set on 192.168.0.1.

Agian confirm a corectenss of of these settings by ifconfig command:

linux_VPN_Client:~# ifconfig tun0
tun0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
inet addr:192.168.0.2 P-t-P:192.168.0.1 Mask:255.255.255.255
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)

Testing A VPN Connection

OpenVPN server and client now uses a tun0 virtual network interface to maintain a encrypted virtual tunnel connection. OpenVPN server's tun0 interface is set to 192.168.0.1 and OpenVPN client's tn0 interface is set to 192.168.0.2.

linux_VPN_Server:~# ifconfig
eth0 Link encap:Ethernet HWaddr 00:0C:29:70:5A:F7
inet addr:10.1.1.3 Bcast:10.255.255.255 Mask:255.0.0.0
inet6 addr: fe80::20c:29ff:fe70:5af7/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:1264 errors:0 dropped:0 overruns:0 frame:0
TX packets:835 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:507743 (495.8 KiB) TX bytes:105283 (102.8 KiB)
Interrupt:169 Base address:0x2000

lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)

tun0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
inet addr:192.168.0.1 P-t-P:192.168.0.2 Mask:255.255.255.255
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)

linux_VPN_Client:~# ifconfig
eth0 Link encap:Ethernet HWaddr 00:0C:29:00:C1:42
inet addr:10.1.1.4 Bcast:10.255.255.255 Mask:255.0.0.0
inet6 addr: fe80::20c:29ff:fe00:c142/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:1953 errors:0 dropped:0 overruns:0 frame:0
TX packets:1376 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:569341 (555.9 KiB) TX bytes:372027 (363.3 KiB)
Interrupt:169 Base address:0x2000

lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)

tun0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
inet addr:192.168.0.2 P-t-P:192.168.0.1 Mask:255.255.255.255
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)

If everything went smoothly and there is no firewall set between both endpoint which may interfere with the VPN tunnel, it should be easy to confirm a VPN connection with ping command.

linux_VPN_Server:~# ping -c 5 192.168.0.2
PING 192.168.0.2 (192.168.0.2) 56(84) bytes of data.
64 bytes from 192.168.0.2: icmp_seq=1 ttl=64 time=3.24 ms
64 bytes from 192.168.0.2: icmp_seq=2 ttl=64 time=4.30 ms
64 bytes from 192.168.0.2: icmp_seq=3 ttl=64 time=1.76 ms
64 bytes from 192.168.0.2: icmp_seq=4 ttl=64 time=1.83 ms
64 bytes from 192.168.0.2: icmp_seq=5 ttl=64 time=2.52 ms

--- 192.168.0.2 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4012ms
rtt min/avg/max/mdev = 1.766/2.733/4.305/0.952 ms

If at the same time we would start a tcpdump program on the OpenVPN client's virtual tun0 network interface we see an ICMP packets transmitted by ping program, including a replay packets.

linux_VPN_Client:~# tcpdump -i tun0
03:54:11.648040 IP 192.168.0.1 > 192.168.0.2: ICMP echo request, id 32520, seq 1, length 64

However on the OpenVPN client's real eth0 network interface the tcpdump program will produce a following ouptut:

linux_VPN_Client:~# tcpdump -i eth0
03:54:11.803616 IP 10.1.1.3.openvpn > 10.1.1.3.openvpn: UDP, length 124

This output from a tcpdump program can be used as a proof of what we have learn previously, that a packets from a virtual tun0 network interface are encapsulated into public network packets and are sent to the recipient encrypted via single 1194/UDP port.
Using a OpenVPN configuration files

Previous VPN tunnel example used a number of arguments and parameters passed on the command line to create a VPN connection. Although, almost every OpenVPN configuration directive can be passed to the openvpn command from the command line, this can sometimes become a very tiresome work. Therefore, we should complete this section on how to create a VPN connection using a Static Symmetric Key and OpenVPN configuration files. Here is a solution which involves a configuration files to achieve the same goal as shown previously.

OpenVPN Server config file

Create a vpn-server.conf file with a following content:

# OpenVPN configuration file for VPN SERVER
dev tun
ifconfig 192.168.0.1 192.168.0.2
secret /root/staticVPN.key
comp-lzo
keepalive 10 60
ping-timer-rem
persist-tun
persist-key
user openvpn
group openvpn
daemon


OpenVPN Client config file

Create a vpn-client.conf file with a following content:

# OpenVPN configuration file for VPN CLIENT
dev tun
remote 10.1.1.3
ifconfig 192.168.0.2 192.168.0.1
secret /root/staticVPN.key
comp-lzo
keepalive 10 60
ping-timer-rem
persist-tun
persist-key
user openvpn
group openvpn
daemon



Explanation of OpenVPN configuration directives

* dev - use a TUN virtual network device
* remote - specifies a IP address or name of a VPN Server
* ifconfig - specifies local and remote endpoint
* secret - a path to the pre-shared static key file
* comp-lzo - enable a fast LZO data compression
* keepalive - keep connection alive by sending a regular ping packets, in our case the ping packet is sent every 10 seconds where reply packet must come within 60 seconds otherwise assume that the other endpoint is down.
* ping-timer-rem - should be used only on VPN server side where daemon started without explicit remote IP address, this way timeout starts only after VPN client connection.
* persist-tun - do not re-create a virtual network interface TUN after automatic restart
* persist-key - no need to read pre-shared static key file again after automatic restart
* user - run openvpn tunnel a user openvpn
* group - run openvpn tunnel a group openvpn
* daemon - once the initialization functions are completed run in the background as a daemon

It is time to put those two OpenVPN configuration files into the action. As stated in both config files we need to create an openvpn user and group first. OpenVPN can run as a root. However, run a vpn tunnel as a non-privileged user "openvpn" is a smart move, and it will greatly enhance a security of your hosts. To create an openvpn group an addgroup command can be used: NOTE: openvpn user and group need to be created on both sides of the VPN tunnel (VPN Server and VPN Clients )

# addgroup openvpn

Now, that "openvpn" group is ready we can create a "openvpn" user.

# useradd --shell=/bin/false -g openvpn openvpn

At this point we are ready to engage both configuration files in OpenVPN tunnel creation:

Start OpenVPN Server:

linux_VPN_Server:~# openvpn --config /root/vpn-server.conf
linux_VPN_Server:~# ps aux | grep openvpn
openvpn 2310 0.2 0.6 4060 988 ? Ss 01:00 0:00 openvpn --config vpn-server.conf
root 2313 0.0 0.1 1512 224 pts/1 R+ 01:00 0:00 grep openvpn

Start OpenVPN Client:

linux_VPN_Client:~# openvpn --config /root/vpn-client.conf
linux_VPN_Client:~# ps aux | grep openvpn
openvpn 2317 0.8 0.7 4060 1188 ? Ss 01:16 0:00 openvpn --config vpn-client.conf
root 2319 0.0 0.4 2852 704 pts/0 S+ 01:16 0:00 grep openvpn

Test VPN Connection:

linux_VPN_Client:~# ping 192.168.0.1
PING 192.168.0.1 (192.168.0.1) 56(84) bytes of data.
64 bytes from 192.168.0.1: icmp_seq=1 ttl=64 time=8.50 ms
64 bytes from 192.168.0.1: icmp_seq=2 ttl=64 time=4.32 ms

--- 192.168.0.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1005ms
rtt min/avg/max/mdev = 4.327/6.416/8.506/2.091 ms

VPN Connection with Public Key Encryption

If you have followed this article from the begging up to this point, you may already know some basics on how Virtual Private Network works as well as you have established a VPN connection using Symmetric Key Encryption. Prior to the establishment of a VPN connection using Symmetric Key Encryption both VPN endpoints need to exchange a symmetric key first. Symmetric key needs to be exchanged securely using some private medium. In case, that company has a large number of employees and each employee needs to exchange symmetric key with anyone who wishes to establish VPN connection with, this task can become very tedious, not to mention that a key can be disclosed to the public somewhere on the way and the whole process would need to start again. This is where it comes to the Public key infrastructure (PKI).
Public key infrastructure

To avoid a public key exchange chaos when using a mesh like model, we could delegate one employee as a Certification Authority ( CA ) who will be responsible for keeping a record of all public keys. The aim of CA will be to collect all private keys from all employees and sign them with CA's private key - to issue a certificate.


If anyone would like to confirm a document's signature created by any other employee, s|he would first use a CA's public key to confirm a sender's public key ( certificate ). Once the sender's public key is confirmed, this key can be further used to confirm a signature of the actual document. Since every peer sends it's own CA signed certificate, only what needs to be done, is just to redistribute CA's public key to every employee.
What needs to be done

To reduce a complexity, let's briefly describe steps which need to be done in order to create a VPN connection using OpenVPN and Symmetric Key Encryption: First we would need to establish Certification Authority. For this we will be using our VPN-Server with IP 10.1.1.3 . Note, that you can establish CA on any other system. The fact that we intend to have CA and vpn-server on the same system as our VPN-Server, is just matter of convenience. This step will produce a CA's self-signed public key ( certificate ) as well as matching private key.

In the next step, we will generate a server's and client's Certificate Signing Request (CSR) and the outcome would be CSR also private key for both peers ( server & client ). Note, that both operations will be done separately on the server and client side. This way we do not have to transfer a client's private key over unsecured connection.

Next we would need to transfer client's CSR to the server where we would sign both server's and clients requests using CA's private key. This will produce two signed certificates one for a server and one for a client.

In the next step, we would transfer client's signed certificate to the client along with CA's public key.

Before we start, make sure that you have an openssl package installed on both systems ( vpn-client and vpn-server ):

apt-get install openssl

and that username "openvpn" and "openvpn" group does exist on both endpoints ( vpn-client and vpn-server ) of your future VPN connection.

# addgroup openvpn
# useradd --shell=/bin/false -g openvpn openvpn

Establishment of Certification Authority

The following command will generate a CA self-signed certificate and private key. Which is all what we need, in order to be able to sign CSRs.

linux_VPN_Server:~#
openssl req -new -x509 -extensions v3_ca -keyout ca-private-key.pem -out ca-certificate.pem -days 365
linux_VPN_Server:~#

You will need to supply some details and more importantly pass-phrase which you would use to sign CSR's. The output will look something like this:

linux_VPN_Server:~# openssl req -new -x509 -extensions v3_ca -keyout ca-private-key.pem -out ca-certificate.pem -days 365
Generating a 1024 bit RSA private key
...............++++++
...++++++
writing new private key to 'ca-private-key.pem'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:SK
State or Province Name (full name) [Some-State]:Slovakia
Locality Name (eg, city) []:Bratislava
Organization Name (eg, company) [Internet Widgits Pty Ltd]:linuxconfig.org
Organizational Unit Name (eg, section) []: Certificate Authority ( CA )
Common Name (eg, YOUR name) []:Certificate Authority ( CA )
Email Address []:
linux_VPN_Server:~#

If everything went well, now you have established your own CA ready to sign CSR. You can find two new files in a directory from where you have issued openssl command:

linux_VPN_Server:~# ls
ca-certificate.pem ca-private-key.pem
linux_VPN_Server:~#

Generate a Certificate Signing Request

Our CA is ready, so at this point we need to create a Certificate Signing Request for our vpn-server and vpn-client. You will be asked to enter some details in regard to your company. It is important that "Common Name" reflects your IP address or a fully qualified domain name (or FQDN) of the system the certificate is intended for.

linux_VPN_Server:~# openssl req -new -nodes -out vpn-server-CSR.pem
Generating a 1024 bit RSA private key
..........................++++++
............................................++++++
writing new private key to 'privkey.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:SK
State or Province Name (full name) [Some-State]:Slovakia
Locality Name (eg, city) []:Bratislava
Organization Name (eg, company) [Internet Widgits Pty Ltd]:linuxconfig.org
Organizational Unit Name (eg, section) []:VPN-SERVER
Common Name (eg, YOUR name) []:10.1.1.3
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
linux_VPN_Server:~#

After creating a Certificate Signing Request you shoud have accquired two new files.

* vpn-server-CSR.pem - vpn-server Certificate Signing Request
* privkey.pem - vpn-server private key

linux_VPN_Server:~# ls
ca-certificate.pem ca-private-key.pem privkey.pem vpn-server-CSR.pem
linux_VPN_Server:~#

linux_VPN_Client:~# openssl req -new -nodes -out vpn-client-CSR.pem
Generating a 1024 bit RSA private key
............++++++
.....++++++
writing new private key to 'privkey.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:SK
State or Province Name (full name) [Some-State]:Slovakia
Locality Name (eg, city) []:Bratislava
Organization Name (eg, company) [Internet Widgits Pty Ltd]:linuxconfig.org
Organizational Unit Name (eg, section) []:VPN-CLIENT
Common Name (eg, YOUR name) []:10.1.1.4
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
linux_VPN_Client:~#

After creating a Certificate Signing Request you shoud have accquired two new files.

* vpn-client-CSR.pem - vpn-client Certificate Signing Request
* privkey.pem - vpn-client private key

linux_VPN_Client:~# ls
privkey.pem vpn-client-CSR.pem
linux_VPN_Client:~#

Since our signing Certificate Authority resides on our vpn-server we copy clients signing a request to be signed there:

linux_VPN_Client:~# scp vpn-client-CSR.pem root@10.1.1.3:~/
root@10.1.1.3's password:
vpn-client-CSR.pem 100% 672 0.7KB/s 00:00
linux_VPN_Client:~#

Signing Certificate Signing Requests

Both Certificates Signing Requests are waiting to be signed.

* vpn-server-CSR.pem
* vpn-client-CSR.pem

For that we could create an openssl config file similar to bellow and use it with conjunction of openssl command. Use your favorite text editor and create a file called CA-openssl.config with content shown below:

linux_VPN_Server:~# cat CA-openssl.config
[ ca ]
default_ca = ca_default
[ ca_default ]
dir = .
new_certs_dir = .
private_key = ca-private-key.pem
certificate = ca-certificate.pem
database = index.txt
default_md = md5
serial = serial
default_days = 365
x509_extensions = usr_cert



policy = generic_policy
[ generic_policy ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional


[ usr_cert ]
authorityKeyIdentifier = keyid
basicConstraints = CA:FALSE
keyUsage = digitalSignature
extendedKeyUsage = serverAuth
linux_VPN_Server:~#

Certificate Authority needs to keep a track of all signed certificates ( index.txt ) and assigned a serial numbers to each of them ( serial ). Therefore, we need to create these two files:

touch index.txt; echo 01 > serial;

All is ready to sign CSR. Let's first sign vpn-server's CSR:

linux_VPN_Server:~# openssl ca -config CA-openssl.config -infiles vpn-server-CSR.pem
Using configuration from CA-openssl.config
Enter pass phrase for ca-private-key.pem:
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
countryName :PRINTABLE:'SK'
stateOrProvinceName :PRINTABLE:'Slovakia'
localityName :PRINTABLE:'Bratislava'
organizationName :PRINTABLE:'linuxconfig.org'
organizationalUnitName:PRINTABLE:'VPN-SERVER'
commonName :PRINTABLE:'10.1.1.3'
Certificate is to be certified until Feb 25 21:34:25 2010 GMT (365 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries

Server certificated is ready, we need to amend CA-openssl.config to sign VPN-Client's public key. Change line:

extendedKeyUsage = serverAuth
TO:
extendedKeyUsage = clientAuth

The following command will also do the trick:

sed 's/serverAuth/clientAuth/' CA-openssl.config > temp; mv temp CA-openssl.config

Now, we are ready to sign vpn-client's CSR:

linux_VPN_Server:~# openssl ca -config CA-openssl.config -infiles vpn-client-CSR.pem
Using configuration from CA-openssl.config
Enter pass phrase for ca-private-key.pem:
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
countryName :PRINTABLE:'SK'
stateOrProvinceName :PRINTABLE:'Slovakia'
localityName :PRINTABLE:'Bratislava'
organizationName :PRINTABLE:'linuxconfig.org'
organizationalUnitName:PRINTABLE:'VPN-CLIENT'
commonName :PRINTABLE:'10.1.1.4'
Certificate is to be certified until Feb 25 21:37:53 2010 GMT (365 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries

Signed certificates are ready to use:

* 01.pem - vpn-server certificate
* 02.pem - vpn-client certificate

linux_VPN_Server:~# ls
01.pem ca-certificate.pem ca-private-key.pem index.txt.attr index.txt.old serial vpn-client-CSR.pem
02.pem CA-openssl.config index.txt index.txt.attr.old privkey.pem serial.old vpn-server-CSR.pem
linux_VPN_Server:~#
You can see both certificates with following commands:

openssl x509 -in 01.pem -noout -text
openssl x509 -in 02.pem -noout -text

At this stage we need to copy vpn-vlient's certificate to the vpn-client system (10.1.1.4) and change the name to something like vpn-client-certificate.pem. Along with the vpn-client certificate we also need to copy a CA's certificate:

linux_VPN_Server:~# scp 02.pem root@10.1.1.4:~/vpn-client-certificate.pem
root@10.1.1.4's password:
02.pem 100% 3173 3.1KB/s 00:00
linux_VPN_Server:~# scp ca-certificate.pem root@10.1.1.4:~/
root@10.1.1.4's password:
ca-certificate.pem 100% 1367 1.3KB/s 00:00
linux_VPN_Server:~#

Change the name of vpn-server's certificate to something like vpn-server-certificate.pem

linux_VPN_Server:~# mv 01.pem vpn-server-certificate.pem
linux_VPN_Server:~#

list of files in vpn-server working directory:

linux_VPN_Server:~# ls
02.pem ca-private-key.pem index.txt.attr.old privkey.pem vpn-client-CSR.pem
ca-certificate.pem index.txt index.txt.old serial vpn-server-certificate.pem
CA-openssl.config index.txt.attr openvpn-server.conf serial.old vpn-server-CSR.pem
linux_VPN_Server:~#

Diffie-Hellman Key Agreement Protocol

Diffie-Hellman Key Agreement protocol allows two users to exchange a secret key over an insecure medium without any prior secrets. We need Diffie-Hellman Key Agreement file only on the server side of our vpn. It can be created by the following command:

linux_VPN_Server:~# openssl dhparam -out dh.pem 1024

Creating configuration files

OpenVPN configuration files will look similar to those we have created in the previous sections where we have created a virtual private network using Symmetric Key Encryption. Create files named openvpn-server.conf and openvpn-client.conf with the following content:

OpenVPN Server config file

Create a openvpn-server.conf file with a following content:

# OpenVPN server configuration file example
local 10.1.1.3
dev tun
server 192.168.0.0 255.255.0.0
ca ca-certificate.pem
cert vpn-server-certificate.pem
key privkey.pem
dh dh.pem
push "redirect-gateway"
comp-lzo
keepalive 10 60
ping-timer-rem
persist-tun
persist-key
user openvpn
group openvpn
daemon


OpenVPN Client config file

Create a openvpn-client.conf file with a following content:

# OpenVPN client configuration file example
client
dev tun
remote 10.1.1.3
tls-remote 10.1.1.3
ca ca-certificate.pem
cert vpn-client-certificate.pem
key privkey.pem
comp-lzo
keepalive 10 60
ping-timer-rem
persist-tun
persist-key
user openvpn
group openvpn
daemon
linux_VPN_Client:~#



Explanation of OpenVPN configuration directives

* dev - use a TUN virtual network device
* server - assign IP addresses to the clients from a given subnet
* ca - path to the Certificate Authority's certificate
* cert - path to the vpn-server's signed certificate
* key - path to the vpn-server's private key
* dh - path to the Diffie-Hellman Key Agreement file
* remote - specifies a IP address or name of a VPN Server
* ifconfig - specifies local and remote endpoint
* secret - a path to the pre-shared static key file
* comp-lzo - enable a fast LZO data compression
* push - push a config file to the clients. Available options are: --route, --route-gateway, --route-delay, --redirect-gateway, --ip-win32, --dhcp-option, --inactive, --ping, --ping-exit, --ping-restart, --setenv, --persist-key, --persist-tun, --echo, --comp-lzo, --socket-flags, --sndbuf, --rcvbuf
* keepalive - keep connection alive by sending a regular ping packets, in our case the ping packet is sent every 10 seconds where reply packet must come within 60 seconds otherwise assume that the other endpoint is down.
* ping-timer-rem - should be used only on VPN server side where daemon started without explicit remote IP address, this way timeout starts only after VPN client connection.
* persist-tun - do not re-create a virtual network interface TUN after automatic restart
* persist-key - no need to read pre-shared static key file again after automatic restart
* user - run openvpn tunnel a user openvpn
* group - run openvpn tunnel a group openvpn
* daemon - once the initialization functions are completed run in the background as a daemon

Start OpenVPN server

linux_VPN_Server:~# openvpn --config openvpn-server.conf
linux_VPN_Server:~# ifconfig tun0
tun0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
inet addr:192.168.0.1 P-t-P:192.168.0.2 Mask:255.255.255.255
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)

Start OpenVPN client


linux_VPN_Client:~# openvpn --config openvpn-client.conf
linux_VPN_Client:~# ifconfig tun0
tun0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
inet addr:192.168.0.6 P-t-P:192.168.0.5 Mask:255.255.255.255
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)

linux_VPN_Client:~#

Test VPN Connection

linux_VPN_Client:~# ping 192.168.0.1
PING 192.168.0.1 (192.168.0.1) 56(84) bytes of data.
64 bytes from 192.168.0.1: icmp_seq=1 ttl=64 time=0.805 ms
64 bytes from 192.168.0.1: icmp_seq=2 ttl=64 time=1.51 ms

--- 192.168.0.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 0.805/1.159/1.513/0.354 ms
linux_VPN_Client:~#

Monday, March 9, 2009

https configuration

Introduction
I recently had a need to setup a private directory on my web server that could only be accessed by a
handful of selected people. The content also needed to be encrypted in transit. This mini-HOWTO
details how I did this on a Red Hat 8.0/Apache 2.0.40 server using mod_ssl and OpenSSL (0.9.6b and
higher). Here are the goals of this small project:
Require HIGH or MEDIUM level SSL/TLS encryption at the transport (TCP) layer

Browser must use SSLv3 or TLSv1, not SSLv2

Require username/password authentication for some subdirectories

Learn about TLS certificates

Be a mini-CA (Certificate Authority)

Use a non-standard port to keep most of the port-scanning riffraff away

Create client certificates, and require them for specific directories

The key to this whole system is the SSL/TLS protocol. SSL stands for Secure Sockets Layer, and it was
developed by Netscape to enable secure transactions over the Web. It operates between the TCP layer
and the HTTP application layer. TLSv1 is the IETF standard implementation, based on SSLv3. TLS
stands for Transport Layer Security.
Assumptions/Prerequisites
First and foremost, this document assumes that you are using some flavor of Linux, Apache 2.0.x, and
that you have OpenSSL installed. These particular instructions were generated using Red Hat 8.0. You
should also check out the excellent documentation at Apache.Org. Other assumptions:
This will be used over the Internet

Your DNS configuration is correct (hostname=FQDN, PTR records O.K., etc.)

Your firewall is setup to allow connections on the chosen https:// port

You have a second machine with Mozilla or another modern browser for testing purposes

In these examples, my FQDN and hostname is: mars.vanemery.com

Most client tests were performed with the Mozilla web browser. Mozilla is the "reference platform".
Step 1: Setup your own CA (Certificate Authority)
In order to run a secure (SSL/TLS encrypted) web server, you have to have a private key and a
certificate for the server. For a commercial web site, you will probably want to purchase a certificate
signed by a well-known root CA. For Intranet or special-purpose uses like this, you can be your own
CA. This is done with the OpenSSL tools.
Here, we will make a private CA key and a private CA X.509 certificate. We will also make a directory
for the certs and keys:
[root]# mkdir /root/CA
[root]# chmod 0770 /root/CA
[root]# cd /root/CA
[root]# openssl genrsa -des3 -out my-ca.key 2048
Generating RSA private key, 2048 bit long modulus
.....................................................+++
...................................................+++
e is 65537 (0x10001)
Enter PEM pass phrase:
Verifying password - Enter PEM pass phrase:
[root]# openssl req -new -x509 -days 3650 -key my-ca.key -out my-ca.crt
Using configuration from /usr/share/ssl/openssl.cnf
Enter PEM pass phrase:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [GB]:US
State or Province Name (full name) [Berkshire]:Kentucky
Locality Name (eg, city) [Newbury]:Fayette County
Organization Name (eg, company) [My Company Ltd]:VanEmery.Com
Organizational Unit Name (eg, section) []:Certificate Authority
Common Name (eg, your name or your server's hostname) []:VanEmery.Com CA
Email Address []:hostmaster@vanemery.com
[root]# openssl x509 -in my-ca.crt -text -noout
Notes: The first OpenSSL command makes the key. The second command makes the X.509 certificate
with a 10-year lifetime. The third command lets you view the completed certificate. Make sure that you
keep the password in a safe place, you will need this every time you sign another certificate! You will
probably also want to make backups of the cert and key and lock them in a safe place.
Step 2: Make a key and a certificate for the web server:
Now, we have to make an X.509 certificate and corresponding private key for the web server. Rather
than creating a certificate directly, we will create a key and a certificate request, then "sign" the
certificate request with the CA key we made in Step 1. You can make keys for multiple web servers this
way. One thing to note is that SSL/TLS private keys for web servers need to be either 512 or 1024 bits.
Any other key size may be incompatible with certain browsers.
[root]# openssl genrsa -des3 -out mars-server.key 1024
Generating RSA private key, 1024 bit long modulus
....++++++
.++++++
e is 65537 (0x10001)
Enter PEM pass phrase:
Verifying password - Enter PEM pass phrase:
[root]# openssl req -new -key mars-server.key -out mars-server.csr
Using configuration from /usr/share/ssl/openssl.cnf
Enter PEM pass phrase:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [GB]:TW
State or Province Name (full name) [Berkshire]:Taipei County
Locality Name (eg, city) [Newbury]:Nankang
Organization Name (eg, company) [My Company Ltd]:VanEmery.Com
Organizational Unit Name (eg, section) []:Web Services
Common Name (eg, your name or your server's hostname) []:mars.vanemery.com <===
This must be the real FQDN of your server!!!
Email Address []:hostmaster@vanemery.com
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
# openssl x509 -req -in mars-server.csr -out mars-server.crt -sha1 -CA my-ca.crt
-CAkey my-ca.key -CAcreateserial -days 3650
Signature ok
subject=/C=TW/ST=Taipei County/L=Nankang/O=VanEmery.Com/OU=Web
Services/CN=mars.vanemery.com/Email=hostmaster@vanemery.com
Getting CA Private Key
Enter PEM pass phrase:
[root]# openssl x509 -in mars-server.crt -text -noout
Make sure that your server name is the same as the FQDN that your clients will use when connecting to
your site. Also, let's get in the habit of protecting our keys with appropriate permissions:
[root]# chmod 0400 *.key
Now, we need to move the new keys and certs into the proper directories in the /etc/httpd hierarchy:
[root]# cp mars-server.crt /etc/httpd/conf/ssl.crt
[root]# cp mars-server.key /etc/httpd/conf/ssl.key
[root]# cp my-ca.crt /etc/httpd/conf/ssl.crt
Step 3: Create directories and files for the secure web service
I do not want the secure branch of my webserver directory tree to be part of my "insecure" branch that
serves unencrypted files. My normal web root directory is /var/www/html . The document root for
the secure web server will be located at /var/www/SSL .
[root]# mkdir /var/www/SSL
[root]# chmod 0775 /var/www/SSL
[root]# cd /var/www/SSL
[root]# mkdir Passneeded
[root]# mkdir Certneeded
[root]# mkdir PassAndCert
For testing purposes, I added this very simple test SSL index file into /var/www/SSL . Save it as
index.html . Copy some JPEG files and text files into each directory, so that there will be
something to look at/retrieve in each directory.
Step 4: Configure the Apache web server
On a default Red Hat 8.0 install, there are two config files that concern us: httpd.conf and
ssl.conf. All of our changes will be made in the /etc/httpd/conf.d/ssl.conf file. It is
not necessary to modify the httpd.conf file to accomplish our goals on a stock Red Hat 8.0 server.
Here are the changes/additions to ssl.conf :
DocumentRoot "/var/www/SSL"
# Note that the FQDN and server hostname must go here - clients will not be able to
connect, otherwise!
ServerName mars.vanemery.com:443
ServerAdmin webmaster@vanemery.com
# Here, I am allowing only "high" and "medium" security key lengths.
SSLCipherSuite HIGH:MEDIUM
# Here I am allowing SSLv3 and TLSv1, I am NOT allowing the old SSLv2.
SSLProtocol all -SSLv2
# Server Certificate:
SSLCertificateFile /etc/httpd/conf/ssl.crt/mars-server.crt
# Server Private Key:
SSLCertificateKeyFile /etc/httpd/conf/ssl.key/mars-server.key
# Server Certificate Chain:
SSLCertificateChainFile /etc/httpd/conf/ssl.crt/my-ca.crt
# Certificate Authority (CA):
SSLCACertificateFile /etc/httpd/conf/ssl.crt/my-ca.crt
# This is needed so that you can use auto-indexing for some directories in the
# /var/www/SSL directory branch. This can be handy if you would like to have
# a list of sensitive files for people to download.

Options Indexes
AllowOverride None
Allow from from all
Order allow,deny

The working config file up to this point is located here.
Step 5: Start the web server and test
Run the following commands to start the the Apache web server:
[root]# /etc/init.d/httpd start
Starting httpd: Apache/2.0.40 mod_ssl/2.0.40 (Pass Phrase Dialog)
Some of your private key files are encrypted for security reasons.
In order to read them you have to provide us with the pass phrases.
Server mars.vanemery.com:443 (RSA)
Enter pass phrase:
Ok: Pass Phrase Dialog successful.
[ OK ]
Note that you will have to enter the password for your server key in order to start the server. You will
also have to do this during boot if you have httpd configured to start automatically.
Make sure that the web server is now listening on the SSL/TLS port, TCP port 443:
[root]# netstat -tna
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN
In order to test that your SSL/TLS web server is running, you will now need to connect to it with a
browser. The URL you use should be https://yourservername.com. You will probably get a
warning prompt about the Certificate Authority (CA) being unknown. You can view the certificate
properties, which will look familiar because you created the cert yourself. You can save the cert in your
browser, or import the my-ca.crt file into your browser as a new CA. How you do this will depend
on which browser you are using. I had no problems doing this with Mozilla.
Step 6: Require simple username/password auth for one of the directories:
We want to require a valid username and password for the /var/www/SSL/Passneeded directory.
The username and password will be encrypted in transit as part of the TCP stream. We will need to
setup the access control directives, as well as use the htpasswd command to add the
username/password pairs.
[root]# htpasswd -c -m /etc/httpd/.htpasswd joe
New password:
Re-type new password:
Adding password for user joe
[root]# htpasswd -m /etc/httpd/.htpasswd john
New password:
Re-type new password:
Adding password for user john
[root]# chown apache.root /etc/httpd/.htpasswd
[root]# chmod 0460 /etc/httpd/.htpasswd
Now, we need to tell Apache to require a username/password to access the Passneeded directory.
Here is what we will add to /etc/httpd/conf.d/ssl.conf file:

AuthType Basic
AuthName "Username and Password Required"
AuthUserFile /etc/httpd/.htpasswd
Require valid-user

Now, restart the webserver with /etc/init.d/httpd restart. When you try to access the
Passneeded directory from a web browser, you should be prompted for a username and password. If
you enter incorrect information, you should be denied access.
The config file (up to this point) is located here.
Step 7: Change the TCP port that Apache SSL/TLS listens on:
Since this is a private, special-purpose secure web server, you may want to change the TCP port from
443 to something else. This will make it just a little more difficult for crackers to locate via automated
network scans. For this excercise, we will change the port to TCP 444 by editing three lines in the
ssl.conf configuration file. Make the following changes to the ssl.conf :
Listen 444

ServerName mars.vanemery.com:444
Now, restart Apache and look at the listening ports:
[root]# /etc/init.d/httpd restart
[root]# netstat -tna
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:444 0.0.0.0:* LISTEN
Now, you should be able to connect to the server with this URL:
https://yourservername.com:444
The config file including this change is located here. If you are having any problems, you may want to
consult the ssl_* logfiles in the /var/log/httpd directory. These can be quite useful for trouble-
shooting.
Congratulations, you have now configured a basic SSL/TLS web server!
Creating Client Certificates for Authentication
Now, let's say that we want a stronger method of authenticating clients, one that is not as susceptible to
password guessing and shoulder-surfing. What can we do? We can create an SSL/TLS client
certificate. The certificate has to be digitally signed by a CA that the server trusts, the user has to have
the client loaded in his browser, and the user has to know a pass phrase to use it. The certificate itself
uses strong, public-key cryptography. We can make such a certificate with our OpenSSL toolkit.
A note on certificate formats: The server and CA certs that we have been using up to now are encoded
in PEM format, which uses ASCII characters. For some reason, the industry-standard client certs used
in web browsers are encoded in the PKCS#12 format, which cannot be viewed as simple text. It is a
binary file. We will now create a client cert by following these steps:
Create a new private key and certificate request

Sign the certificate request, thereby creating the client certificate

Generate the PKCS#12 cert file

View information about the PKCS#12 cert

Import the PKCS#12 client cert into your browser

Test!

[root]# cd /root/CA
[root]# openssl genrsa -des3 -out van-c.key 1024
Generating RSA private key, 1024 bit long modulus
..++++++
........................................................................++++++
e is 65537 (0x10001)
Enter PEM pass phrase:
Verifying password - Enter PEM pass phrase:
[root]# openssl req -new -key van-c.key -out van-c.csr
Using configuration from /usr/share/ssl/openssl.cnf
Enter PEM pass phrase:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [GB]:TW
State or Province Name (full name) [Berkshire]:Taipei County
Locality Name (eg, city) [Newbury]:Nankang
Organization Name (eg, company) [My Company Ltd]:VanEmery.Com
Organizational Unit Name (eg, section) []:Sales
Common Name (eg, your name or your server's hostname) []:Van Emery
Email Address []:ve@vanemery.com
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
# openssl x509 -req -in van-c.csr -out van-c.crt -sha1 -CA my-ca.crt -CAkey my-
ca.key -CAcreateserial -days 3650
[root]# openssl pkcs12 -export -in van-c.crt -inkey van-c.key -name "Van Emery
Cert" -out van-c.p12
[root]# openssl pkcs12 -in van-c.p12 -clcerts -nokeys -info
Note: The "export password" is all the end-user needs to know. This is what you will be asked for when
installing the certificate in a browser.
Now move the van-c.p12 file to your client machine and import it into your web browser. This is
usually done your browser's "Preferences" section under "Privacy and Security", "Certificates",
"Manage Certificates". You may be asked to input a Software Security Device Master Password. DO
NOT FORGET this password! You will also be asked for the client certificate's export password.
Configure Apache to require client certificates for a specific directory:
In order to require client certificates for the /var/www/SSL/Certneeded directory, you will need
to add the following lines to the /etc/httpd/conf.d/ssl.conf configuration file:

SSLVerifyClient require
SSLVerifyDepth 1

Now, restart Apache with /etc/init.d/httpd restart. You can now connect from your client
machine browser to the secure webserver at https://yoursevername.com:444. You should
now be able to click on the "Client Certificate Required" link and view the files in that directory. I
successfully tested my client certificate with:
Mozilla 1.4 and 1.2.1 on Linux

Mozilla 1.4 on Windows 2000

Internet Explorer 6 on Windows 2000

Opera 7 on Linux

Konqueror 3.0.5 on Linux

Galeon 1.2.7 on Linux

If you connect from a different browser that does not have the certificate installed, you will not be able
to enter the directory at all. When you look in your /var/www/httpd/ssl_error_log file, you
will see this error:
[17:41:41] [error] Re-negotiation handshake failed: Not accepted by client!?
[17:41:41] [error] SSL handshake failed (server mars.vanemery.com:444, client
192.168.1.191)
[17:41:41] [error] SSL Library Error: 336105671
error:140890C7:lib(20):func(137):reason(199)
Here is the config file that includes all of the changes up to this point.
Configure Apache to require client certificates AND username/password for a
specific directory:
If you are super paranoid, you may want to require a client certificate AND username/password. This is
totally up to you, and it is easy to do.
For this simple example, we will use the .htpasswd file and usernames/passwords that have already
been created earlier. This will force clients to have a certificate and a valid username/password pair in
order to access the /var/www/SSL/PassAndCert. All we have to do is add the following section
to the /etc/httpd/conf.d/ssl.conf configuration file:

SSLVerifyClient require
SSLVerifyDepth 1
AuthType Basic
AuthName "Restricted Area"
AuthUserFile /etc/httpd/.htpasswd
Require valid-user

Now, restart Apache with /etc/init.d/httpd restart. Connect from your client machine
browser to the secure webserver. When you click the link for the "Client Cert AND Password
Required" directory, you should be prompted for a username and password. You should then be able to
view the directory contents. If you delete your client certificate from the browser, you will be unable to
access either directory that requires client certificates.
Final Config File (The ssl.conf config file which incorporates ALL of the changes):
Complete Config with All Remarks
Complete Config with Minimal Remarks
Web Server Key Password:
You have probably noticed by now that every time you restart Apache or boot your server, you are
forced to enter the password for the server key. This is a security measure, but it can be inconvenient. If
you would like to make an insecure server key that will allow Apache to start automatically at boot
time, then there is a way to do this. In my case, I don't run an e-commerce site and I'm not worried
about someone else creating a fake VanEmery.Com secure web site. It is more likely that a power
outage will occur that will cause my server to reboot while I am not around, so I want it to boot without
requiring a password. The choice is yours...
Here is how you do it:
[root]# cd /etc/httpd/conf/ssl.key
[root]# cp mars-server.key mars-server.key.org
[root]# openssl rsa -in mars-server.key.org -out mars-server.key
[root]# chmod 0400 mars-server*
Now, you should be able to restart Apache or boot your server without having to input the password.
This may also be a very good time to copy all the keys and certificates that you made to floppy or
CD. You can imagine what a pain it would be if you lost all of your keys and certs due to a disk failure.
You may even want to make paper copies of the PEM encoded certificates and keys, which use ASCII
text. Lock them in a secure place, along with any passwords.
Conclusion/Final Comments
As you can see, setting up a secure web server for some specific function is not that difficult. All the
tools are included with a standard GNU/Linux distribution. OpenSSL is a fantastic Open Source toolkit
that can be used in a number of applications. For example, you can use it to run files through different
hashing functions, handle S/MIME encrypted mail, or encrypt & decrypt files.
In order to use Apache as a high-volume e-commerce server with SSL/TLS, you will probably need to
do more configuration and hardware tuning. You may need to buy and configure a hardware crypto
accelerator card. You will almost certainly want to purchase a "real" server certificate signed by
Entrust, Thawte, or one of the other root-level CAs.
In any event, you now have a good feel for all the pieces, parts, and protocols that make it work! If you
have any comments or corrections, please zap me an e-mail here: webmaster [at] vanemery.com