• chevron_right

      DNSSEC signing with an offline KSK

      pubsub.slavino.sk / jpmens.net · Wednesday, 21 September, 2022 - 22:00 · 5 minutes

    The level of complexity caused by KSK/ZSK split in DNSSEC isn’t necessary for most purposes; you can in fact just have one key for a zone and sign everything with it such. co.uk. does this , and I also make frequent use of Combined Signing Key (or Single Signing Key).

    However, the KSK/ZSK split has one advantage: it allows us to keep the KSK offline and only bring it out occasionally to sign the DNSKEY RRset. This key can be kept stable (i.e. it need to be changed frequently or at all) and thus the interaction with the parent (DS submission) be kept at a minimum.

    Jaromir Talir held a presentation about offline KSK with Knot DNS , and from the terminology he used in 2019 I made this diagram a few years ago to help me better understand the flow of keys.

    key flow in offline KSK signing

    The idea is that the KSK (depicted on the left) is managed completely offline. Only public keys are carried around – on floppy disks or USB keys, say, and as such there is an extremely low risk of the KSK being compromised.

    The ZSK and the zone proper are maintained on the right, online and/or on a hidden primary. Since the ZSK can easily be replaced there is little risk of compromise, and the zone data is public anyway.

    Once created, the ZSK (or ZSKs – plural) are copied to the KSK machine for signing. The KSK signer uses the KSK to sign the DNSKEY RRset and the resulting RRset and its signatures (RRSIG) are transported back to the zone signer on the right. This data is now public: the DNSKEY RRset contains the public keys for the zone.

    The zone is now signed (on the right) with the ZSK only, so this signs all of the RRsets in the zone, and as a last step we enrich the newly-signed zone with the public DNSKEY of the KSK and its signatures, and this zone (named example.com.final in the diagram) we then load and serve.

    The diagram shows “key requests” being passed left and right. These could be signed (PGP?) containers carrying public key material, but for our purposes simple files containing the public DNSKEY records suffice.

    In the example which follows, the offline KSK will be managed with tools from the ldns toolchain, and the zone signer with tools from BIND and optionally from ldns . Why? Just to introduce diversity.

    creating the keys

    We begin by preparing our environment. Everything in the directory left contains files which we will have on the offline KSK machine; conversely, the directory right contains files on our actual zone signer.

    % mkdir left right
    % touch left/KSK.data                       #this file will contain public data
    
    % cd right/
    right% dnssec-keygen -a13 example.com       #generate ZSK
    Generating key pair.
    Kexample.com.+013+54147
    
    right% ln -s Kexample.com.+013+54147.key ZSK.key
    

    We copy the public ZSK.key to the left . In the following script, I have to replace $INCLUDE.*$ by the actual public ZSK DNSKEY RR because ldns-read-zone and friends don’t understand $INCLUDE .

    % cd left/
    left% ldns-keygen -a13 -k example.com       #generate KSK
    Kexample.com.+013+11238
    
    left% cat example.com
    $TTL 3600
    @ SOA  unused.invalid. jp.invalid.  1 3H 1H 1W 1H
      NS   unused.invalid.
    
    ;$INCLUDE"../zone/ZSK.key";This is a ZONE-SIGNING key, keyid 54147, for example.com.
    example.com. IN DNSKEY 256 3 13 ah+p9L1ydOMAWsHTW9sLokRDrA1by6TV6ZPLKPDhkowEMAN7o36Vs1Bt db+obk6h22D548XWTWV6cWEkbNYHPQ==
    
    left% cat Kexample.com.+013+11238.ds
    example.com.	IN	DS	11238 13 2 2d0d834fe6aea4c80ec3bcbf5af753653c9d9ea6dc997ea86e90c2615edef19f
    

    Note the DS record which we will later submit to the parent. This is public data, so we can safely copy it to the right for further submission.

    On the left, the content of the zone doesn’t matter; I’ve used invalid. to underline the fact. We will now sign that zone with the KSK, and I set the signature validity to a date I’ll recognize in the final zone. The only records from this signed zone we are interested in are the DNSKEY and RRSIG over DNSKEY.

    left% ldns-signzone -e 20221224 -o example.com example.com Kexample.com.+013+11238
    
    #now grab the KSK DNSKEY record and its RRSIG
    left% ldns-read-zone example.com.signed |
    	awk '($4 =="DNSKEY"&&$5== 257)||($4=="RRSIG"&&$5=="DNSKEY"){ print }' | tee KSK.data
    example.com.	3600	IN	DNSKEY	257 3 13 cMW3t5/jWcESqrzNgNjksnfUZdS4TtqO1gOae0cBRxgopoT/FNIa5GATNQAg64TJw3tgECVOq1beXpbJGSjG7Q== ;{id = 11238 (ksk), size = 256b}
    example.com.	3600	IN	RRSIG	DNSKEY 13 2 3600 20221224000000 20220922073938 11238 example.com. 35J+toX0FyIyXRTNpamM6UVyivLFV1deUSWrJl+3DCVH2feolbDP45i/myLDnnywAS4NzQIZqjdkZQMTyVSxfg==
    
    left% wc -l KSK.data
           2 KSK.data
    

    The file KSK.data contains the public key and signature which we transfer (floppy disk, remember?) back to the right .

    signing the zone

    Back on the right we have the zone, the ZSK, and the public KSK in the file KSK.data , so we can now sign this:

    right% ./bsig.sh
    *** sign the zone;set SOA serial to epoch
    example.com.signed
    *** remove dsset file as it contains ZSK only
    *** replace RRSIG over DNSKEY created by ZSK with that created by KSK
    *** verify signed zone using ldns-verify-zone
    Zone is verified and complete
    *** verify signed zone using dnssec-verify
    Loading zone 'example.com' from file 'example.com.signed'
    Verifying the zone using the following algorithms: ECDSAP256SHA256.
    Zone fully signed:
    Algorithm: ECDSAP256SHA256: KSKs: 1 active, 0 stand-by, 0 revoked
                                ZSKs: 1 active, 0 stand-by, 0 revoked
    *** verify signed zone using validns
    records found:       17
    skipped dups:        0
    record sets found:   10
    unique names found:  3
    delegations found:   0
        nsec3 records:   0
    not authoritative names, not counting delegation points:
                         0
    validation errors:   0
    signatures verified: 8
    time taken:          0.003s
    

    The b in bsig.sh is for signing with the BIND utilities, and there’s an lsig.sh which uses ldns for signing.

    Both scripts work in a similar way: they first sign the zone using only our ZSK (BIND’s smart signing finds the key by itself, with ldns I have to specify it). Then they remove the RRSIG over DNSKEY which was created by the ZSK (we don’t need that; our DNSKEY RRset is signed by the KSK), and add the public DNSKEY of the KSK and its RRSIG, both obtained from left . Finally, we use three distinct tools to verify the validity of the zone.

    The signed zone file is the one we (re-)load on our (hidden) primary server.

    finally

    As the diagram above suggests, there’s no reason why you couldn’t add complexity security by adding a bunch of HSMs here and there.

    And if you don’t like using floppy disks to transport the public keys from right to left and back, but want to make life difficult for intruders, a serial cable and the likes of UUCP or Kermit might be employed. :-)


    Značky: #Network

    • wifi_tethering open_in_new

      This post is public

      jpmens.net /2022/09/22/dnssec-signing-with-an-offline-ksk/