In this post we configure Openswan and Windows 7 (or Vista) to bring up an IPsec + L2TP tunnel. One point of difference is that we focus on using certificates to facilitate secure IPsec connectivity. Put another way, we use RSA certs on phase1, rather than a pre-shared key. Configuring and maintaining this properly is not easy.
We will also look at how the Windows Vista and Windows 7
clients are configured with certificates (spoiler: it's the same way for both clients).
I'm a bit of an
Openswan fan. I don't exactly know why, since
strongSwan seems to be more feature rich. Maybe I defer to Openswan because it's easily installed through any Linux distro's package manager. Or perhaps because I started muddling around with it back in 2005. Anyway, a lot of what is written here will carry over to strongSwan.
Openswan seems to lack features that strongSwan offers; the ability to configure lifetime bytes (lifebytes) was one Openswan limitation I most recently bumped up against.
If there's anything in all this that isn't clear, then I'm happy to field comments or questions.
If you're wondering about the Oklahoma references later, it's because yesterday I watched the 1940 adaptation of The Grapes of Wrath.
Server Version
# cat /etc/debian_version
7.11
Files
/etc/ipsec.conf
/etc/ssl/openssl.cnf
/etc/xl2tpd/xl2tpd.conf
/etc/ppp/options.l2tpd.lns
/etc/ppp/chap-secrets
Openswan
Simply take the example configuration and make amendments in
a few places. Insert the contents of this file into the
/etc/ipsec.config file. You can just cat the file appending it to
ipsec.conf. For example:
cat l2tp-cert.conf >> /etc/ipsec.conf
The examples directory contains lots of handy files:
# ls -la /etc/ipsec.d/examples/
total 44
drwxr-xr-x 2 root root 4096 Mar 9 20:12 .
drwxr-xr-x 10 root root 4096 Mar 9 20:12 ..
-rw-r--r-- 1 root root 1659 May 27 2012 hub-spoke.conf
-rw-r--r-- 1 root root 1017 May 27 2012 ipv6.conf
-rw-r--r-- 1 root root 1736 May 27 2012 l2tp-cert.conf
-rw-r--r-- 1 root root 1825 May 27 2012 l2tp-psk.conf
-rw-r--r-- 1 root root 1156 May 27 2012 linux-linux.conf
-rw-r--r-- 1 root root 1580 May 27 2012 mast-l2tp-psk.conf
-rw-r--r-- 1 root root 235 May 27 2012 oe-exclude-dns.conf
-rw-r--r-- 1 root root 1694 May 27 2012 sysctl.conf
-rw-r--r-- 1 root root 664 May 27 2012 xauth.conf
The following example config has all the helpful comments snipped out for brevity:
# cat /etc/ipsec.conf
version 2.0 # conforms to second version of ipsec.conf specification
# basic configuration
config setup
#plutodebug="control parsing"
#plutodebug="all"
dumpdir=/var/run/pluto/
nat_traversal=yes
virtual_private=%v4:10.0.0.0/8,%v4:192.168.0.0/16,%v4:172.16.0.0/12,%v4:25.0.0.0/8,%v6:fd00::/8,%v6:fe80::/10
oe=off
protostack=auto
conn l2tp-X.509
authby=rsasig
pfs=no
auto=add
rekey=no
dpddelay=10
dpdtimeout=90
dpdaction=clear
ikelifetime=8h
keylife=1h
type=transport
# This is your server's IP:
left=192.168.168.24
leftid=%fromcert
leftrsasigkey=%cert
# You will create this certificate:
leftcert=/etc/ipsec.d/certs/ipsec-serverCert.pem
leftprotoport=17/1701
right=%any
rightca=%same
rightrsasigkey=%cert
rightprotoport=17/%any
rightsubnet=vhost:%priv,%no
conn passthrough-for-non-l2tp
type=passthrough
# This is your server's IP:
left=192.168.168.24
This is your server's gateway:
leftnexthop=192.168.168.1
right=0.0.0.0
rightsubnet=0.0.0.0/0
auto=route
Make sure that nat_traversal is on.
You
need to provide the IP address of the interface that the IPsec
connections will arrive on. If your IPsec server is behind a NAT (as in the diagram and example config), then
this will be your private network IP and
not the public IP.
The leftnexthop is the nexthop address for your openswan server. Typically you can determine that as such:
# route -n
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.168.1 0.0.0.0 UG 0 0 0 eth0
192.168.168.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
In the above example, the gateway for the default network 0.0.0.0 is 192.168.168.1, which is the nexthop IP we are after.
If
you put your server behind a NAT then you need to open UDP ports 500
and 4500 on your modem and pinhole
those ports directly to the internal Openswan server IP (that you specified as "left").
This is a function frequently supported on even the most basic home
routers.
Openswan - Special Notes
type=transport
In
IPsec configurations, normally you want "tunnel" over transport, but
this is one of the rare times that "transport" is necessary.
rightca=%same
That's
the same CA as the left (server) side. You specify this to indicate
that only certificates signed by your IPsec CA are valid. You don't want
anyone with a signed certificate from anywhere to get access!
L2TP / PPP
HowTo documents often recommend setting up /etc/xl2tpd/l2tp-secrets but this did not
seem to work for me. In the end I needed to configure the
/etc/ppp/chap-secrets file.
# cat /etc/ppp/chap-secrets
# Secrets for authentication using CHAP
# client server secret IP addresses
# * * password 192.168.168.30
ipsec-user ipsec-server.example.com password 192.168.168.0/24
The
beauty of this is that all four settings are needed, nothing is wide
open. The username "ipsec-user" and the password "password" are filled
in on the Windows client in the initial connection dialogue box. The "IP
addresses" is the server local range.
# cat /etc/xl2tpd/xl2tpd.conf
; Output trimmed, generally
[global] ; Global parameters:
port = 1701 ; * Bind to port 1701
access control = no ; * Refuse conn without IP match
[lns default] ; Our fallthrough LNS definition
exclusive = yes ; * Permit one tunnel per host
ip range = 192.168.168.100-192.168.168.105 ; Allocate
hidden bit = no ; * Use hidden AVP's?
local ip = 192.168.168.24 ; * Our local IP to use
length bit = yes ; * Use length bit in payload?
require chap = yes ; * Require CHAP auth. by peer
refuse pap = yes ; * Refuse PAP authentication
name = ipsec-server.example.com ; * Use as hostname
ppp debug = no ; * Turn on PPP debugging
pppoptfile = /etc/ppp/options.l2tpd.lns ; * ppp options
You
need to take note of the "ip range", "local ip" and "name". In this example, the "ip range" comes from the same local IP network as the IPsec
listening interface is on. This was selected as a matter of routing
convenience.
# cat /etc/ppp/options.l2tpd.lns
lock
noauth
#debug
dump
logfd 2
logfile /var/log/xl2tpd.log
mtu 1400
mru 1400
ms-dns 192.168.168.1
lcp-echo-failure 12
lcp-echo-interval 5
require-mschap-v2
nomppe
If
you have a local router then ms-dns is going to your local router if
not then try whatever DNS address you normally use in your network.
Openssl - Config
# ls -la /usr/lib/ssl/
lrwxrwxrwx 1 root root 20 Feb 1 23:16 openssl.cnf -> /etc/ssl/openssl.cnf
countryName_default = US
stateOrProvinceName_default = Oklahoma
0.organizationName_default = My Industries
Openssl - Server CA
Create a 10 year certificate authority (CA) specifically for IPsec.
# cd /etc/ipsec.d
# openssl req -x509 -newkey rsa:2048 -keyout private/caKey-ipsec-server.pem -out cacerts/caCert-ipsec-server.pem -days 3650
Openssl - Server Certificate
Now that we have a CA, we need to
generate server certificates and have them signed by that CA. This
sounds like two steps when one would do, but you may need to revoke your
server certificate one day.
# openssl ca -in /etc/ipsec.d/private/ipsec-serverReq.pem -days 3650 -out /etc/ipsec.d/private/ipsec-serverCert.pem -notext -cert /etc/ipsec.d/cacerts/caCert-ipsec-server.pem -keyfile /etc/ipsec.d/private/caKey-ipsec-server.pem
# openssl rsa -in /etc/ipsec.d/private/ipsec-serverKey.pem -out ipsec-serverKey-rsa.pem
Openssl - Server CRL
Generate a Certificate Revocation List (CRL),
which at this stage will have no revoked certificates. Later on, you
will see how to easily revoke a signed certificate and add that
certificate to this CRL.
# openssl ca -gencrl -keyfile /etc/ipsec.d/private/caKey-ipsec-server.pem -cert /etc/ipsec.d/cacerts/caCert-ipsec-server.pem -out /etc/ipsec.d/crls/ipsec-server.crl
Openssl - SSL Client Certificates
The easiest method (in my opinion) is
to issue all certificates from the Openswan server itself. I created a
script (
ipsec-cert-management.sh) to step through the certificate generation
steps because it is unnecessarily painful.
When you run
this script (
ipsec-cert-management.sh), you'll be prompted for a series of
passwords. One password will be for the CA's private key password, the
other will be for the new private client key you are creating.
You should create a password for your client key. When you import
the key into your Windows OS, you have to enter the password once, but
other people will not be able to export and use the key elsewhere unless
they know the password. In other words, there is little overhead in
using a passworded key, but putting a password on the key adds an extra
layer of difficulty for anyone trying to steal your private key from the
local system.
Below, watch for my comments:
# New PK password
# CA password
# Enter
- Where "New PK password" is for the new client key that you are generating.
- Where "CA password" is the password for the CA private key"
- Where "Enter" means do nothing, just hit the enter key.
Here we go:
# ./ipsec-cert-management.sh testguy
Generating a 2048 bit RSA private key
..................................+++
............................+++
writing new private key to '/etc/ipsec.d/clientcerts/testguy/testguyKey.pem'
Enter PEM pass phrase: # New PK password
Verifying - Enter PEM pass phrase: # New PK password
-----
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) [US]:
State or Province Name (full name) [Oklahoma]:
Locality Name (eg, city) []:
Organization Name (eg, company) [My Industries]:
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:testguy # Recommend using the client hostname
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []: # Enter
An optional company name []: # Enter
Using configuration from /usr/lib/ssl/openssl.cnf
Enter pass phrase for /etc/ipsec.d/private/caKey-ipsec-server.pem: # CA password
Check that the request matches the signature
Signature ok
Certificate Details:
Serial Number: 13 (0xd)
Validity
Not Before: Mar 23 20:43:19 2014 GMT
Not After : Mar 20 20:43:19 2024 GMT
Subject:
countryName = US
stateOrProvinceName = Oklahoma
organizationName = My Industries
commonName= testguy
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Netscape Comment:
OpenSSL Generated Certificate
X509v3 Subject Key Identifier:
X509v3 Authority Key Identifier:
keyid:
Certificate is to be certified until Mar 20 20:43:19 2024 GMT (3650 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
Data Base Updated
Enter pass phrase for /etc/ipsec.d/clientcerts/testguy/testguyKey.pem:# New PK password
Enter Export Password: # New PK password
Verifying - Enter Export Password: # New PK password
Import /etc/ipsec.d/clientcerts/testguy/testguyKey.p12 to your Windows client.
total 24
drwxr-xr-x 2 root root 4096 Mar 23 21:42 .
drwxr-xr-x 3 root root 4096 Mar 23 21:42 ..
-rw-r--r-- 1 root root 1322 Mar 23 21:43 testguyCert.pem
-rw-r--r-- 1 root root 3526 Mar 23 21:43 testguyKey.p12
-rw-r--r-- 1 root root 1834 Mar 23 21:43 testguyKey.pem
-rw-r--r-- 1 root root 968 Mar 23 21:43 testguyReq.pem
I had written most of the content in the post before
Heartbleed broke
in April 2014. Until that point, I hadn't worried about digging into
certificate revocation. In all reality, as a home user with an IPsec
server running intermittently, I could count myself as particularly
unlucky if someone had not only targeted my server for a
Heartbleed attack
but also managed to extract private keys or passwords; Noting also that
my machine was patched within 24 hours of the announcement of
Heartbleed.
Still, there will always be a need to be able to quickly revoke a
certificate, for example if I thought that my windows machine had been
compromised.
In that context, the script (see end of
post) needed to be enhanced to automate the revocation of any
certificate signed by the IPsec CA. Note that the script cannot revoke a
certificate signed by an external CA. In other words, if you generated a
signed cert with this script then you can revoke the cert with this
script.
Also note that if you sign a client certificate and
subsequently generate a new CA certificate, you can still revoke the
previously signed client certificate using the new CA certificate.
After
revoking the client certificate and restarting IPsec, new connection
attempts with the revoked cert will have this signature in the "ipsec
barf" logs:
May 3 21:43:43 ipsec-server pluto[6922]: "l2tp-X.509"[1] 93.104.122.73 #1: Main mode peer ID is ID_USR_ASN1_DN: 'C=US, ST=Oklahoma, O=My Industries, CN=roadwarrior'
May 3 21:43:43 ipsec-server pluto[6922]: "l2tp-X.509"[1] 93.104.122.73 #1: certificate was revoked on May 03 19:42:27 UTC 2014
May 3 21:43:43 ipsec-server pluto[6922]: "l2tp-X.509"[1] 93.104.122.73 #1: X.509 certificate rejected
May 3 21:43:43 ipsec-server pluto[6922]: "l2tp-X.509"[1] 93.104.122.73 #1: no suitable connection for peer 'C=US, ST=Oklahoma, O=My Industries, CN=roadwarrior'
May 3 21:43:43 ipsec-server pluto[6922]: "l2tp-X.509"[1] 93.104.122.73 #1: sending encrypted notification INVALID_ID_INFORMATION to 93.x.x.x:61421
May 3 21:43:48 ipsec-server pluto[6922]: "l2tp-X.509"[1] 93.104.122.73 #1: Main mode peer ID is ID_USR_ASN1_DN: 'C=US, ST=Oklahoma, O=My Industries, CN=roadwarrior'
You
can't revoke a certificate unless you have it to hand. I'd deleted a
lot of certs during my testing and discovered that the index or
"database" of issued certificates in /etc/ssl/demoCA/index.txt was
populated with many certs that I no longer had. There appears to be no
way to revoke a signed certificate by the serial number alone.
However, as we use the default openssl settings in the script (see end
of post) much of the time, the signed certificates are copied into
/etc/ssl/demoCA/newcerts/ and named by serial number. As a result, we
can revoke the serial number by finding the cert in that directory.
# ls -la /etc/ssl/demoCA/newcerts/
total 64
drwxr-xr-x 2 root root 4096 May 3 22:27 .
drwxr-xr-x 4 root root 4096 May 3 22:27 ..
-rw-r--r-- 1 root root 1744 Mar 17 20:32 01.pem
-rw-r--r-- 1 root root 1724 Mar 17 20:38 02.pem
-rw-r--r-- 1 root root 1724 Mar 17 20:49 03.pem
-rw-r--r-- 1 root root 1342 Mar 17 22:28 04.pem
-rw-r--r-- 1 root root 1342 Mar 17 22:29 05.pem
-rw-r--r-- 1 root root 1322 Mar 17 22:39 06.pem
-rw-r--r-- 1 root root 1342 Mar 17 23:38 07.pem
-rw-r--r-- 1 root root 1322 Mar 18 21:06 08.pem
-rw-r--r-- 1 root root 1367 Mar 18 23:09 09.pem
-rw-r--r-- 1 root root 1330 Mar 23 14:21 0A.pem
-rw-r--r-- 1 root root 1322 Mar 23 21:40 0B.pem
-rw-r--r-- 1 root root 1322 Mar 23 21:42 0C.pem-revoked
-rw-r--r-- 1 root root 1322 Mar 23 21:43 0D.pem
-rw-r--r-- 1 root root 1330 May 3 22:27 0E.pem
# cat /etc/ssl/demoCA/index.txt
V 240314193233Z 01 unknown /C=US/ST=Oklahoma/O=My Industries/CN=ipsec-server.example.com
V 240314193805Z 02 unknown /C=US/ST=Oklahoma/O=My Industries/CN=toshiba
V 240314194925Z 03 unknown /C=US/ST=Oklahoma/O=My Industries/CN=toshiba
V 240314212827Z 04 unknown /C=US/ST=Oklahoma/O=My Industries/CN=ipsec-server.example.com
V 240314212952Z 05 unknown /C=US/ST=Oklahoma/O=My Industries/CN=ipsec-server.example.com
R 240314213921Z 140503193859Z 06 unknown /C=US/ST=Oklahoma/O=My Industries/CN=toshiba
R 240314223758Z 140503194035Z 07 unknown /C=US/ST=Oklahoma/O=My Industries/CN=ipsec-server.example.com
V 240315200605Z 08 unknown /C=US/ST=Oklahoma/O=My Industries/CN=hnzlwin7
R 240320132104Z 140503194227Z 0A unknown /C=US/ST=Oklahoma/O=My Industries/CN=roadwarrior
V 240320204055Z 0B unknown /C=US/ST=Oklahoma/O=My Industries/CN=testguy
R 240320204223Z 140503200045Z 0C unknown /C=US/ST=Oklahoma/O=My Industries/CN=testguy
R 240320204319Z 140503152636Z 0D unknown /C=US/ST=Oklahoma/O=My Industries/CN=testguy
V 240430202749Z 0E unknown /C=US/ST=Oklahoma/O=My Industries/CN=roadwarrior
To verify the loading of the CRL, "ipsec barf" will give you something like this:
000 May 03 21:43:35 2014, revoked certs: 4
000issuer: 'C=US, ST=Oklahoma, O=My Industries, CN=ipsec-server.example.com'
000distPts: 'file:///etc/ipsec.d/crls/ipsec-server.crl'
000updates: this May 03 21:42:30 2014
000 next Jun 02 21:42:30 2014 ok
and this...
May 3 21:43:35 ipsec-server pluto[6922]: Changing to directory '/etc/ipsec.d/crls'
May 3 21:43:35 ipsec-server pluto[6922]: loaded crl file 'ipsec-server.crl' (759 bytes)
May 3 21:43:35 ipsec-server pluto[6922]: loading certificate from /etc/ipsec.d/certs/ipsec-serverCert.pem
May 3 21:43:35 ipsec-server pluto[6922]: loaded host cert file '/etc/ipsec.d/certs/ipsec-serverCert.pem' (1342 bytes)
The output of the
ipsec-cert-management.sh script (when revoking) will look something like this:
# ./ipsec-cert-management.sh /etc/ssl/demoCA/newcerts/02.pem
/etc/ssl/demoCA/newcerts/02.pem exists. Do you want to revoke this Certificate? [y/N]: y
Using configuration from /usr/lib/ssl/openssl.cnf
Enter pass phrase for /etc/ipsec.d/private/caKey-ipsec-server.pem:
Revoking Certificate 02.
Data Base Updated
Using configuration from /usr/lib/ssl/openssl.cnf
Enter pass phrase for /etc/ipsec.d/private/caKey-ipsec-server.pem:
Certificate Revocation List (CRL):
Version 2 (0x1)
Signature Algorithm: sha1WithRSAEncryption
Issuer: /C=US/ST=Oklahoma/O=My Industries/CN=ipsec-server.example.com
Last Update: May 3 22:21:19 2014 GMT
Next Update: Jun 2 22:21:19 2014 GMT
CRL extensions:
X509v3 CRL Number:
13
Revoked Certificates:
Serial Number: 02
Revocation Date: May 3 22:21:15 2014 GMT
Serial Number: 06
Revocation Date: May 3 19:38:59 2014 GMT
Serial Number: 07
Revocation Date: May 3 19:40:35 2014 GMT
Serial Number: 09
Revocation Date: May 3 19:46:03 2014 GMT
Serial Number: 0A
Revocation Date: May 3 19:42:27 2014 GMT
Serial Number: 0C
Revocation Date: May 3 20:00:45 2014 GMT
Serial Number: 0D
Revocation Date: May 3 15:26:36 2014 GMT
Serial Number: 0F
Revocation Date: May 3 22:00:11 2014 GMT
Serial Number: 10
Revocation Date: May 3 22:02:53 2014 GMT
Signature Algorithm: sha1WithRSAEncryption
Done, check for errors above. YOU MUST RESTART IPSEC!
-rw-r--r-- 1 root root 1724 Mar 17 20:38 /etc/ssl/demoCA/newcerts/02.pem-revoked
My advice is to make sure you have (R)evoked anything you aren't sure about. At the bare minumum you will have one (V)alid certificate for your server and one (V)alid certificate for an IPsec client.
# cat /etc/ssl/demoCA/index.txt
R 240314193233Z 140503223446Z 01 unknown /C=US/ST=Oklahoma/O=My Industries/CN=ipsec-server.example.com
R 240314193805Z 140503222115Z 02 unknown /C=US/ST=Oklahoma/O=My Industries/CN=toshiba
R 240314194925Z 140503223056Z 03 unknown /C=US/ST=Oklahoma/O=My Industries/CN=toshiba
R 240314212827Z 140503223459Z 04 unknown /C=US/ST=Oklahoma/O=My Industries/CN=ipsec-server.example.com
V 240314212952Z 05 unknown /C=US/ST=Oklahoma/O=My Industries/CN=ipsec-server.example.com
R 240314213921Z 140503193859Z 06 unknown /C=US/ST=Oklahoma/O=My Industries/CN=toshiba
R 240314223758Z 140503194035Z 07 unknown /C=US/ST=Oklahoma/O=My Industries/CN=ipsec-server.example.com
R 240315200605Z 140503223122Z 08 unknown /C=US/ST=Oklahoma/O=My Industries/CN=hnzlwin7
R 240315220911Z 140503194603Z 09 unknown /C=US/ST=Oklahoma/O=My Industries/CN=hnzlwin7/emailAddress=hnzlwin7@hnzl.de
R 240320132104Z 140503194227Z 0A unknown /C=US/ST=Oklahoma/O=My Industries/CN=roadwarrior
R 240320204055Z 140503223138Z 0B unknown /C=US/ST=Oklahoma/O=My Industries/CN=testguy
R 240320204223Z 140503200045Z 0C unknown /C=US/ST=Oklahoma/O=My Industries/CN=testguy
R 240320204319Z 140503152636Z 0D unknown /C=US/ST=Oklahoma/O=My Industries/CN=testguy
V 240430202749Z 0E unknown /C=US/ST=Oklahoma/O=My Industries/CN=roadwarrior
R 240430215836Z 140503220011Z 0F unknown /C=US/ST=Oklahoma/O=My Industries/CN=nogood
R 240430220142Z 140503220253Z 10 unknown /C=US/ST=Oklahoma/O=My Industries/CN=nogoodagain
With this
ipsec-cert-management.sh script, it's easy to add and revoke a certificate, so there's no excuse to compromise security on the grounds of complexity.
References
- Using a Linux L2TP/IPsec VPN server with Windows Vista
- Github: https://github.com/mofftech/Server-Automation/