TCP/IP
and Security
Arnaud Aubert
The worldwide success of the Internet rapidly made TCP/IP the
most used network protocol. Despite its popularity, it lacks some
important features especially regarding security. In fact, TCP/IP
can neither ensure the hosts you're communicating with are the ones
you think nor prevent the data from being captured. For example,
passwords used in protocols like HTTP, POP3, or telnet are not usually
encrypted.
The IPsec framework, ratified by the Internet Engineering Steering
Group (IESG), allows defining a policy that specifies which packets
you want to secure. Those treated packets are simply encapsulated
in IP datagrams by applying two kinds of layers:
- Authentication headers (AH) -- Based on integrity checksum
computed using data and a private key, it ensures the host you're
communicating with is the one you suppose it to be. Data integrity
is fully assured, but this method cannot prevent network listeners
from getting sensitive information from your authenticated traffic.
- Encapsulating Security Payload (ESP) -- Based on encryption
algorithms, this method prevents other hosts from retrieving confidential
information from your network. The ESP layer can provide the same
features as AH. You should therefore use ESP both for authentication
and encryption to fully secure your network.
This technology is absolutely independent of the protocols used
behind it to implement AH and ESP entities. Specifications exist
for common algorithms such as MD5 or SHA1 for authentication and
DES, 3DES, or Blowfish for encryption.
The IPsec policy defines which packets are secured. It comprises
a set of rules dependent on each implementation and generally based
on criteria such as IP address, port, direction, or protocol. The
rule can ask for communications to be secured or not in one or both
directions.
The keys used by security algorithms must be defined in a separate
place called the Security Association Database (SADB). It comprises
a set of security associations, which includes definitions for:
- The type of security association (which can be either ESP or
simply AH).
- A unique 8-byte identifier called the Security Parameter Index
(SPI) of the security association within the SADB. This identifier
should be the same on both sides of the communication.
- The authentication algorithm used (for AH and authenticated
ESP).
- The encryption algorithm used (only for ESP security associations).
- Source and destination addresses concerned by this association.
Note that a security association is direction dependent; thus,
you need two security associations to protect communication between
two hosts in both directions.
Also, the security association should include any key needed by
the security algorithms. Key lengths are dependent on the algorithm
and should be equal to that used at the remote side of the security
association.
Applying IPsec to a Solaris/Linux Communication
Linux uses two main open source projects to implement IPsec:
- FreeSWAN -- One of the first real complete implementations
of IPsec. It is quite stable but the project recently stopped.
Two other projects are continuing its development: openSWAN and
strongSWAN.
- KAME -- A joint effort of Japanese companies to provide an
IPsec implementation to BSD platforms. The project has been ported
to Linux since kernel 2.5.47 and back-ported to older kernels
in some distributions like Red Hat Enterprise Linux. This software
is used in this article for the Linux side.
In the example, I will specify an IPsec policy to secure traffic
between a Solaris 9 host 192.168.1.201 and a Red Hat Enterprise
Linux 3 ES host 192.168.1.203 (see Figure 1). Traffic will be secured
by ESP using DES for encryption and MD5 for authentication.
Setting Up the Policy Database
The Solaris policy database is managed by the /usr/sbin/ipsecconf
command. The entries are read at boot time from the configuration
file /etc/inet/ipsecinit.conf. Updates to the policy can be made
at runtime by parsing configuration files using the -a policyfile
argument, but they won't be preserved across reboots. To secure
traffic between the Solaris host and 192.168.1.203, we will ask
to use ESP with any encryption or authentication algorithm to and
from this Linux address. Run the following script on the Solaris
host to force the use of IPsec when communicating with 192.168.1.203:
#!/usr/sbin/ipsecconf -a
{ raddr 192.168.1.203 } ipsec { encr_algs any encr_auth_algs any }
On Solaris, IPsec configuration is handled by ipsecconf. The main
arguments are:
-a -- Load an IPsec configuration file.
-f -- Flush the current IPsec policies.
-l -- Display the rules currently applied by the policy.
The configuration file is a set of rules specifying which hosts
should be secured with IPsec and which algorithms should be used.
The KAME implementation is managed by the setkey command.
It receives instructions from either stdin using the -c argument
or from a file with the -f argument. As in Solaris, updates
to the policy are not preserved across reboots.
The following script will define the same policy on the Solaris
endpoint:
#!/sbin/setkey -f
# Secure outgoind communications
spdadd 192.168.1.203 192.168.1.201 any -P out ipsec esp/transport//require;
# Secure ingoing communications
spdadd 192.168.1.201 192.168.1.203 any -P in ipsec esp/transport//require;
The setkey command is responsible for KAME policy and keys
management. It takes these most useful arguments:
-f filename -- Load a KAME configuration file.
-DP and -FP -- Display and flush the rules currently
applied.
-D and -F -- Display and flush the keys currently
defined.
Spdadd instruction syntax is: spdadd src_range dst_range proto_to_secure
-P in|out policy.
Using KAME, we need to add two explicit rules for both transport
directions (identified by the -P in|out). In Solaris syntax,
the raddr instruction implicitly activates a bi-directional
security.
Setting Up the Security Association Database
Traffic should now be impossible between the two hosts, because
the policy enforces security but the keys have not been defined
yet. The security associations are responsible for this and are
located in /etc/inet/secret/ipseckeys for Solaris. They are loaded
by the ipseckey -f filename command. For readability purposes,
short key length algorithms have been chosen.
Run the following script on Solaris to set up the security associations
related to the previous policies:
#!/usr/sbin/ipseckey -f
add esp spi 0x10001 src 192.168.1.201 dst 192.168.1.203 \
encralg DES encrkey 0123456789abcdef authalg MD5 authkey \
0123456789abcdef0123456789abcdef
add esp spi 0x10002 src 192.168.1.203 dst 192.168.1.201 \
encralg DES encrkey fedcba9876543210
authalg MD5 authkey fedcba9876543210fedcba9876543210
On the KAME side, the setkey command manages the security association
in addition to the Security Policy database (SPD). The following script
will apply the keys to the already defined policy:
#!/sbin/setkey -f
add 192.168.1.2O1 192.168.1.203 esp 0x10001 -E \
des-cbc 0x0123456789abcdef -A hmac-md5 0x \
0123456789abcdef0123456789abcdef;
add 192.168.1.2O3á192.168.1.201 esp 0x10002 -E des-cbc \
0xfedcba9876543210 -A hmac-md5 0x fedcba9876543210fedcba9876543210;
Notice that the 0x10001 and 0x10002 numbers are Security Parameter
Indexes (SPI). They are used to identify the security association
in the SADB and need to be the same on both sides of the connection.
Once the keys and the policy have been configured properly, traffic
is secured and the same telnet session would result in a dump like:
# tcpdump host 192.168.1.101
18:07:51.910553 test1 > test3: ESP(spi=0x00010002,seq=0x1e2) (DF)
18:07:51.910754 test3 > test1: ESP(spi=0x00010001,seq=0x191) (DF) [tos 0x10]
18:07:51.912927 test3 > test1: ESP(spi=0x00010001,seq=0x192) (DF) [tos 0x10]
18:07:51.953335 test1 > test3: ESP(spi=0x00010002,seq=0x1e3) (DF)
18:07:51.953436 test3 > test1: ESP(spi=0x00010001,seq=0x193) (DF) [tos 0x10]
18:07:52.003291 test1 > test3: ESP(spi=0x00010002,seq=0x1e4) (DF)
The IPsec framework matches the policy with security associations;
the packets' data is no longer clearly visible and is fully authenticated.
The sniffer shows SPIs that have been used to generate the IPsec packet.
You may specify to tcpdump the keys used by the security association
to view deciphered packets.
Tunneling with IPsec
IPsec can go beyond securing packets using the tunneling mode
so that entire packets are encapsulated. If the entire IP datagram
is encapsulated, two intranets may be securely connected through
the Internet. The intranet addresses are then included in the tunneled
packets so they are re-routed correctly at the end of the tunnel.
For this example, let's say that Linux is connected through the
eth1 interface to the private network 172.17.0.0/16 as 172.17.0.1;
whereas Solaris is connected as 172.16.0.1 to 172.16.0.0/16 through
the sfe1 interface.
On Solaris, we will flush the old policy using ipsecconf -f
and create a classic IP-IP tunnel. Don't forget to enable forwarding
on the required network interfaces. The use of ESP with DES and
MD5 for the tunnel will be specified using the encr_algs
and encr_auth_algs arguments with the ifconfig command:
#!/bin/sh
ipsecconf -f
ndd -set /dev/ip ip_forwarding 0
ndd -set /dev/ip ip_strict_dst_multihoming 1
ifconfig ip.tun0 plumb
ifconfig ip.tun0 172.16.0.1 172.17.0.1 tsrc 192.168.1.201 tdst 192.168.1.203
ifconfig ip.tun0 encr_algs DES encr_auth_algs MD5
ifconfig ip.tun0 up
ndd -set /dev/ip sfe1:ip_forwarding 1
ndd -set /dev/ip ip.tun0:ip_forwarding 1
The same operations on Linux/KAME will be done using the following
script:
#!/bin/sh
echo 1 > /proc/sys/net/ipv4/ip_forward
ip tunnel add mytun mode ipip remote 192.168.1.201 local 192.168.1.203
ifconfig mytun 172.17.0.1
route add -net 172.16.0.0/16 dev mytun
setkey -c << EOF
spdflush;
flush;
add 192.168.1.201 192.168.1.203 esp 0x10001 -m tunnel -E des-cbc \
0x0123456789abcdef -A hmac-md5 0x0123456789abcdef0123456789abcdef;
add 192.168.1.203 192.168.1.201 esp 0x10002 -m tunnel -E des-cbc \
0xfedcba9876543210 -A hmac-md5 0xfedcba9876543210fedcba9876543210;
spdadd 172.16.0.0/16 172.17.0.0/16 any -P in ipsec \
esp/tunnel/192.168.1.201-192.168.1.203/require;
spdadd 172.17.0.0/16 172.16.0.0/16 any -P out ipsec \
esp/tunnel/192.168.1.203-192.168.1.201/require;
EOF
In this example, the spdflush and flush instructions,
respectively, flush policy and security associations directly from
within the configuration file.
Note that under Linux, the security association definitions must
now include the -m tunnel argument. Network 172.16.0.0/16
can now talk to 172.17.0.0/16 through the 192.168.1.0/24 network
securely because all data being tunneled to and from 192.168.1.203
and 192.168.1.201 is now IPsec'd.
Automating Key Management
Another IPsec mechanism is called Internet Key Exchange (IKE).
It allows automated negotiation of the way data should be encrypted
between hosts. This automation includes aspects like the protocols
and keys to be used, the lifetime of these keys or the way IKE should
trust another host before negotiating. The IKE protocol is divided
into two phases:
- Phase 1 (a.k.a. Main Mode) -- Use public key encryption methods
to create a bi-directional ISAKMP (Internet Security Association
and Key Management Protocol) security association. This secured
channel is later used to negotiate new keys. Multiple authentication
methods can be used but we'll concentrate on using basic pre-shared
keys. Notice, however, that you may also use X.509 certificates.
- Phase 2 (a.k.a. Quick Mode) -- Use the first phase's ISAKMP
to regularly change security keys by updating the SADB. Negotiated
keys can be asked by dumping the SADB with setkey -D on
Linux or ipseckey dump on Solaris.
We will now use a pre-shared key to re-establish the transport
security system previously used. The secured connection will be
the same, except we will now use triple DES and let the operating
system take care of the choice and change of the security keys.
These keys in fact will be randomized. We should first flush the
previous policy using ipsecconf -f and SADB using ipseckey
flush and ask for 3DES encryption to Solaris:
#!/usr/sbin/ipsecconf -a
{ raddr 192.168.1.203 } ipsec { encr_algs 3des encr_auth_algs md5 }
The same would be done on Linux/KAME using:
#!/sbin/setkey -f
spdflush;
spdadd 192.168.1.203 192.168.1.201 any -P out ipsec esp/transport//require;
spdadd 192.168.1.201 192.168.1.203 any -P in ipsec esp/transport//require;
Once the SPD entries have been set up again, we will ask IKE to take
care of the key assignment automatically.
Configuring IKE with Solaris
Let's start by configuring the Solaris host using the /etc/inet/ike/config
file, which is automatically loaded at boot time by the in.iked
daemon:
{
label "Partnership with Linux/Racoon"
local_addr 192.168.1.201
remote_addr 192.168.1.203
local_id_type ip
p1_xform { auth_method preshared oakley_group 2 auth_alg md5 encr_alg 3des }
}
IKE rules are separated by brackets and identified by a label. The
rules specify both local (local_addr) and remote ends (remote_addr)
that should be concerned. Also, the p1_xform instruction consists
in a proposal of a way to secure the commmunication. More instructions
are available in the ike.config (4) man page
This IKE rule will apply between local_addr and remote_addr in
both directions. The instruction named p1_xform describes a way
to secure the system. The IKE transaction will result in the choice
of a proposal common to both endpoints. The oakley_group instruction
defines the level of encryption for the second phase. Once we've
defined how the data should be protected, we must define a shared
secret key.
The key length will no longer need to be specific to the algorithm
used internally because real security associations will be generated
by IKE. Pre-shared keys are stored on Solaris in /etc/inet/secret/ike.preshared
as a set of rules identifying local and remote ends and their associated
shared secret. SunOS needs the keys to be written in hexadecimal
format. Set the file contents to the following in order to use the
simple secret "AAAAAAAA":
{
localidtype IP
localid 192.168.1.201
remoteidtype IP
remoteid 192.168.1.203
key 4141414141414141
}
Each pre-shared key is defined within a bracket pair. The key should
associate one host to another one. Localid and remoteid will be interpreted
depending on localidtype and remoteidtype, which state how the host
should be identified (by IP address in this example). The key field
defines the secret key in hexadecimal without any leading 0x.
Running /usr/lib/inet/in.iked -f /etc/inet/ike/config will
start the daemon and apply the rule defined without rebooting.
Configuring IKE with Racoon
The KAME project includes a daemon named racoon, which is responsible
for the key management. The following /etc/racoon/racoon.conf file
will define the same rules as on Solaris except that the rule will
apply to any remote host. In this configuration, the keyword "anonymous"
specifies the settings that should be applied to anyone negotiating
security:
path include '/etc/racoon';
path pre_shared_key '/etc/racoon/psk.txt'
# Phase 1 - Configuration
remote anonymous
{
exchange_mode main;
proposal { encryption_algorithm 3des; hash_algorithm md5; \
authentication_method pre_shared_key; dh_group 2; }
}
# Phase 2 - Configuration
sainfo anonymous
{
encryption_algorithm 3des ;
authentication_algorithm hmac_md5;
compression_algorithm deflate;
}
Both main (Phase 1) and quick modes (Phase 2) must be configured in
the racoon.conf file. The proposal keyword behaves like p1_xform on
the Solaris side. Compression_algorithm is a mandatory instruction
simply specifying that packet compression (IPComp) should not be enabled.
The /etc/racoon/psk.txt will simply contain the following line.
This simple secret key is the hexadecimal representation of the
string "AAAAAAAA". The pre-shared keys file will be searched for
the identifier of the remote peer so that its associated secret
will be used:
192.168.1.101 0x4141414141414141
Starting racoon -f /etc/racoon/racoon.conf will start the daemon
and apply the rule defined.
Testing Encryption
Now both racoon and in.iked have been loaded and configured properly,
a simple tcpdump will show that security associations for both directions
have been automatically created and indexed by SPIs that were not
defined manually:
# tcpdump host 192.168.1.201
tcpdump: listening on eth0
19:39:26.127175 test1 > test3: ESP(spi=0x06db34e8,seq=0x3) (DF)
19:39:26.127284 test3 > test1: ESP(spi=0x7aa657a6,seq=0x2)
2 packets received by filter
0 packets dropped by kernel
The goal of this article was to introduce and demonstrate some of
the basic yet powerful features of the IPsec framework. Many implementations
of this technology do exist, and it can be sometimes difficult to
make them work together. For more information on the subject, check
the following references.
References
IPsec and IKE Administration Guide in Solaris System Administrator
Collection -- http://docs.sun.com/db/doc/817-2694
The IETF IP Security Protocol working group Web page -- http://www.ietf.org/html.charters/ipsec-charter.html
FreeSWAN Web site -- http://www.freeswan.org
KAME Web site -- http://www.kame.net
IPsec Tools (Linux port of KAME) -- http://ipsec-tools.sourceforge.net/
Arnaud Aubert is an independent consultant and trainer working
from France. He contributes regularly to IT publications. He can
be reached at aaubert@magesi.com.
|