100200300400500600
  
 
 

IPSec with DNSSEC

Since future has come, we need to pace ahead and utilize its merits. One of the benefits of having DNSSEC is independence in making own certs (with DANE) and simplified roll-out of those certs (with CERT RR).

First I want to mention about choice of IPSec stack. I've tried to make a research, comparison, etc. and stopped on StrongSWAN first. After all I'm familiar with SWAN family from pluto/KLIPS times when KAME was sturdy BSD-only feature. Alas - I wasn't able to make anything useful with it. My bad. But time is short - Big Brother is watching me, and you, and everyone, so racoon - despite being poorly maintained - is still working and available out-of-the-box on most distros.

Racoon

So as a first step we would set racoon configuration - to understand our prerequisites, and to make sure keying is working. After all - keying is the most tricky thing, once isakmp SA is obtained - it is a mechanical operation to set actual encryption.

remote anonymous {
        exchange_mode main,base,aggressive;
        my_identifier fqdn "host.domain.tld";
        certificate_type x509 "/etc/ssl/certs/www.pem"
			    "/etc/ssl/private/www.key";
        peers_certfile dnssec;
        send_cert off;
        send_cr off;
        proposal {
                encryption_algorithm aes;
                hash_algorithm sha256;
                authentication_method rsasig;
                dh_group modp1024;
        }
        nat_traversal on;
}
sainfo anonymous {
        pfs_group modp768;
        encryption_algorithm aes;
        authentication_algorithm hmac_sha1;
        compression_algorithm deflate;
}

As simple as this should suffice for most of our needs. So - exchange mode is standard, but next 3 rows are important for our DNSSEC setup. my_identifier is saying that we would lookup the peer based on its FQDN - that is when we contact remote system we identify ourself by this name (not by IP or any other arbitrary identifier). This is important since this ID will then be used by remote system to validate us, obtain our certificate and validate all together by matching pieces.

Next is our certificate - we'll discuss certificate later for now let just keep in mind that we would need our local certificate and key since that's what we'll be publishing in DNS.

And finally with peers_certfile dnssec we specify that we do not care what peer is going to send us as its certificate, instead we want to rely on DNSSEC to get the right one. With this approach sending or requesting certificates inside IKE negotiation is unnecessary overhead and hence next two lines - do not send our cert over the line and not even request one from remote side.

Proposal section in general is up to you, although important part is authentication which would be rsasig for our certificates. Since we're going to deal with remote machines with dynamic IPs (whoa, how you're going to keep protected DNS record for dynamic address is out of the scope of this article - I'm doing it with the script) we also need nat_traversal. Next section sainfo is also up to you and no recommendation are here.

Certificate

Certificate appeared to be a tricky part, since the one I generated some time ago for the host was simply refused. The problem appeared in the way how verification is done. I always thought that CN part of the DN should just represent the hostname and that's it. Not a bit. It's old and deprecated approach, supported by modern crypto stuff just out of compatibility. Modern systems are relying on subjectAltName x509v3 extension. The extension could carry multiple values, listing all the valid names and aliases, including FQDN, email and IP addresses.

The way Racoon does validation is following:

  1. Initiator does Phase1 by negotiating proposals and sending its ID(FQDN as specified above)
  2. Responder does CERT lookup for ID (requesting and verifying DNSSEC AD flag)
  3. Responder extracts subjectAltName attributes and iterates through them to find the match
  4. Peers are doing DH exchange using initiator's private key and responder's fetched RSA cert.

I didn't find any proper way to attach the attribs from the command line so you'd need to edit openssl.conf file to get them defined. Hence first add a section to the conf (used in your system by default or create a new one) and then generate a cert using defined extension:

echo >> /etc/ssl/openssl.conf
echo "[ v3_alt ]" >> /etc/ssl/openssl.conf
echo -n "subjectAltName=email:copy," >> /etc/ssl/openssl.conf
echo -n "DNS:host1.tld,DNS:host2.tld," >> /etc/ssl/openssl.conf
echo "IP:ip1.v4.addr,IP:ip1:v6::addr" >> /etc/ssl/openssl.conf
sed -i 's/ = v3_ca/ = v3_alt/' /etc/ssl/openssl.conf
openssl req -new -newkey rsa:2048 -keyout /etc/ssl/private/www.pem \
    -out /etc/ssl/certs/www.pem -days 700 -nodes -x509

This example above is based on default Ubuntu pki/ssl setup. Here we first adding two lines with extension definition, then modifying default openssl.conf by replacing assigned by default v3_ca extension with our newly defined v3_alt definition for self-signed certificate requests, and finally executing this self signed request. Important parts in last line are -nodes to generate non-encrypted private key, and -x509 to generate self-signed certificate instead of certificate request.

Don't forget to place cert and key to the path configured in racoon.conf

DNSSEC

This is the easiest part. Luckily NSD supports CERT RRs so we just need to define it for corresponding host. The format of the record is R TTL CLASS CERT purpose tag algo key. Honestly Racoon ignores all these fields except CERT and key. But just to be at least somehow compliant we'll define it as CERT PKIX 0 5 keydata.

Keydata is simple base64 encoded certificate, just take a content of the cert file between -BEGIN/END CERTIFICATE-. yes, this is really big for 2048 RSA key. I would definitely prefer ECC key which is a way shorter. But we're tied for the moment to RSA since this is what Racoon supports in the proposal. So the end result will look something like:

		IN CERT ( PKIX 0 5 MIIblahblablah
		foofoofoo
		barbarbar
		bazbazbaz
		idontknowanyotherstupidwords
		manyotherlinesoftextgarbage
		== )

So this huge pile of text will be returned each time phase1 is negotiated. Anyone volunteers implementing ECC? But on the other hand this pile could be transfered only via TCP which somehow decreases spoofing, with RRSIG protecting against forging.

Speaking of RRSIG - if you protect your CERT with NSEC - RRSIG will be also replied to Racoon - which confuses it and makes it refuse the CERT. See this bug. You may use provided patch in the bug report or pre-built deb from ppa

Before making a final stroke let confirm ike works by initiating and checking connection:

# racoonctl -w establish-sa isakmp inet host1.domain.tld  host2.domain.tld
# racoonctl show-sa isakmp
Destination            Cookies                           Created
11.22.33.44.4500     7d432a32907ce0d6:50db0dae7658a4cd 2013-08-13 15:17:51

IPSec

This is probably the easiest part. At least if you already dealt with IPSec on KAME - nothing new here. The only thing I spotted - and honestly was hopping to utilize - is sthat you cannot forward IPv6 packets in IPv4 policy. Sender is encapsulating and forwarding as expected, but receiver never can extract the packet. Maybe patch will follow but... who cares. IPv4 is dead.

#!/usr/sbin/setkey -f

flush;
spdflush;

spdadd 10.10.10.25 46.167.245.136 any -P in  ipsec 
    esp/tunnel/11.22.33.44[4500]-46.167.245.136[4500]/require;
spdadd 46.167.245.136 10.10.10.25 any -P out ipsec 
    esp/tunnel/46.167.245.136[4500]-11.22.33.44[4500]/require;

spdadd 2a01:8c00:ff6d:1::252 2a01:5e0:36:5001::2 any -P in  ipsec
    esp/transport//require;
spdadd 2a01:5e0:36:5001::2 2a01:8c00:ff6d:1::252 any -P out ipsec
    esp/transport//require;

Don't tell me we can do the same with xfrm. I know. But at least we have startup scripts out-of-the-box, and with xfrm will come stupid user-friendly-wrapper-shell-library. So what's the difference.

Here we just add two ipsec SA, saying that all traffic to 10.10.10.25 we need to encap to ESP and send to 1.2.3.4 over NAT-T port (i.e. ESP-UDP), and returning traffic from that host we would like to decrypt. Similarly we want to send IPv6 traffic between nodes as is(transport), just slightly obfuscated by ipsec. 1.2.3.4 here is dynamic IP. Well, you can't use xauth and DNSSEC. As per my knowledge.

On poor obstinated by _dead IPv4_ node we will add following:

#!/usr/sbin/setkey -f
## Flush the SAD and SPD
#
flush;
spdflush;

spdadd 10.10.10.25 46.167.245.136 any -P out ipsec
    esp/tunnel/10.10.10.25[4500]-46.167.245.136[4500]/require;
spdadd 46.167.245.136 10.10.10.25 any -P in  ipsec
    esp/tunnel/46.167.245.136[4500]-10.10.10.25[4500]/require;

spdadd 2a01:8c00:ff6d:1::252 2a01:5e0:36:5001::2 any -P out ipsec
    esp/transport//require;
spdadd 2a01:5e0:36:5001::2 2a01:8c00:ff6d:1::252 any -P in  ipsec
    esp/transport//require;

And now you should show a finger to NSA and enjoy the silence. Since silence is the best protection against eavesdropping.

Wed Aug 14 08:43:41 2013
 
 
© ruff 2011