wiki:SecureDHCPv6

Secure DHCPv6

Reference https://tools.ietf.org/html/draft-ietf-dhc-sedhcpv6-08

Implementation notes

Code points

TBD -> 70 (e.g., 701 for the public key option, 708 for SignatureFail status).

Design

TOFU (trust-on-first-use) is not implemented mainly because there is no place in the current code to store the information.

Authorization is supported. It means when it is enabled a client may not impersonate another one. In this implementation it means:

  • packets without a public key or certificate option, or without a signature option (aka insecure packets) are rejected.
  • there must be a host reservation for the DUID or the hardware address in the subnet, or packets are rejected.
  • the public key or certificate in the option and in the host reservation are compared, when they don't match packets are rejected.

Source changes

lib/util/ntp_utils.{h,cc} and lib/util/tests/ntp_utils_unittest.cc implements NTP timestamps in the Ntp class.

lib/cryptolink asymetrical crypto version (aka trac3634a) is fixed and extended with from_bind9 and to_bind9 ad hoc tools for converting private key (which includes the public key in RSA).

in lib/dhcp:

  • secure DHCPv6 constants are defined in dhcp6.h. Note the algorithms are defines (vs enums) because some can collide with cryptolink.
  • the 4 secure DHCPv6 options are defined. Note the signature option is a custom one with 2 uint8_t fields for algorithm identifiers.

in lib/dhcpsrv:

  • secure-dhcp6 server configuratiion (both cfg and parser files, member and set/get in the server configuration class).
  • a credential field to get the public key or certificate is added to host reservations (class and parser).
  • TSlast and RDlast timestamp members are added to host reservation temporary state extension (cf #3915 ticket and trac3915a branch).
  • add a new parameter to configuration manager clear() method to solve a static destruction order fiasco with the Botan crypto backend on Fedora (another proof it is useful to vary compilers :-).
  • tests/testdata directory to keep the key material for unit tests. A README file explains how to build these files using the openssl command line.

in bin/dhcp6:

  • kea-dhcp6 server configuration syntax gets a secure-dhcp6 structure (flags and keys) and host reservation credentials.
  • some SEDHCP6_XXX log messages are added.
  • kea-dhcp6 server processing is extended in 3 points:
    • validateSeDhcpOptions() in all processXXX() routines on query and response packets and the client context (for the host reservation configuration) implements I-D section 6.2.
    • appendSeDhcpOptions() in run() on the response packet which implements I-D section 6.1 at the exception of the signature itself.
    • finalizeSignature() in run() on the response packet which implements the signature phase itself.
  • extend the unpackOptions6 with an extra signature offset parameter.
  • clear configurations before existing in main().
  • parseToBeSigned() local util to re-parse packets used in both ways.

And of course unit tests (not enough :-) and documentation (same comment)...

Configuration

Test bed on an iMac OS X 10.10.3 with VMware Fusion. Server (Kea sedhcpv6a branch) launched by kea-dhcp6 -d -c kea.conf. KEA_LOCKFILE_DIR environment variable must be set (to /tmp for instance). Note the interface must have an address in the IPv6 prefix (my Free 6to4 prefix so please replace by one of yours or an assigned to example/demo/... one, cf. RFC 6890).

Client on an Ubuntu 15.04 32 bit Virtual Machine with bridged Ethernet (MAC 00:0c:29:40:3b:88). Modified ISC DHCP (secure_client git branch). Two key files: foo.pkcs8 and foo.spki built using dnssec-keygen -a RSASHA256 -b 1024 foo, from_bind9 ad hoc tool and openssl. Configured by ./configure --with-atf=bind LIBS=-lcrypto, launched by ./dhclient -6 -v -d -lf /tmp/leases -k foo ethXXX. Tcpdump in another window: tcpdump -v -v -x -p -n -s 2000 -e -i eth0 udp port 547.

Server on the iMac host (Ethernet, firewall disabled) or on a Fedora 22 64 bit Virtual Machine.

Server Configuration File

Aka. kea.conf:

{

"Dhcp6":
{
  "interfaces-config": {
      "interfaces": [ "en0" ]
  },

  "lease-database": {
      "type": "memfile",
      "name": "/tmp/lease.csv"
  },

  "preferred-lifetime": 3000,
  "valid-lifetime": 4000,
  "renew-timer": 1000,
  "rebind-timer": 2000,

  "subnet6": [ {
       "subnet": "2a01:e35:2ec8:85d0::/64",
       "pools": [ { "pool": "2a01:e35:2ec8:85d0:1::/80" } ],
       "id": 1,
       "interface": "en0",
       "reservations":
       [ {
           "hw-address": "00:0c:29:40:3b:88",
	   "ip-addresses": [ "2a01:e35:2ec8:85d0::1234" ],
	   "public-key": "client.pem"
         } ]
   } ],

   "secure-dhcp6": {
       "sign-answers": true,
       "timestamp-answers": true,
       "public-key": "pub.pem",
       "private-key": "priv.pem",
       "check-signatures": true,
       "check-timestamps": true,
       "check-authorizations": true
   }
},

"Logging":
{
  "loggers": [
    {
      "name": "kea-dhcp6",
      "output_options": [
          {
            "output": "/tmp/kea-dhcp6.log"
          }
      ],
      "severity": "DEBUG",
      "debuglevel": 0
    } ]

}

}

Run example (client side)

vubuntu15:~/dhcp/client> sudo ./dhclient -6 -d -lf /tmp/leases -k foo eth0
Internet Systems Consortium DHCP Client 4.3.2
Copyright 2004-2015 Internet Systems Consortium.
All rights reserved.
For info, please visit https://www.isc.org/software/dhcp/

Listening on Socket/eth0
Sending on   Socket/eth0
PRC: Soliciting for leases (INIT).
XMT: Forming Solicit, 0 ms elapsed.
XMT:  X-- IA_NA 29:40:3b:88
XMT:  | X-- Request renew in  +3600
XMT:  | X-- Request rebind in +5400
XMT: Solicit on eth0, interval 1010ms.
RCV: Advertise message on eth0 from fe80::20c:29ff:fe9e:bfae.
RCV:  X-- IA_NA 29:40:3b:88
RCV:  | X-- starts 1433372488
RCV:  | X-- t1 - renew  +1000
RCV:  | X-- t2 - rebind +2000
RCV:  | X-- [Options]
RCV:  | | X-- IAADDR 2a01:e35:2ec8:85d0::1234
RCV:  | | | X-- Preferred lifetime 3000.
RCV:  | | | X-- Max lifetime 4000.
RCV:  X-- Server ID: 00:01:00:01:1d:02:43:c1:00:0c:29:9e:bf:ae
RCV:  Advertisement recorded.
RCV: Advertise message on eth0 from fe80::20c:29ff:fe9e:bfae.
RCV:  X-- IA_NA 29:40:3b:88
RCV:  | X-- starts 1433372488
RCV:  | X-- t1 - renew  +1000
RCV:  | X-- t2 - rebind +2000
RCV:  | X-- [Options]
RCV:  | | X-- IAADDR 2a01:e35:2ec8:85d0::1234
RCV:  | | | X-- Preferred lifetime 3000.
RCV:  | | | X-- Max lifetime 4000.
RCV:  X-- Server ID: 00:01:00:01:1d:02:43:c1:00:0c:29:9e:bf:ae
RCV:  Advertisement recorded.
PRC: Selecting best advertised lease.
PRC: Considering best lease.
PRC:  X-- Initial candidate 00:01:00:01:1d:02:43:c1:00:0c:29:9e:bf:ae (s: 153, p: 0).
XMT: Forming Request, 0 ms elapsed.
XMT:  X-- IA_NA 29:40:3b:88
XMT:  | X-- Requested renew  +3600
XMT:  | X-- Requested rebind +5400
XMT:  | | X-- IAADDR 2a01:e35:2ec8:85d0::1234
XMT:  | | | X-- Preferred lifetime +7200
XMT:  | | | X-- Max lifetime +7500
XMT:  V IA_NA appended.
XMT: Request on eth0, interval 980ms.
RCV: Reply message on eth0 from fe80::20c:29ff:fe9e:bfae.
RCV:  X-- IA_NA 29:40:3b:88
RCV:  | X-- starts 1433372489
RCV:  | X-- t1 - renew  +1000
RCV:  | X-- t2 - rebind +2000
RCV:  | X-- [Options]
RCV:  | | X-- IAADDR 2a01:e35:2ec8:85d0::1234
RCV:  | | | X-- Preferred lifetime 3000.
RCV:  | | | X-- Max lifetime 4000.
RCV:  X-- Server ID: 00:01:00:01:1d:02:43:c1:00:0c:29:9e:bf:ae
PRC: Bound to lease 00:01:00:01:1d:02:43:c1:00:0c:29:9e:bf:ae.
/sbin/dhclient-script: 55: /sbin/dhclient-script: shopt: not found
/sbin/dhclient-script: 68: /sbin/dhclient-script: shopt: not found
PRC: Renewal event scheduled in 1000 seconds, to run for 1000 seconds.
PRC: Depreference scheduled in 3000 seconds.
PRC: Expiration scheduled in 4000 seconds.
RCV: Reply message on eth0 from fe80::20c:29ff:fe9e:bfae.
RCV: Input packets are ignored once bound.

Added signature validation in the client:

...
RCV:  public key option (size 162)
RCV:  signature option (size 130)
RCV:  timestamp option (2015/06/04 23:11:08.858)
signature is valid.

Run example (server side)

2015-06-04 01:00:19.434 INFO  [kea-dhcp6.dhcp6/52787] DHCP6_STARTED Kea DHCPv6 server version 0.9.1-git started
...
2015-06-04 01:01:28.166 DEBUG [kea-dhcp6.dhcp6/52830] DHCP6_PACKET_RECEIVED SOLICIT packet received
2015-06-04 01:01:28.166 DEBUG [kea-dhcp6.dhcp6/52830] DHCP6_QUERY_DATA received packet length 1, data length 0, data is localAddr=[ff02::1:2]:0 remoteAddr=[fe80::20c:29ff:fe40:3b88]:546
msgtype=1, transid=0x1a43de
type=00001, len=00014: 00:01:00:01:1d:02:38:44:00:0c:29:40:3b:88
type=3(IA_NA) iaid=692075400, t1=3600, t2=5400 0 sub-options:

type=00006, len=00004: 23(uint16) 24(uint16)
type=00008, len=00002: 0 (uint16)
type=00701, len=00162: 30:81:9f: ... :01:00:01
type=00703, len=00130: 1 (uint8) 1 (uint8) A1DFC6B8F3 ... 7D (binary)
type=00704, len=00008: 00:00:d9:1a:05:c8:35:2a

2015-06-04 01:01:28.166 DEBUG [kea-dhcp6.dhcpsrv/52830] DHCPSRV_CFGMGR_SUBNET6_IFACE selected subnet 2a01:e35:2ec8:85d0::/64 for packet received over interface eno16777736
2015-06-04 01:01:28.166 DEBUG [kea-dhcp6.hosts/52830] HOSTS_CFG_GET_ONE_SUBNET_ID_HWADDR_DUID get one host with IPv6 reservation for subnet id 1, HWADDR hwtype=1 00:0c:29:40:3b:88, DUID 00:01:00:01:1d:02:38:44:00:0c:29:40:3b:88
2015-06-04 01:01:28.166 DEBUG [kea-dhcp6.hosts/52830] HOSTS_CFG_GET_ALL_HWADDR_DUID get all hosts with reservations for HWADDR hwtype=1 00:0c:29:40:3b:88 and DUID 00:01:00:01:1d:02:38:44:00:0c:29:40:3b:88
2015-06-04 01:01:28.166 DEBUG [kea-dhcp6.hosts/52830] HOSTS_CFG_GET_ALL_IDENTIFIER get all hosts with reservations using identifier: hwaddr=00:0c:29:40:3b:88
2015-06-04 01:01:28.166 DEBUG [kea-dhcp6.hosts/52830] HOSTS_CFG_GET_ALL_IDENTIFIER_HOST using identifier: hwaddr=00:0c:29:40:3b:88, found host: hwaddr=00:0c:29:40:3b:88 ipv6_subnet_id=1 hostname=(empty) ipv4_reservation=(no) ipv6_reservation0=2a01:e35:2ec8:85d0::1234 credential=client.pem
2015-06-04 01:01:28.166 DEBUG [kea-dhcp6.hosts/52830] HOSTS_CFG_GET_ALL_IDENTIFIER_COUNT using identifier hwaddr=00:0c:29:40:3b:88, found 1 host(s)
2015-06-04 01:01:28.166 DEBUG [kea-dhcp6.hosts/52830] HOSTS_CFG_GET_ALL_IDENTIFIER get all hosts with reservations using identifier: duid=00:01:00:01:1d:02:38:44:00:0c:29:40:3b:88
2015-06-04 01:01:28.166 DEBUG [kea-dhcp6.hosts/52830] HOSTS_CFG_GET_ALL_IDENTIFIER_COUNT using identifier duid=00:01:00:01:1d:02:38:44:00:0c:29:40:3b:88, found 1 host(s)
2015-06-04 01:01:28.166 DEBUG [kea-dhcp6.hosts/52830] HOSTS_CFG_GET_ONE_SUBNET_ID_HWADDR_DUID get one host with 1 reservation for subnet id hwtype=1 00:0c:29:40:3b:88, HWADDR 00:01:00:01:1d:02:38:44:00:0c:29:40:3b:88, DUID hwaddr=00:0c:29:40:3b:88 ipv6_subnet_id=1 hostname=(empty) ipv4_reservation=(no) ipv6_reservation0=2a01:e35:2ec8:85d0::1234 credential=client.pem
2015-06-04 01:01:28.166 DEBUG [kea-dhcp6.dhcp6/52830] SEDHCP6_OPTION_RECEIVED secure DHCPv6 option has been received: type public key
2015-06-04 01:01:28.166 DEBUG [kea-dhcp6.dhcp6/52830] SEDHCP6_OPTION_RECEIVED secure DHCPv6 option has been received: type signature
2015-06-04 01:01:28.166 DEBUG [kea-dhcp6.dhcp6/52830] SEDHCP6_INCOMING_TRACE secure DHCPv6 processing: checking algorithms
2015-06-04 01:01:28.166 DEBUG [kea-dhcp6.dhcp6/52830] SEDHCP6_INCOMING_TRACE secure DHCPv6 processing: creating RSA objects
2015-06-04 01:01:28.166 DEBUG [kea-dhcp6.dhcp6/52830] SEDHCP6_INCOMING_TRACE secure DHCPv6 processing: comparing with config
2015-06-04 01:01:28.187 DEBUG [kea-dhcp6.dhcp6/52830] SEDHCP6_INCOMING_TRACE secure DHCPv6 processing: handling timestamp
2015-06-04 01:01:28.187 DEBUG [kea-dhcp6.dhcp6/52830] SEDHCP6_OPTION_RECEIVED secure DHCPv6 option has been received: type timestamp
2015-06-04 01:01:28.187 DEBUG [kea-dhcp6.dhcp6/52830] SEDHCP6_INCOMING_TRACE secure DHCPv6 processing: new client
2015-06-04 01:01:28.187 DEBUG [kea-dhcp6.dhcp6/52830] SEDHCP6_INCOMING_TRACE secure DHCPv6 processing: checking signature
2015-06-04 01:01:28.187 DEBUG [kea-dhcp6.dhcp6/52830] SEDHCP6_INCOMING_TRACE secure DHCPv6 processing: signature is valid
2015-06-04 01:01:28.187 DEBUG [kea-dhcp6.dhcp6/52830] SEDHCP6_INCOMING_TRACE secure DHCPv6 processing: updating timestamps
2015-06-04 01:01:28.187 DEBUG [kea-dhcp6.dhcp6/52830] SEDHCP6_TIMESTAMP_UPDATED timestamps have been updated
2015-06-04 01:01:28.187 DEBUG [kea-dhcp6.dhcp6/52830] DHCP6_SUBNET_SELECTED the 2a01:e35:2ec8:85d0::/64 subnet was selected for client assignment
2015-06-04 01:01:28.187 DEBUG [kea-dhcp6.dhcp6/52830] DHCP6_PROCESS_IA_NA_REQUEST server is processing IA_NA option (duid=00:01:00:01:1d:02:38:44:00:0c:29:40:3b:88, iaid=692075400, hint=(no hint))
2015-06-04 01:01:28.187 DEBUG [kea-dhcp6.dhcpsrv/52830] DHCPSRV_MEMFILE_GET_IAID_SUBID_DUID obtaining IPv6 leases for IAID 692075400, Subnet ID 1, DUID 00:01:00:01:1d:02:38:44:00:0c:29:40:3b:88 and lease type IA_NA
2015-06-04 01:01:28.187 DEBUG [kea-dhcp6.dhcpsrv/52830] DHCPSRV_MEMFILE_GET_ADDR6 obtaining IPv6 lease for address 2a01:e35:2ec8:85d0::1234 and lease type IA_NA
2015-06-04 01:01:28.187 DEBUG [kea-dhcp6.dhcpsrv/52830] DHCPSRV_MEMFILE_GET_ADDR6 obtaining IPv6 lease for address 2a01:e35:2ec8:85d0::1234 and lease type IA_NA
2015-06-04 01:01:28.187 INFO  [kea-dhcp6.dhcpsrv/52830] DHCPSRV_HR_RESERVED_ADDR_GRANTED reserved address 2a01:e35:2ec8:85d0::1234 was was assigned to client (duid=00:01:00:01:1d:02:38:44:00:0c:29:40:3b:88)
2015-06-04 01:01:28.187 DEBUG [kea-dhcp6.dhcp6/52830] DHCP6_LEASE_ADVERT address lease 2a01:e35:2ec8:85d0::1234 advertised (client duid=00:01:00:01:1d:02:38:44:00:0c:29:40:3b:88, iaid=692075400)
2015-06-04 01:01:28.187 DEBUG [kea-dhcp6.dhcp6/52830] SEDHCP6_OPTION_ADDED secure DHCPv6 option has been added: type public key, size 166
2015-06-04 01:01:28.187 DEBUG [kea-dhcp6.dhcp6/52830] SEDHCP6_OPTION_ADDED secure DHCPv6 option has been added: type signature, size 134
2015-06-04 01:01:28.188 DEBUG [kea-dhcp6.dhcp6/52830] SEDHCP6_OPTION_ADDED secure DHCPv6 option has been added: type timestamp, size 12
2015-06-04 01:01:28.188 DEBUG [kea-dhcp6.dhcp6/52830] DHCP6_RESPONSE_DATA responding with packet type 2 data is localAddr=[ff02::1:2]:547 remoteAddr=[fe80::20c:29ff:fe40:3b88]:546
msgtype=2, transid=0x1a43de
type=00001, len=00014: 00:01:00:01:1d:02:38:44:00:0c:29:40:3b:88
type=00002, len=00014: 00:01:00:01:1d:02:43:c1:00:0c:29:9e:bf:ae
type=3(IA_NA) iaid=692075400, t1=1000, t2=2000 1 sub-options:
  type=5(IAADDR) addr=2a01:e35:2ec8:85d0::1234, preferred-lft=3000, valid-lft=4000

type=00701, len=00162: 30:81:9f:30:0d:06:09:2a:86:48:86:f7:0d:01: ... 1f:ca:7e:1d:02:03:01:00:01
type=00703, len=00130: 1 (uint8) 1 (uint8) 0000000 ... 00000000 (binary)
type=00704, len=00008: 00:00:d9:1a:05:c8:30:21

2015-06-04 01:01:28.188 DEBUG [kea-dhcp6.dhcp6/52830] SEDHCP6_SIGNATURE_DUMP final signature: 44570A414D3A0C6E602861686A6AC5 ... 185D59F1

TODO list

  • take 2 (DONE, tested).
  • implement validation-policy for the online value. (DONE, untested)
  • test secure DHCPv6 with a relay (should work!).
  • implementing verification in the ISC DHCP secure client. (DONE, authorisation to do)
Last modified 2 years ago Last modified on Jul 15, 2015, 11:39:53 AM