Algorithm Rollover in OpenDNSSEC 1.3

October 29, 2015 by yuri

Erratum: Unfortunately it appears that this method does not work for OpenDNSSEC 1.4.x. It still works for 1.3.x, specifically 1.3.18 is tested (thanks Michał Kępień!).

The current version of OpenDNSSEC is unable to perform an algorithm rollover. Blindly changing the KSK and ZSK algorithm in the kasp.xml will result in a bogus zone. The only option to do it is to go unsigned: Remove the DS record, wait, publish unsigned zone, and then start signing with the new algorithm. This is undesirable.

There is however a way to roll to a new algorithm securely if you are clever about it and don’t mind some manual intervention. We have worked out a way for you to do this. The nice part is that it requires no manual interaction with the HSM, and that ods-signerd, the signer daemon, can keep running without any interruptions. This means there needs to be no service downtime, your zonefile can still be updated and resigned during this process. For simplicity, a requirement is that your new keys must be of the same length as your old keys.

Also, please note that since we are working with key pairs, the key material should be compatible. This method allows us to switch between different RSA signature algorithms. For example from RSA/SHA-1 to RSA/SHA-256 but not from RSA/SHA-256 to P-256/SHA-256.

1 – Stop Enforcer

First we must stop ods-enforcerd. We will not start it again until the whole process is finished. Make sure nothing autostarts it, which could very well disrupt the whole rollover process badly. Also please make sure you are not currently in a rollover of some sort. Your signconf must mention two keys exactly. A KSK and a ZSK.

2 – Duplicate ZSK

We will edit the signing configuration for your zone. To persuade the signer to double sign everything we will introduce a new ZSK. But rather than generating a new key we will reuse the key material of the old key. This file will generally live under /var/opendnssec/signconf/.

Thus the following section…

<Keys>
  <Key>
    <Flags>257</Flags>
    <Algorithm>5</Algorithm>
    <Locator>b530cf857e0bf2768e3cbf8d59a572d6</Locator>
    <KSK />
    <Publish />
  </Key>
  <Key>
    <Flags>256</Flags>
    <Algorithm>5</Algorithm>
    <Locator>d4823c2f7eedceab5e5e3fd2c16c5dc4</Locator>
    <ZSK />
    <Publish />
  </Key>
</Keys>

would become

<Keys>
  <Key>
    <Flags>257</Flags>
    <Algorithm>5</Algorithm>
    <Locator>b530cf857e0bf2768e3cbf8d59a572d6</Locator>
    <KSK />
    <Publish />
  </Key>
  <Key>
    <Flags>256</Flags>
    <Algorithm>5</Algorithm>
    <Locator>d4823c2f7eedceab5e5e3fd2c16c5dc4</Locator>
    <ZSK />
    <Publish />
  </Key>
  <Key>
    <Flags>256</Flags>
    <Algorithm>8</Algorithm>
    <Locator>d4823c2f7eedceab5e5e3fd2c16c5dc4</Locator>
    <ZSK />
   </Key>
</Keys>

Take care not to include the “<Publish />” element for the new key.

Now the signer must pickup this change:

$ ods-signer update opendnssec.org

Note that at this point the signer is instructed to double sign your entire zone. It might take a long time for large zones, and your zone will possibly almost double in size. This is the only way to do a secure algorithm rollover in DNSSEC. Also, all your DNSSEC responses increase in size.

One might be tempted to also publish the DNSKEY records of the KSK and ZSK at this time. However I advise against that. If this is done, it is possible for a resolver to retrieve the new DNSKEY RRset (containing the new algorithm) but to have RRsets in its cache with signatures created by the old DNSKEY RRset (i.e., without the new algorithm). [see RFC6781]

We have to make sure every signature is picked up by intermediate resolvers before introducing the new DNSKEY records. Whatever the longest TTL is in your zone, dictates how long you have to wait before starting STEP 3.

3 – Duplicate KSK

For the KSK we do the same trick as for the ZSK: introduce a new key that uses the same key material as the old key. Your <Keys> section in the signconf will now look like this:

<Keys>
  <Key>
    <Flags>257</Flags>
    <Algorithm>5</Algorithm>
    <Locator>b530cf857e0bf2768e3cbf8d59a572d6</Locator>
    <KSK />
    <Publish />
  </Key>
  <Key>
    <Flags>256</Flags>
    <Algorithm>5</Algorithm>
    <Locator>d4823c2f7eedceab5e5e3fd2c16c5dc4</Locator>
    <ZSK />
    <Publish />
  </Key>
  <Key>
    <Flags>257</Flags>
    <Algorithm>8</Algorithm>
    <Locator>b530cf857e0bf2768e3cbf8d59a572d6</Locator>
    <KSK />
    <Publish />
  </Key>
  <Key>
    <Flags>256</Flags>
    <Algorithm>8</Algorithm>
    <Locator>d4823c2f7eedceab5e5e3fd2c16c5dc4</Locator>
    <ZSK />
    <Publish />
  </Key>
</Keys>

This time we add the “<Publish />” element to our new ZSK. Again we notify the signer of the changed signconf for our zone. Since algoritihm rollover is not officially supported it might take some effort to convince the signer to pick up all the changes:

$ ods-signer update opendnssec.org
$ ods-signer clear opendnssec.org
$ ods-signer sign opendnssec.org

At this point only the DNSKEY RRset should be changed. Once the resulting zone is transferred proceed to the next step.

We must be sure everyone was able to pick up the new DNSKEY RRset. Thus before proceeding to the next step wait at least the TTL of the DNSKEY RRset. You can find the TTL in the <keys> section of kasp.xml. Don’t even consider rushing over this step! Waiting here is of utter most importance.

4 – Generate DS

Since our DNSKEY changed, our DS will also be different. We can’t ask ods-ksmutil for the DS this time since it isn’t in the database yet. We can find the DNSKEY ofcource in the signed zonefile, a grep or even a simple dig should give it to us. Then we need to calculate the DS.

$ dig opendnssec.org DNSKEY |grep 257 > dnskeys
$ ldns-key2ds -n dnskeys

At this point you can switch the old DS record at the parent for the new one. Either in one action or add the newest first and then remove the oldest.

Then there is more waiting involved: the TTL of the DS record. Query your parent or look it up in the KASP. <Parent><DS><TTL>.

5 – Clean up

We will now remove the old KSK section from signconf, notify the signer and wait for TTL of DNSKEY RRset. We then remove the old ZSK entry from the signconf and notify the signer. (No need to wait here.)

$ ods-signer clear opendnssec.org
$ ods-signer sign opendnssec.org

6 – Mangle the Database

To get the enforcer state in line with the latest signconf is easy. Only the algorithm number is set different. A quick database edit can fix it. For Example:

$ sqlite3 /var/opendnssec/kasp.db
sqlite> UPDATE `keypairs` SET `algorithm`=8 WHERE 
  `HSMkey_id`='d4823c2f7eedceab5e5e3fd2c16c5dc4' OR 
  `HSMkey_id`='b530cf857e0bf2768e3cbf8d59a572d6';
$ mysql -u ods-db-usr opendnssec -p
mysql> UPDATE `keypairs` SET `algorithm`=8 WHERE
  `HSMkey_id`='d4823c2f7eedceab5e5e3fd2c16c5dc4' OR
  `HSMkey_id`='b530cf857e0bf2768e3cbf8d59a572d6';

The HSMkey_id can be find in the signconf as <Locator>.

7 – Start Enforcer

If everything was executed according to plan, the enforcer daemon once started should produce the same signconf as the one we last fabricated by hand. I recommend to verify this before feeding the signconf to the signer.

Wed Sep 25 2013

© Stichting NLnet Labs

Science Park 400, 1098 XH Amsterdam, The Netherlands

labs@nlnetlabs.nl, subsidised by NLnet and SIDN.