FreeBSD as a RAS for WIN2K and others IPSEC road warriors
$Id: FreeBSD-WIN2K-IPSEC-HOWTO.html,v 2.16 2002/07/22 08:27:05 aivanov Exp $
1. Introduction and Disclaimers
FreeBSD on a common desktop class machine is
sufficient as a RAS for the needs of a small enterprise.
It can support up to 256
clients, more than 4 MBit 3des and more than 10MB des-cbc, blowfish or aes throughput on a
700MHz PIII. If you need more than this you most likely will have to
go for a specialized access point from Cisco, Nortel or other vendors and/or
specialized client software that supports algorithms more efficient than 3des.
These numbers are quoted for the specific deployment scenario when FreeBSD
accepts connections from Windows2000 and XP machines that do not run any
additional software. Without additional software these OSes can do only PPTP and L2TP
VPNs. IPSEC is simply an additional protection. This results in the following
peculiarities (I will intentionally avoid classifying them as advantages or disadvantages):
- Capability to tunnel non-IP protocols. These
are all but extinct now but you may still sometimes need them.
- Capability of additional authentication that can be integrated easily into
a standard windows domain security policy.
- Simplified debugging. End-user is presented with a "proper" interface and a proper connection which
the OS can immediately identify as up or down.
- No extra client costs.
- CPU overhead from encapsulating all frames into GRE (or L2TP) prior to transmission.
Initially I have designed the setup described in this document for Windows only. It currently
supports Linux with FreeSWAN 1.96 after it has been patched with the x509 patch. It can also
be extended further to support other VPN clients that can do PPTP or L2TP and IPSEC with certificates.
I have added the clients other then windows for reasons of the "because it can be done" variety
rather then because of a specific need. Most of these can do IPSEC tunnel mode and are better
behaved in tunnel mode as well. There are not that many cases for this approach for non-windows
systems. For example:
DISCLAIMER and COPYRIGHT NOTICE(S)
- Having all clients the same to make administration easy and/or because of policy comliance.
- The need to use routing protocols between the client and network (this is one thing that
does not work over tunnel mode).
All usual disclaimers apply:
This worked for me, your mileage may vary.
My employer denies any responsibility for any damages or losses
caused by the use or misuse of this information. I deny any
reponsibility as well.
All trademarks are property of their respective owners.
This material is based on the excellent
OpenSSL cookbook, OpenSSL documentation
and various documents from Microsoft
, Verisign, the
KAME project and others. All information used in this HOWTO is either
freely available on the Internet or can be derived from elementary interoperability
I will be glad to accept any corrections and amendments to this document
and maintain it.
You are allowed to redistribute this document free of charge,
modify it as you see fit and include in other documents and products as long
as the original copyright notice is retained and/or due credit is given.
2. Certificate Authority.
If you already have one - skip to section 2.3. Otherwise you will need to
create a certificate root.
2.1. Create the necessary directory structure
Choose your own directory location. For example:
/usr/local/etc/openssl. Create the necessary subdirectories and files:
echo "01" > /usr/local/etc/openssl/serial
2.2. Prepare an openssl.conf file
The only reason for doing this is to avoid having to enter your company
name, location, etc every time you run openssl. Here is a sample config based
on the SSL Cookbook.
RANDFILE = /usr/local/etc/openssl/.rand
[ ca ]
default_ca = CA_default # The default ca section
[ CA_default ]
dir = /usr/local/etc/openssl # Where everything is kept
certs = $dir/certs # Where the issued certs are kept
crl_dir = $dir/crl # Where the issued crl are
database = $dir/index.txt # database index file.
new_certs_dir = $dir/newcerts # default place for new certs.
certificate = $dir/private/CAcert.pem # The CA certificate
serial = $dir/serial # The current serial number
crl = $dir/clr/crl.pem # The current CRL
private_key = $dir/private/CAkey.pem # The private key
RANDFILE = $dir/private/.rand # private random number
#x509_extensions = x509v3_extensions # The extentions
to add to the cert
default_days = 365 # how long to certify for
default_crl_days= 30 # how long before next CRL
default_md = md5 # which md to use.
preserve = no # keep passed DN ordering
# A few difference way of specifying how similar the request should look
# For type CA, the listed attributes must be the same, and the optional
# and supplied fields are just that :-)
policy = policy_match
# For the CA policy
[ policy_match ]
countryName = match
stateOrProvinceName = optional
localityName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ] default_bits = 1024
default_keyfile = privkey.pem
distinguished_name = req_distinguished_name
attributes = req_attributes
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = UK
countryName_min = 2
countryName_max = 2
stateOrProvinceName = State or Province Name (full name)
localityName = Locality Name (eg, city)
localityName_default = Cambridge
organizationName = Organization Name (eg, company)
organizationName_default = IP Access
organizationalUnitName = Organizational Unit Name (eg, section)
commonName = Common Name (eg, YOUR name)
commonName_default = ipaccess.com
commonName_max = 64
emailAddress = Email Address
emailAddress_max = 40
emailAddress_default = firstname.lastname@example.org
[ req_attributes ]
challengePassword = A challenge password
challengePassword_min = 4
challengePassword_max = 20
The v3 x509 extensions have been commented out. I have had some
trouble with them and they are not used by any of the parties concerned anyway.
At the moment I have yet to find out how to set up automated certificate distirbution in a manner when it will end
up in the computer account on a Win2K machine. Sending them out in email and/or supplying them through http using CGI
scripts puts them in the user account. This does not work for IPSEC. So you may consider
your administrative overhead and possibly extend the cert validity to
the highest value you think to be safe. For example: something like
2.3. Create the CA certificate and make a copy of it in PKCS#12 format
so Windows can read it.
As a result you will have two PEM format files for your Certificate Root
and a PKCS#12 file which you can import into a windows system. Keep in mind
that if you do not use the -nokeys switch, the resulting PKCS#12 file will
contain your CA private key as well. At least with OpenSSL 0.9.6c under
debian-woody (which is what I use for a cert authority)
this option does not work correctly and the keys are present
in the PKCS#12 file (according to windows).
If your private key has been kept for any reason it can be easily
stripped by exporting it under windows and reimporting it back in.
openssl req -new -x509 -keyout /var/openssl/private/CAkey.pem \
-out /var/openssl/private/CAcert.pem -config openssl.conf
openssl pkcs12 -export -in private/CAcert.pem \
-inkey private/CAkey.pem -nokeys -out CA.p12
2.4. Create a cert request for the server, sign it and make a non-encrypted
copy of it.
openssl req -new -keyout server-key-encrypted.pem \
-out server.pem -days 360 -config openssl.conf
cat server.pem server-key.pem > server-req.pem
openssl ca -policy policy_match -out server-signed.pem \
-config openssl.conf -infiles server-req.pem
openssl rsa -in server-key-encrypted.pem -out server-key.pem
- The openssl certificate request creates an encrypted private key.
It has to be decrypted in order for racoon to be able to use it. That
is the reason for the last
openssl rsa line.
2.5. Create a cert request for each windows machine, sign it and make
windows readable PKCS#12 copy of it.
Similar to the above:
openssl req -new -keyout user-key.pem -out user.pem \
-days 360 -config openssl.conf
cat user.pem user-key.pem > user-req.pem
openssl ca -policy policy_match -out user-signed.pem \
-config openssl.conf -infiles user-req.pem
openssl pkcs12 -export -in user-signed.pem -inkey user-key.pem \
-name "User Name Goes Here" -certfile private/CAcert.pem -out user.p12
- You need to repeat step 2.5 for every user and import the certificate into
the windows system as described in 4.1.
- You will also need to copy the certificates to the FreeBSD VPN system and
symlink them to their checksums (see section 3.2).
- Under normal circumstances, the
first two lines and the last line are actually the end-user's obligation.
You should not know the user RSA key. All you need to do is sign it.
- Once again Windows is supposed to be able to formulate a cert request. Unfortunately
I do not how to set it up versus openssl. If this is possible of course.
3. Setting up a FreeBSD box.
3.1. Rebuild your kernel with IPSec.
You will need to enable the following in the config file:
Also enable the firewall of your choice IPFIREWALL or IPFILTER. Keep in
mind that some options like NAT may not be compatible with using IPSEC.
options IPSEC #IP security
- Unless I am mistaken, at least IPFILTER looks at the packet twice.
Once at the encrypted (so you need to permit ESP) and once on the
decrypted (so you need to permit gre and tcp 1723).
BSD does not enforce incoming packet encryption policy
compliance (like cisco). It is the job of the IP filtering rules
to do this.
3.2. Build and install KAME racoon from the ports collection.
It is under
/usr/ports/security/racoon. In most cases a simple
make install should be enough. Best of all put the config under
its own directory like
/usr/local/etc/racoon/. The config is quite simple:
I have set it for the most elementary method of locally valid certificates
(no certificate chain). When used this way racoon searches for certificates based on their checksum.
So, all client and certification authority certificates
under the cert directory will need to be symlinked to their magic hash names. For example:
path pre_shared_key "/usr/local/etc/racoon/racoon.keys" ;
path certificate "/usr/local/etc/racoon/cert" ;
# These value can be changed per remote node.
counter 5; # maximum trying count to send.
interval 20 sec; # maximum interval to resend.
persend 1; # the number of packets per a send.
# timer for waiting to complete each phase.
phase1 30 sec;
phase2 15 sec;
# exchange_mode main, aggressive, base; uncomment this for windows only
# linux does not do aggresive mode and requires a different phase 1 proposal
exchange_mode main, base;
certificate_type x509 "server-signed.pem" "server-key.pem";
# Windows 2000, Cisco, others
authentication_method rsasig ;
dh_group 1 ;
# linux freeswan, more paranoic clients
# delete if you are dealing with windows only
# and enable aggressive mode
authentication_method rsasig ;
dh_group 2 ;
encryption_algorithm cast128, blowfish, aes, 3des, des ;
authentication_algorithm non_auth, hmac_sha1;
ln -s demon.pem `openssl x509 -noout -hash -in demon.pem`.0
I managed to make racoon to coredump. Unfortunately I have been unable to reproduce this and
I no longer run it in aggressive mode (due to linux compatibility issues).
It is filed as a kame bug fbsd4/414. It is not the bug described in
. It is something else. So having a script running behind racoon's back, saving any cores
and restarting it after it dies may be a very good idea.
- Racoon is capable of verifying certificate chains. If you put the
certificate authority PEM and symlink it as described above racoon will authenticate using
any certificate signed by it. Looking through the source it seems that the revocation should be supported
in a similar fashion, but I need to test this one futher. This is not documented in the man pages. The
only documentation I could find was in
the Kame newsletter which states the
fact that is works and little more. I could not find any
documentation on CRLs so if you intend to use racoon in this mode you will need to test their use throughly.
Alternatively you may put every cert except the CA certificate and symlink them as above. This will work
If aggressive mode is not enabled you may get some timeouts and initial access problems if a client Windows machine
on a static IP address during the first several minutes after it has been rebooted.
Tracing exactly what happens is on my TODO list (note: I think that it is related to aggressive mode, have yet to
find time to trace it).
3.3. Build and install the PoPToP PPTP server.
It is under
/usr/ports/net/poptop. FreeBSD by default builds
it with userland ppp which by default does not support RC4 encryption
(it can be rebuilt with it).
Considering that encryption is delegated to IPSec this is not a problem.
Alternatively there is another VPN daemon and kernel ppp both of which support
RC4 but I have not tested them. At least the kernel ppp with the RC4 patches
is reported to be unstable. It may also be illegal to use it in some
After building it you need to add the following section to the bsd ppp
Update the IPs in the pptpd.conf file as well. I have not had the time to
try what happens if they differ. If they are the same it works.
set timeout 0
set log phase chat connect lcp ipcp command
set device localhost:pptp
# Server (local) IP address, Range for Clients, and Netmask
set ifaddr 192.168.20.1 192.168.20.130-192.168.20.254 255.255.255.255
set server /tmp/loop "" 0177
set timeout 0
set log phase lcp ipcp command
allow mode direct
# Authenticate against /etc/passwd
# The next depends on your routing. Proxy arp is an easy way out
# enable proxy
# DNS Servers to assign client
set dns 192.168.0.1 192.168.0.2
# NetBIOS/WINS Servers to assign client
set nbns 192.168.0.15 192.168.0.16
set device !/etc/ppp/secure
BSD pppd will allocate a different IP to the same client every time. This results in keepalives on netbios
sessions being sent to addresses that are no longer in use. This imposes additional overhead on your SMB servers
which can and should be avoided. The two best way to do this is add a route with a -reject option for the entire
network range in use by the VPN clients to the loopback address. The clients themselves will be served by
more specific ppp interface routes. So this route will be used only for links that have been dropped
- The allocation of a different address every time also makes varios browsing problems more prominent. It is
better to put static IP addresses on a per-client basis in the ppp secrets file. See the Windows setup section for
3.4. Create a traffic policy
Traffic policy on the BSD side is fairly simple. All GRE packets and PPTP
control channel traffic is set to require IPSEC.
spdadd 172.28.1.2 0.0.0.0/0 gre -P out ipsec
spdadd 0.0.0.0/0 172.28.1.2 gre -P in ipsec
spdadd 172.28.1.2 0.0.0.0/0 tcp -P out ipsec
spdadd 0.0.0.0/0 172.28.1.2 tcp -P in ipsec
4. Windows 2000 Setup
You will need admin privileges
for every client. There are also some prerequisites. Windows must be patched
to SP2 and have the high encryption pack installed. The high encryption pack
is available from
- You will also need working network browsing across subnets. The easiest way to achieve
this is to enable WINS on the PDC (or its samba equivalent) and ask PPP to
supply the clients with the WINS server address. Unfortunately even one machine with
enabled NetBIOS or IPX can spoil the convergence of SMB name resolution.
So you will need to clean up your network from Netbios and IPX speakers.
WINS entries on a Windows server have several days worth of lifespan. As a result if you initiate a new connection
with a new IP address you may run into the problem of having to deal with cached information on the network. Also
both WINS servers and some WINS capable clients (Windows2000, Samba) try to supplement WINS information with
DNS lookups. If these lookups resolve to the same name as the SMB name browsing, authentication and overall cross
subnet network behaviour become much more reliable. It is especially important to have correct reverse DNS here.
Correct forward is not that critical.
As a result, it is very beneficial to put all pptp clients on static IPs assigned by the ppp daemon.
This assumes that one user always logs on from one PC and that there are no duplicate logins. This assumption is
correct for most VPN access cases. In the few where it is not, you can get around by defining different PPTP login
names for the different systems.
4.1. Certificate Setup
Note, that this is the part where it is easiest of all to make a mistake.
start menu run "mmc". From the console menu chose add-remove snap-in. Add
the certificate and the IPSEC snap-ins. When asked which certificates do
you want to manage chose local computer. Note that windows has per-user certificates
as well as per-computer ones, but the per-user ones are not useable for IPSEC.
Under the Certificates, right button click on
Trusted Root Certification
all actions choose
. Import your certificate authority PKCS#12 certificate here. Check if it
Under the Certificates, right button click on
all actions choose
import. Import the user
PKCS#12 certificate here. Check if it is correctly displayed and the root
authority is known.
Under IP Security policies choose a policy which you are not using or
create a new one. Specify it as follows:
If your personal certificate is correctly signed it will than be used for
isakmp key negotiation. If you are having trouble, run racoon in debug mode
on the BSD box. It will display the whole certificate in the debug output.
- One access list for all traffic going to the IP address of
the BSD VPN Gateway.
- All traffic requires IPSec and is authenticated using
- From the list of authorities choose yours. Disable or remove all other rules and enable the policy.
4.2. PPTP setup.
Create a new VPN connection. Make sure that under properties, in the security
require data encryption field is left blank. You
do not need it. This is the RC4 encryption for the PPTP which will be unnecessary
overhead if IPSEC is protecting the connection. It may also be a good idea
to force the connection to be a PPTP one. Windows 2000 tries L2TP first, so
leaving this setting on automatic may slow down the connection process.
5. Linux Setup
I have used debian woody and compiled freeswan-1.96 from the unstable distribution. The
reason for this choice is that the package in unstable already has x509 and several other
important patches applied. If you are on a non-debian system I would suggest to start from the
debian sources and patches in order to minimise the hassle. Otherwise the x509 patch is
available from http://www.strongsec.com.
Overall, the linux IPSEC stack still has a way to go and is not 100% integrated into
linux networking. Also, the syntax of ipsec.conf leaves more to be desired. There are
several strong sides as well, like CRL support but they do not really come into play as
5.1. FreeSWAN installation
Obtain freeswan if possible patched with the x509 patch and install it according to the
instructions supplied on freeswan's web site and the
instructions for the x509 patches.
5.2. FreeSWAN configuration
Extract the subject lines out of the certificates on the linux system and the FreeBSD
VPN access machine. In theory you should not need to specify these in ipsec.conf. In practice
I could not make it work. If you specify
for the system identity it will still
supply/ask for an IP address instead of ASN1_DN in IKE phase 1.
This results in the following config
leftid="Your FreeSWAN ASN1_DN goes here"
rightid="Your VPN Access point ASN1_DN goes here"
leftcert is completely ignored. It is taken from /etc/x509cert.der instead
left=%defaultroute is not a pleasant way to do it but there is nothing
you can do if you are dealing with a dynamically assigned addresses (dialup). It will become more
clear in the networking section.
- Overall, in terms of available parameters and syntax ipsec.conf compared to racoon + setkey leaves a lot
to be asked for.
There is a pptp client package available nowdays in almost all distributions. Once again it has
been tested on debian, so if there is no pptp package on your system I would suggest using debian
The setup from now on revolves around the problem of
well as several other problems related to the fact that IPSEC is still not properly
integrated into linux networking code
left=%defaultroute. If the IP address is dynamic, then
you need this statement to be able to chose the correct interface for IPSEC. This
choses the "external" interace or where your default route goes. This means that
you can no longer use a default route down the pptp tunnel. If you do, and the SA needs to be
renegotiated it will fail most miserably. As a result you will have to set statics (not default)
in the ppp ip-up scripts. Another way to deal with this is to set up the connections
directly in the ip-up/down or their equivalents instead of using ipsec.conf.
Overall, there is no cookbook solution here.
DEBUGGING and CAVEATS
If you run into trouble your best chance is to use racoon in non-daemon
mode with debugging enabled. In some cases having a look at the messages
left by pptpd in the syslog may be necessary as well.
I found most errors to be self-explanatory except
This happens when the certificate used for the BSD server has an encrypted
private key. You will need to run
- Racoon fails when trying to read its own private key with no additional error
openssl rsa in order to decrypt
This happens either when Windows 2000 has not been ServicePack2-ed or has
remnants of some 3rd party tunnel mode software. Some of this software disables
the Windows IKE infrastructure and uses its own DIY keying instead.
You will need to reenable the service.
- It just does not work with no meaningfull explanations in the log.
There are two possible reasons for this. One is IKE not negotiating after a failure
in modes different from aggressive. I have not debugged this one fully yet. In some cases
only a reboot on the Windows machine may help. Move to aggressive mode if possible (see notes).
- Windows fails to connect after a link failure.
Sequencing problems with the GRE packets. Windows VPN stops working if the packets are
reordered along the way. Same goes for the pptpd implementation.
This is a known problem and there is nothing you can do about it besides
fixing the network or changing the provider. If the reordering occurs in
your network look for any of the following:
This problem will also occur if the windows network interface drops and comes back with the
same IP address. Most common reason for this is network filters or IPSEC policy that prohibit
DHCP on the Windows machine. These are visible in the windows log. Check and fix the policy
accordingly. Note: If you wait for the normal redial interval the link will come back OK.
Problem occurs only if you press the redial button too fast.
- Cisco's "load sharing per packet". You need to share per flow. Standard load
sharing done by fast switching or CEF will do nicely.
- Linux with multipath routing and no load sharing routing disciplines. Have
a look at the advanced routing howtos on chosing a proper load sharing discipline.
- Early juniper routers with load sharing across several links. In this case you
have no other choice but to upgrade the hardware.
- Other load balancing cases: check with the vendor literature on how to fix it.
These condition can be easily
discovered on the pptpd side (large and small jumps in GRE sequence numbers) and I will hopefully
fix them once I have some time to get to it. Watch this place ;-) This of course lives the windows side but not like there is anything I can do there.