(new Soapbox())->shout(array_map('strtoupper', $opinions)); //Shaun's blog


Me, elsewhere

GitHub
parseword
Miscellaneous public code

Twitter
@parseword
I don't tweet much

XMPP chat
xmpp@shaunc.com
(Pidgin, Miranda, Swift, etc.)

Generating vanity DNSSEC key tags

Posted October 16, 2018 by shaun

After watching the root DNSSEC KSK rollover transpire with no notable fallout, I thought it would be a good time to try a rollover of my own. My attitude towards DNSSEC has been to set it and forget it, so I've never touched a zone's keys after the initial signing procedure. What better time to practice a rollover than when it's top of mind?

While I was poking around, I decided the key tags for this zone were a little boring and could use some spicing up:

[parse@stemmons ~]$ delv DNSKEY shaunc.com. +nocrypto +short
    256 3 8 [key id = 18723]  ; ZSK; alg = RSASHA256 ; key id = 18723
    257 3 8 [key id = 1300]  ; KSK; alg = RSASHA256 ; key id = 1300

Key tags, like 1300 and 18723 above, are generated random-ish-ly when you mint a new key with dnssec-keygen. There's a function that computes the key tag based on the key type, protocol, algorithm, and key text. Considering that the key itself is derived from pseudorandom input, the identifier for any given key ends up being "random" for all practical purposes. The output is an unsigned 16-bit integer, giving key tags a range of 00000 to 65535 inclusive.

But I didn't want random numbers anymore; I wanted custom values.

Vanity DNSSEC key tag generator

Brute force is the only option for getting a specific key tag value, so I wrote a little bash script that runs dnssec-keygen over and over until it creates a key with a particular tag. Set KEY_ZONE to the domain you want to sign, and DESIRED_KEYTAG to any integer between 0 and 65535. If you want an exact number containing fewer than 5 digits, you'll need to zero-pad it, like 00123.

#!/bin/bash

KEY_ZONE=example.org
DESIRED_KEYTAG=12345

while true; do

    for i in {1..100}; do

        #KEYTAG=$(dnssec-keygen -a RSASHA256 -b 2048 -f KSK ${KEY_ZONE} | cut -f3 -d'+')
        KEYTAG=$(dnssec-keygen -a ECDSAP256SHA256 -f KSK ${KEY_ZONE} | cut -f3 -d'+')
        if [[ $KEYTAG = *${DESIRED_KEYTAG}* ]]; then
            echo "Key with desired tag has been generated."
            exit
        fi

        #Keep a log of which key tags we've seen
        echo $KEYTAG >> keytags.txt

    done

    #Clean up and relax
    rm -f *.key *.private
    sleep 15

done

I let this run on 3 machines for 12 hours generating 2048-bit RSASHA256 (algorithm 8) keys, and never got a key with the desired tag. Checking the combined output files, the script had produced 591,000 keys but only 16,386 unique key tags, approximately a quarter of the expected potential values. The collisions displayed an affinity towards integers in the 60000s. I don't know whether this is a function of the inputs involved with RSASHA256, a quirk of hardware configuration, or what.

Hoping for a better outcome, I switched to ECDSAP256SHA256 (algorithm 13), and the script produced the intended 1337-tagged KSK after just 110 minutes. I ran it a second time to get a 31337-tagged ZSK, which took another 54 minutes. Reviewing the output for these runs, the set of generated key tags was more evenly distributed. Out of 142,760 keys generated, there were 58,130 unique key tags, covering most of the spectrum with fewer collisions.

Clearly, ECDSAP256SHA256 is more conducive to getting the key tag you want. It also happens to be current best practice. Per Algorithm Implementation Requirements and Usage Guidance for DNSSEC, which is on track to supersede RFC6944,

"Due to industry-wide trend to move to elliptic curve cryptography, the ECDSAP256SHA256 is RECOMMENDED for use by new DNSSEC deployments, and users of RSA based algorithms SHOULD upgrade to ECDSAP256SHA256."

More notes on key generation

  • dnssec-keygen has a variety of options. Of particular importance are -a to set the key algorithm, -b to set the key size in bits, and -f KSK if you want to generate a KSK (the program defaults to ZSK). Be sure to fiddle with those flags in the script if you want something else.

  • All 65536 key tag values may not be producible by every algorithm. If the script runs for many hours without success, consider changing to a different algorithm (-a). Unless you're required to use RSASHA256 for regulatory purposes, ECDSAP256SHA256 is a better choice.

  • The script might take a very long time, or it might not. Given the random nature of key generation, it's possible you'll strike gold on the first key. If you happen to have a spare c5d.18xlarge to run this on, let me know how that goes...

  • Less-greedy matches speed things up considerably. For example, if you like the number 5, DESIRED_KEYTAG=55555 could take considerably more time than settling for DESIRED_KEYTAG=555, which will stop on a key tag like 12555 or 35558.

Performing the rollover

With new keys in hand, the rollover itself was a straightforward process, even with an algorithm change involved.

In modern versions of BIND, zones configured with auto-dnssec maintain will automate all of the signing changes from the authoritative server's standpoint. Things may be more or less complex with other resolvers. Rolling to the new keys with BIND involved the following steps:

  1. Lower the TTLs on the zone, incrementing the serial and reloading BIND.

  2. Wait out at least one interval of the original TTL so cached results can expire.

  3. Run dnssec-dsfromkey to obtain a DS record from the new KSK.

  4. Enter the new DS record at the domain registrar.

  5. Place the new key file(s) in the configured key-directory so BIND sees them.

  6. Run dnssec-settime to set inactivation and deletion dates on the old key(s).

  7. Wait for the old key(s) deletion date to pass, then wait out at least one interval of the TTL.

  8. Use dig or delv to ensure public resolvers are only seeing RRSIG records signed with the new key(s).

  9. Remove the old DS record at the domain registrar.

  10. Delete the old key file(s) from disk.

  11. Restore the original TTLs to the zone, incrementing the serial and reloading BIND.

The result of this effort is that I now have some vanity DNSSEC key tags:

[parse@stemmons ~]$ # delv DNSKEY shaunc.com. +nocrypto +short
    256 3 13 [key id = 31337]  ; ZSK; alg = ECDSAP256SHA256 ; key id = 31337
    257 3 13 [key id = 1337]  ; KSK; alg = ECDSAP256SHA256 ; key id = 1337

This goofy little experiment probably wasted more electrons than it was worth, but it served as good practice in conducting a key rollover.


Card image from DNSViz



Recent articles

📰 Generating vanity DNSSEC key tags

📰 DDoS involving forged packets from 23.225.141.70

📰 Website integrity monitoring through version control

📰 SpamAssassin 3.4.2 fixes security problems, adds HashBL and phishing plugins

📰 Bug or turf war? ICQ via Pidgin now fails with "startOSCARSession: Request Timeout"

📰 🎂

📰 SFSQuery, a PHP class to query the StopForumSpam API and DNSBL

📰 Resolving portmaster error "pkg-static: automake-1.16.1 conflicts with automake-wrapper-20131203"

📰 Resolving LibreNMS error "RuntimeException: The only supported ciphers are AES-128-CBC and AES-256-CBC with the correct key lengths"

📰 1.1.1.1: Fast, but not so accurate (yet)

📰 autodiscover.xml as an Indicator of Attack

📰 Blocking Facebook's Tracking and Surveillance: A Comprehensive Approach

📰 Let's Encrypt Readies for Certificate Transparency with Embedded SCTs

📰 Evaluating DNSBL Effectiveness with Postfix Logs

📰 Resolving subversion error E145001: Node has unexpectedly changed kind

▲ Back to top | Permalink to this page