Securing 802.11 with OpenBSD

Jarkko Turkulainen Sorry, you have to write it!

What's new in this document

Table of Contents


1. Introduction

We have all heard about the security disasters of 802.11 WLAN WEP encryption. Products like Airsnort sniff the WLAN segments and can use the captured traffic to recover crypto keys. This was also in my mind when I was installing my first production WLAN.

How can we make sure that our WLAN traffic is useless for all unauthorized listeners? From the OSI layer 3 point of view, 802.11 is not different than any other LAN technique (ethernet, token ring..). This makes it possible to use standard solutions for securing IP traffic.

This document describes an implementation of 802.11 wireless LAN access point and VPN gateway using the OpenBSD operating system and how to secure the WLAN traffic with IPsec. We are going to utilize many of the hot Internet buzzwords, including

2. Network architecture

In the most simple setup (the one that I have implemented), there is only one OpenBSD machine that acts as a VPN gateway, firewall and iBSS access point. iBSS, "independent base service set" is basically the same as the old Lucent Ad-hoc mode.

Using an external, "real" BSS-mode access point is also perfectly possible. The access points are wired to same physical network as the OpenBSD box via hub/switch. Of course, you need two ethernet interfaces in this setup. If your network is large and spans over multiple rooms/buildings, this is the only way to go.

Update: It is possible to build a BSS-mode access point using a so called "Host AP mode" in Intersil Prism2 chips. Check out my cool (and not only thermally) OpenBSD 802.11b access point project.

The most important thing to remember with either of these configurations is routing. 802.11 network has to found behind the VPN gateway interface eth0. Most of the time, this involves installing a static route. It should be noted that even if you are using HW access points, the VPN gateway acts as a router to 802.11 network - not bridge!

3. OpenBSD configuration

The configuration has been tested only with OpenBSD 3.0. Most of the things should work with earlier versions - the only notable change is probably pf, the new packet filter for OpenBSD. It uses almost identical syntax as the old ipfilter, it should be fairly simple to convert the few rules of the section 3.7.

3.1 WLAN interface setup

If your setup consists of HW access points, you can skip this section.

The wireless interface is easy to setup. Plug in the interface card and write the configuration in /etc/hostname.in where "in" is the name of the interface. Please read the file INSTALL.i386 for supported interface cards. In my case, the card is Lucent Orinoco silver PCMCIA card plugged in PCMCIA->ISA bridge board (Vadem VG469). My /etc/hostname.wi0 is


inet 10.10.10.10 255.255.255.0
!wicontrol \$if -e 0 -p 1 -t 3 -c 1 -n klake -q klake -s openbsd

Change the IP (10.10.10.10), mask (255.255.255.0), channel (3), network names (klake) and station name (openbsd). You may also have to change the device name (wi0), check out your dmesg(8). Note that the WEP encryption is set off (e = 0) - we are speaking only IPsec here.

3.2 DHCP server

For the convenience of our users, we want the clients to get their network setup via the DHCP server. The most obvious place for this is the OpenBSD box. Fortunately, this is easy to setup. Edit the file /etc/dhcpd.conf:


shared-network LOCAL-NET {
        option  domain-name "www.klake.org";
        option  domain-name-servers 10.10.9.53;

        subnet 10.10.10.0 netmask 255.255.255.0 {
                option routers 10.10.10.10;

                range 10.10.10.129 10.10.10.254;
        }
}

Again, change the names, IP addresses and netmasks. Next, edit the file /etc/rc.conf and change the line


dhcpd_flags="-q wi0"    # for normal use: "-q"

The flag "-q" makes dhcpd silent and wi0 is the interface on the wireless side. Fire up the daemon with command


# /usr/sbin/dhcpd -q wi0

3.3 CA Certificate

Because we are configuring a (possibly unknown) number of roaming WLAN workstations, the simplest key management solution, pre-shared keys is not an option. We should go the X.509 way. This involves setting up a sort of Certificate authority (CA) for signing of the client X.509 certificates.

Setting up a public key infrastructure (PKI) using OpenSSL is documented in the isakmpd(8) manual page. You can also check out my project Simple CA for OpenBSD based VPN and skip chapters 3.3 - 3.5.

Create CA key and certificate request


# openssl genrsa -out /etc/ssl/private/ca.key 2048
# openssl req -new -key /etc/ssl/private/ca.key \
	-out /etc/ssl/private/ca.csr

Now it's time to enter your DN (Distinguished Name) and sign the certificate request with the command


# openssl x509 -req -days 730 -in /etc/ssl/private/ca.csr \
	-signkey /etc/ssl/private/ca.key \
	-extfile /etc/ssl/x509v3.cnf -extensions x509v3_CA \
	-out /etc/ssl/ca.crt
# ln -s /etc/ssl/ca.crt /etc/isakmpd/ca/ca.crt
Note that the certificate lifetime is 730 days (~ 2 years). The second command makes a symbolic link of the certificate to isakmpd default location.

You can now look at the details of the CA certificate


$ openssl x509 -in ca.crt -text -noout

        Issuer: C=FI, O=www.klake.org, CN=www.klake.org VPN CA
        Validity
            Not Before: Jan 12 16:41:50 2002 GMT
            Not After : Jan 12 16:41:50 2004 GMT
        Subject: C=FI, O=www.klake.org, CN=www.klake.org VPN CA
(only selected portions of the command output is displayed)

3.4 Server certificate

Next, we generate key and certificate request for the OpenBSD gateway. Issue the following commands as root

# openssl genrsa -out /etc/isakmpd/private/local.key 1024
# openssl req -new -key /etc/isakmpd/private/local.key \
	-out /etc/isakmpd/private/server.csr

Enter the FQDN as server CN (Common name) and proceed with the signing of the certificate


# openssl x509 -req -days 365 -in /etc/isakmpd/private/server.csr \
	-CA /etc/ssl/ca.crt \
	-CAkey /etc/ssl/private/ca.key -CAcreateserial \
	-out /etc/isakmpd/certs/local.crt

subjectAltName extension is added to certificates using a certpatch(8) utility.


# certpatch -k /etc/ssl/private/ca.key -t FQDN -i vpngw.klake.org \
	/etc/isakmpd/certs/local.crt /etc/isakmpd/certs/local.crt
Change vpngw.klake.org as the FQDN of your gateway. This value is the ID string that your VPN clients expect to see.

3.5 Client certificates

Client certificates are generated the same way as the server certificate. Some things should be considered, though. Because the clients (should) use DHCP, we don't have fixed IP or FQDN. Instead, we use UFQDN and bind the identity to e-mail address of the client.

# certpatch -k /etc/ssl/private/ca.key -t UFQDN -i noone@nowhere.com \
	client.crt client.crt
noone@nowhere.com is the subjectAltName for this client, client.crt is the X.509 certificate.

Next, we export the key and certificates


# openssl pkcs12 -export -certfile /etc/ssl/ca.crt \ 
	-inkey client.key -in client.crt -out client.p12 

3.6 VPN configuration

OpenBSD IKE daemon, isakmpd is configured with file /etc/isakmpd/isakmpd.conf. Details of the file is documented in manual page isakmpd.conf(5). The following example file should work if the CA and server certificates are in default locations (see sections 3.3 and 3.4).


# Global options
[General]
Retransmits=            5
Exchange-max-time=      120
Check-interval=         60

# X.509 certificate locations
[X509-certificates]
CA-directory=		/etc/isakmpd/ca/
Cert-directory=		/etc/isakmpd/certs/
Private-key=		/etc/isakmpd/private/local.key

# IKE Phase 1 & 2
[Phase 1]
Default=               	Client-phase1 
[Phase 2]
Passive-Connections=    Client-phase2

# Clients, phase 1 and 2
[Client-phase1]
Phase=                  1
Transport=              udp
Local-address=          10.10.10.10
Configuration=          Client-main-mode
ID=                     My-ID
[My-ID]
ID-type=                FQDN
Name=                   vpngw.klake.org

[Client-phase2]
Phase=                  2
Configuration=          Client-quick-mode
Local-ID=               All-networks
Remote-ID=              Unknown-address

# Network details
[All-networks]
ID-Type=                IPV4_ADDR_SUBNET
Network=                0.0.0.0
Netmask=                0.0.0.0
[Unknown-address]
ID-Type=                IPV4_ADDR
Address=                0.0.0.0

# Main -and quick mode transforms
[Client-main-mode]
DOI=                    IPSEC
EXCHANGE_TYPE=          ID_PROT
Transforms=             3DES-MD5-Client
[Client-quick-mode]
DOI=                    IPSEC
EXCHANGE_TYPE=          QUICK_MODE
Suites=                 QM-ESP-3DES-MD5-SUITE

# Encryption/Authentication suite definitions

[3DES-MD5-Client]
ENCRYPTION_ALGORITHM=   3DES_CBC
HASH_ALGORITHM=         MD5
AUTHENTICATION_METHOD=  RSA_SIG
GROUP_DESCRIPTION=      MODP_1536
Life=                   LIFE_9000_SECS

[QM-ESP-3DES-MD5-SUITE]
Protocols=              QM-ESP-3DES-MD5

[QM-ESP-3DES-MD5]
PROTOCOL_ID=            IPSEC_ESP
Transforms=             QM-ESP-3DES-MD5-XF

[QM-ESP-3DES-MD5-XF]
TRANSFORM_ID=           3DES
ENCAPSULATION_MODE=     TUNNEL
AUTHENTICATION_ALGORITHM=       HMAC_MD5
GROUP_DESCRIPTION=      MODP_1024
Life=                   LIFE_3600_SECS

# Lifetime definitions
[LIFE_3600_SECS]
LIFE_TYPE=              SECONDS
LIFE_DURATION=          3600,1800:7200
[LIFE_9000_SECS]
LIFE_TYPE=              SECONDS
LIFE_DURATION=          9000,4500:18000

Isakmpd also needs a second file to be present, /etc/isakmpd/isakmpd.policy. My policy file allows anyone with a non-null ESP algorithm to connect:


KeyNote-Version: 2
Authorizer: "POLICY"
Conditions: app_domain == "IPsec policy" &&
                esp_present == "yes" &&
                esp_enc_alg != "null" -> "true";

Edit the file /etc/rc.conf


isakmpd_flags=""        # for normal use: ""

Start up the daemon with command


# /sbin/isakmpd

3.7 Firewall configuration

It is not enough to protect authorized traffic from wiretapping. Your neighbor may be still able to gain access to your resources via DHCP and scan the networks behind WLAN. We must protect the WLAN interface with packet filter that allows only a very limited set of protocols through.

The following example /etc/pf.conf tries to clarify this.


########################################################################
# WLAN (wi0) traffic
########################################################################

# SSH for remote administation
pass in quick on wi0 proto tcp from 10.10.10.128/25 to 10.10.10.10/32 \
	port = 22 keep state

# dhcp requests and responses
pass in quick on wi0 proto {tcp,udp} from any port = 68 to 10.10.10.10/32 \
	port = 67
pass out quick on wi0 proto {tcp,udp} from 10.10.10.10/32 port = 67 to \
	10.10.10.128/25 port = 68
pass out quick on wi0 proto icmp from 10.10.10.10/32 to 10.10.10.128/25 \
	icmp-type 8 keep state

# ESP and IKE
pass out quick on wi0 proto esp from 10.10.10.10/32 to 10.10.10.128/25
pass in quick on wi0 proto esp from 10.10.10.128/25 to 10.10.10.10/32
pass out quick on wi0 proto udp from 10.10.10.10/32 to 10.10.10.128/25 \
	port = 500
pass in quick on wi0 proto udp from 10.10.10.128/25 to 10.10.10.10/32 \
	port = 500

# default deny 
block out log quick on wi0 all
block in log quick on wi0 all

10.10.10.128/25 is the address pool of the DHCP server (see section 3.2) and 10.10.10.10/32 is the wireless interface. If you are using HW access points, replace the interface wi0 with your ethernet interface (eth1 in the picture 2.2). The default action for pf is pass so the above example file should work out of the box. Of course, you should configure filters on all the other interfaces (ethernet(s), loopback, enc) as well.

The rules can be tightened further by using authpf(8). In that case, we allow only the ssh connection and dhcp. IPsec related rules are created dynamically if the user authentication is successful. See the chapter Improving security.

Activate the IP forwarding and start filtering


# sysctl -w net.inet.ip.forwarding=1
# pfctl -e
And remember to check the files /etc/sysctl.conf and /etc/rc.conf

4. Client configuration

The OpenBSD IPsec implementation works with just about any IPsec client software out there. In the next sections, we will configure the clients for Windows 2000 and Linux. More client configuration examples can be found at Allard Consulting OpenBSD page.

4.1. Windows 2000 Safenet Soft-PK

Windows 2000 client is implemented with Safenet's Soft-PK IPsec client. Install the software and download the client key/certificate bundle (client.p12) created in section 3.5. You will also need the CA certificate.

Start the Certificate Manager and Import your client certificate

Import the CA certificate

Next, start the Policy Editor and type in a new connection. Note that the Gateway ID Type is "Domain Name" (FQDN), this is the "My-ID" section in our example isakmpd.conf.

Configure Proposal for IKE Phase 1. Type in the Authentication Method, Algorithms and Key group (Group 5 = MODP_1536).

Configure Proposal for IKE Phase 2. Nothing exciting here.

4.2. Linux FreeS/WAN

Linux IPsec client is implemented with the excellent FreeS/WAN software with X.509 patch from StrongSec. FreeS/WAN doesn't support RSA-based authentication using X.509 certificates out of the box. Install and patch the FreeS/WAN distribution and download the client key/certificate bundle (client.p12) created in section 3.5.

Import certificates and private key


$ openssl pkcs12 -in client.p12 -out client.certs

Cut and paste the CA certificate in file client.certs as /etc/ipsec.d/cacerts/ca.crt. Cut and paste your client certificate (also in the file client.certs) as a new file. Convert this new file into binary DER format


$ openssl x509 -in newfile -outform DER -out /etc/x509cert.der

Next, strip the private key with fswcert utility


$ fswcert -k --type pkcs12 client.p12

Insert the fswcert output in the file /etc/ipsec.secrets. The key is bound to the UFQDN of the client


noone@nowhere.com : RSA {
	Modulus:
	PublicExponent:
	PrivateExponent:
	Prime1:
	Prime2:
	Exponent1:
	Exponent2:
	Coefficient:
}
(key values are not printed)

Next, edit the file /etc/ipsec.conf. Below is an example of connection section.


conn klake
        keyexchange=ike
        auth=esp
        keyingtries=5
        type=tunnel
        pfs=yes
        authby=rsasig
        ikelifetime=2.5h
        keylife=1h
        rekey=yes
        auto=start
        # gateway-side connection
        left=10.10.10.10
        leftrsasigkey=%cert
        leftid=@vpngw.klake.org
        leftnexthop=
        leftsubnet=0/0
        # client-side connection
        right=%defaultroute
        rightrsasigkey=%cert
        rightid=noone@nowhere.com
        rightnexthop=
        rightsubnet=
left is the IP address of the OpenBSD box, leftid is the FQDN (note the '@'-char!). On the client side, rightid is your UFQDN.

That should be all that is needed. Run /etc/rc.d/init.d/ipsec start.

4.3. Windows 2000 native IPsec

It is also possible to use the native IPsec implementation of Windows 2000 and XP. Please follow the instructions at this page.

Some notes

Thanks for Kevin Cheng for this information.

5. Improving security

Client security

But wait.. We got the VPN securing our traffic, isn't that enough? It might be, but there are some possible dangers in this setup: Some things to consider

Gateway security

Yes, there really is some ways to improve the security of the OpenBSD system. One would be a use of authpf(8) - the OpenBSD authenticating gateway user shell. It works by splitting the pf rules in a two separate sections: the global rules in /etc/pf.conf and dynamic rules that are appended to the running filter list if the user authenticates succesfully.

By following the example networks of this document, all the necessary WLAN rules can be shrinked down to a following rule set that allows only SSH and DHCP:


########################################################################
# WLAN rules in /etc/pf.conf
########################################################################

# SSH for user authentication
pass in quick on wi0 proto tcp from 10.10.10.128/25 to 10.10.10.10/32 \
	port = 22 keep state

# dhcp requests and responses
pass in quick on wi0 proto {tcp,udp} from any port = 68 to 10.10.10.10/32 \
	port = 67
pass out quick on wi0 proto {tcp,udp} from 10.10.10.10/32 port = 67 to \
	10.10.10.128/25 port = 68
pass out quick on wi0 proto icmp from 10.10.10.10/32 to 10.10.10.128/25 \
	icmp-type 8 keep state

# default deny 
block out log quick on wi0 all
block in log quick on wi0 all

The following rules are enough to allow VPN connections from the IP address that initiates the authentication process:


########################################################################
# /etc/authpf/authpf.rules
########################################################################

# ESP and IKE
pass out quick on wi0 proto esp from 10.10.10.10/32 to $user_ip
pass in quick on wi0 proto esp from $user_ip to 10.10.10.10/32
pass out quick on wi0 proto udp from 10.10.10.10/32 to $user_ip port = 500
pass in quick on wi0 proto udp from $user_ip to 10.10.10.10/32 port = 500

Please read carefully the manual page for authpf(8), it includes all the information that is needed to setup user accounts and authpf configuration files.

You also need to install a SSH client software in your workstation. Any SSH2 compatible package will do the trick (ssh.com, OpenSSH, PuTTY). You can also try this precompiled OpenSSH-3.5p1 if you are not willing to pay a big $$ for ssh.com or playing with cygwin. The package include some scripts that will make the setup easier. Just unzip the file to directory C:\authpf and run the shortcut "User Authentication".

6. Problems

path MTU discovery (PMTU)

The only problem I have experienced so far with this setup is the path MTU discovery (PMTU). It happens because all the traffic (including Internet traffic) is encapsulated in IPsec tunnel, thus lowering the MTU (in fact, it lowers the MSS of the TCP sessions). I also have to use NAT because of the private address space assigned to clients. Yes - some hosts block these ICMP messages anyway but my problem is that my NAT cannot handle correctly PMTU. Possible solutions include

authpf

User authentication may be complicated if the authentication gateway (usually the OpenBSD VPN gateway) is in the protected side of the network. That is clearly the case in this document because all of the traffic is secured using VPN. Here is what happens: This is a classic chicken-egg problem! Fortunately, there is some ways to go around it

Copyright and Disclaimer

This document is copyright (c) 2002 of Jarkko Turkulainen. Redistribution of the document, with or without modification, is permitted provided that the redistribution retain the above copyright notice.

THE AUTHOR IS NOT RESPONSIBLE OF ANY DAMAGES INCURRED DUE TO ACTIONS TAKEN BASED ON THE INFORMATION IN THIS DOCUMENT.

Feedback

Bug reports, discussion, etc.: Sorry, you have to write it!.



Last updated Nov 24 2002 Home