Archive for October, 2010

Alignment fixes for natpmpd

Sunday, October 24th, 2010

A one line fix and natpmpd should now work on OpenBSD platforms that have stricter code alignment requirements than i386 or amd64 such as armish and sparc64. Fairly amazed that was the only breakage.

Next release should hopefully have privilege separation now that the various imsg_*(3) functions will be easily available in the 4.8 release.

Nokia Series 60 and a Cisco VPN

Friday, October 15th, 2010

One redeeming feature of Series 60 Nokia phones is there’s a reasonable IPsec VPN client available. It might be pre-installed on your phone already or you can check if your phone is compatible and download it here.

It can however be a bit of a pig to configure as you do very little of it on the phone and instead you have to supply a VPN policy file with all of the various settings contained within. Nokia ship a tool that allows you to create these, however it’s only available for Windows, so if you’re on a Mac or a Linux machine you’re out of luck. However, when you realise that a VPN policy file is just a renamed ZIP archive there’s no need to give up.

Nokia have documentation available specifically the VPN Client Policy Specification that explains what the various files in the ZIP archive are for. Unless you authenticate via certificates, chances are you only need the minimum two required files in the archive.

The first of these is a .pin file. It’s a really simple file that just supplies the policy details and is formatted like so:

1
2
3
4
5
6
7
8
9
10
[POLICYNAME]
Company VPN
[POLICYVERSION]
1.0
[POLICYDESCRIPTION]
Secure access to internal systems
[ISSUERNAME]
My Company
[CONTACTINFO]
vpn@domain.com

For the most part, you only really need to specify the policy name and version, the other fields can be empty as they aren’t generally visible.

The other required file is the .pol file. This one is a lot more complicated as it specifies all of the various IKE and IPsec parameters. A sample one looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
SECURITY_FILE_VERSION: 1
[INFO]
Company VPN
[POLICY]
sa CISCO_ASA_PSK = {
esp
encrypt_alg 3
auth_alg 2
identity_remote 0.0.0.0/0
src_specific
hard_lifetime_bytes 0
hard_lifetime_addtime 3600
hard_lifetime_usetime 3600
soft_lifetime_bytes 0
soft_lifetime_addtime 3600
soft_lifetime_usetime 3600
replay_win_len 0
}
 
remote 0.0.0.0 0.0.0.0 = { CISCO_ASA_PSK(vpn.domain.com) }
inbound = { } 
outbound = { }
 
[IKE]
ADDR: vpn.domain.com 255.255.255.255
IKE_VERSION: 1
MODE: Aggressive
REPLAY_STATUS: FALSE
USE_MODE_CFG: TRUE
IPSEC_EXPIRE: TRUE
USE_XAUTH: TRUE
USE_COMMIT: FALSE
ESP_UDP_PORT: 0
SEND_NOTIFICATION: TRUE
INITIAL_CONTACT: TRUE
USE_INTERNAL_ADDR: FALSE
DPD_HEARTBEAT: 90
NAT_KEEPALIVE: 60
REKEYING_THRESHOLD: 90
ID_TYPE: 11
FQDN: group
PRESHARED_KEYS:
FORMAT: STRING_FORMAT
KEY: 8 password
USE_NAT_PROBE: FALSE
PROPOSALS: 1
ENC_ALG: 3DES-CBC
AUTH_METHOD: PRE-SHARED
HASH_ALG: MD5
GROUP_DESCRIPTION: MODP_1024
GROUP_TYPE: DEFAULT
LIFETIME_KBYTES: 0
LIFETIME_SECONDS: 86400
PRF: NONE

When creating this file it’s handy to know what the other side is expecting otherwise a lot of trial and error is involved.

The above file works for me to connect to a Cisco ASA firewall, some key points:

  • Lines 7 & 8 specify the IPsec crypto algorithms, in this case 3DES-MD5. To use for example AES-SHA1 instead you would change the values on those lines to 12 and 3 respectively.
  • Line 20 specifies the address of your VPN server, this can be either a fully-qualified domain name or an IP address.
  • Line 25 repeats the address of your VPN server, except this time you also need to specify the netmask, which in most cases is 255.255.255.255.
  • Line 31 enables XAUTH which is required in common Cisco setups where you authenticate with your own personal username and password which is quite often linked to Active Directory, etc.
  • Lines 40 & 41 specify the first authentication step which in my setup is a shared group and password, so ID type 11 is used to specify that FQDN is just bytes rather than an IP address or fully-qualified domain, etc. then the group name itself is specified on the following line.
  • Line 44 specifies the password, note that you first specify the length of the password followed by the actual password string itself.
  • Lines 47 & 49 specify the IKE crypto algorithms. In contrast to the IPsec values these are actually spelled out instead of using cryptic values.

It’s important that both of these files are saved in DOS format with the correct newlines. You can use for example unix2dos(1) to convert them:

# unix2dos policy.p*

Then all that is left is to create the zip archive:

# zip policy.vpn policy.p*

It’s important that all three files share a common basename, in this example we used “policy” but it can be anything.

Now you need to upload the .vpn file to the phone. This can be done in any number of ways, such as USB or Bluetooth. You then need to run the file on the phone which forces it to be installed as a VPN policy.

Once that’s done you need to create a VPN access point which is accessed on my Nokia E71 under Tools > Settings > Connection > VPN > VPN access points. There you create a new access point, you need to give it a name, pick the policy that you just installed and an existing access point for it to piggyback on top of such as your 3G/GPRS connection or WiFi.

With the VPN access point defined you now use it like a regular access point. One thing I haven’t managed to get working yet is split tunnelling so that while I’m using the VPN I can access regular websites, instead I have to reconnect with a non-VPN access point but this is a minor niggle.

OpenBSD IPsec and RFC 3884

Sunday, October 3rd, 2010

As part of another OpenBSD & IPsec problem I’m investigating, I was pointed at RFC 3884 which puts forward a solution for solving problems with dynamic routing protocols and the use of IPsec in tunnel mode.

The RFC covers a few scenarios and solutions, but the main solution put forward is to replace IPsec tunnel mode with a combination of IPsec transport mode and the use of IP-in-IP tunnels. This has the benefit that it remains interoperable with IPsec tunnel mode implementations as the packet format is identical.

To show this you need to understand how IPsec packets are constructed. The RFC covers this and there also sites like this one which give you better diagrams. You only really need to pay attention to how ESP works rather than AH as AH is rarely used due to it’s shortcomings with the dreaded NAT. Once you know that all an IP-in-IP tunnel does is encapsulate an existing IP packet with another one you can see how the two implementations have the same wire format, the innermost packets just have a slightly different route through the network stack.

Anyway, after reading this I thought I’d test it to see if it really does work between a pair of OpenBSD hosts so I fired up a couple of stock 4.7 installs under VMware.

On both hosts I disabled pf to eliminate that as a source of any failures:

# pfctl -d

For reasons I’ll explain later, we’ll just deal with manually keyed IPsec so you’ll need to generate a handful of keys. On each host generate an authentication and encryption key:

# openssl rand 32 | hexdump -e '"0x" 32/1 "%02x" "\n"'
0x7a5a5832c43395c62aa1c443cfda68f3f8fff89378fdb2df40419df01547a40a
# openssl rand 16 | hexdump -e '"0x" 16/1 "%02x" "\n"'
0x811ce51cebcaed4280aae9cb2e195f93

On the first host we’ll set up the regular IPsec tunnel. Add the following to /etc/ipsec.conf using the keys we generated:

flow esp from 10.0.0.1/32 to 10.0.0.2/32 local 172.16.252.128 peer 172.16.252.130
esp tunnel from 172.16.252.128 to 172.16.252.130 spi 0xdeadbeef:0xfeedbeef \
        authkey 0xebfd3e8038fd1c9eadcc32308e5f12aba813114614855e4a93e7407f3c40f827:0x7a5a5832c43395c62aa1c443cfda68f3f8fff89378fdb2df40419df01547a40a \
        enckey 0x46c670e4ad2ef30a29a0ce64738d01e5:0x811ce51cebcaed4280aae9cb2e195f93

We’ll need a dummy interface with the 10.0.0.1 address for testing, the easiest way is to just use the loopback interface like so:

# ifconfig lo1 create
# ifconfig lo1 10.0.0.1 prefixlen 32

On the second host, we’ll need to set up the IP-in-IP tunnel which on an OpenBSD host uses the gif(4) interface:

# ifconfig gif0 create
# ifconfig gif0 tunnel 172.16.252.130 172.16.252.128
# ifconfig gif0 10.0.0.2 10.0.0.1 prefixlen 32

Now add the following to /etc/ipsec.conf using the same keys, but remember to swap around the various parameters:

flow esp proto ipencap from 172.16.252.130 to 172.16.252.128
esp transport from 172.16.252.130 to 172.16.252.128 spi:0xfeedbeef:0xdeadbeef \
        authkey 0x7a5a5832c43395c62aa1c443cfda68f3f8fff89378fdb2df40419df01547a40a:0xebfd3e8038fd1c9eadcc32308e5f12aba813114614855e4a93e7407f3c40f827 \
        enckey 0x811ce51cebcaed4280aae9cb2e195f93:0x46c670e4ad2ef30a29a0ce64738d01e5

Note that we only apply transport mode to the IP-in-IP tunnel packets (proto ipencap) otherwise all other traffic will be dropped by the first host if you tried ping, SSH, etc. between them.

With that done, on each host now do:

# ipsecctl -f /etc/ipsec.conf

Everything should be working now so on the first host with the regular IPsec tunnel, try pinging the remote IP address. You’ll need to specify the source address so it matches the IPsec flow:

# ping -I 10.0.0.1 10.0.0.2
PING 10.0.0.2 (10.0.0.2): 56 data bytes
64 bytes from 10.0.0.2: icmp_seq=0 ttl=255 time=0.628 ms
64 bytes from 10.0.0.2: icmp_seq=1 ttl=255 time=0.670 ms
...

While that’s running, on the opposite host you should be able to use tcpdump to see the IPsec traffic flowing back and forth:

# tcpdump -nn -i vic0
tcpdump: listening on vic0, link-type EN10MB
23:43:43.067641 esp 172.16.252.128 > 172.16.252.130 spi 0xdeadbeef seq 23 len 136
23:43:43.067880 esp 172.16.252.130 > 172.16.252.128 spi 0xfeedbeef seq 55 len 136
...

You can also use tcpdump on the enc0 interface to see the packets passing through the IPsec stack:

# tcpdump -nn -i enc0
tcpdump: listening on enc0, link-type ENC
23:46:51.679546 (authentic,confidential): SPI 0xdeadbeef: 10.0.0.1 > 10.0.0.2: icmp: echo request (encap)
23:46:51.679628 (authentic,confidential): SPI 0xfeedbeef: 10.0.0.2 > 10.0.0.1: icmp: echo reply (encap)
...

Here you can see the actual payload of the packets, in this case ICMP.

You can repeat the test from the opposite side with the gif0 interface:

# ping 10.0.0.1
PING 10.0.0.1 (10.0.0.1): 56 data bytes
64 bytes from 10.0.0.1: icmp_seq=0 ttl=255 time=1.008 ms
64 bytes from 10.0.0.1: icmp_seq=1 ttl=255 time=0.549 ms
...

Note that you don’t need to specify a source address this time as the routing sorts this out and correctly assigns you the local address of the IP-in-IP tunnel interface, (this is in fact another perceived benefit of the solution proposed by the RFC).

So we’ve hopefully proved it works, however this has only been demonstrated for manually keyed IPsec associations. Most IPsec these days is set up using IKE to automatically exchange keys in various forms and dynamically configure the flows on the hosts.

Here lies the problem, if I set up each end to use isakmpd(8) neither end will agree on a proposal as one side will propose tunnel mode and the other will propose transport mode. What I need to be able to do is get the transport side to propose tunnel mode but actually configure transport mode flows on the local side and rely on a suitable gif(4) interface to be set up. Currently there doesn’t appear to be a way to do this with isakmpd(8).