|
libwebsockets
Lightweight C library for HTML5 websockets
|
lws-crypto-dnssec is a native utility provided by libwebsockets for handling DNSSEC cryptographic operations, allowing you to generate keys, create Delegation Signer (DS) records, and securely sign authoritative DNS zone files natively without relying on heavy external tools like BIND or NSD utilities.
It produces standard, RFC-compliant outputs: .key files (RFC 4034 DNSKEY format), .zone files containing canonical RRSIG and NSEC3 chains, and outer JSON Web Signatures (JWS) for deployment to the lws DHT.
To build this utility, you must enable the following CMake options when configuring libwebsockets:
You can enable these individually, or if your build script enables them recursively, ensure they are ultimately selected. Once configured, build using make.
Start by creating a standard, unsigned text DNS zone file for your domain. You do not need to manually add DNSKEY, NSEC3, NSEC3PARAM, or RRSIG records—the signing utility will automatically generate and inject these for you.
Create a file named mydomain.com.zone:
The zone must have exactly one $ORIGIN line, ahead of its records and naming the domain, and every record must be at or below it: that is what binds the zone to the domain whose keys sign it. The signer, the DHT publisher and auth-dns all refuse a zone with a second $ORIGIN, or with records outside its origin.
DNSSEC requires a pair of keys: a Key Signing Key (KSK) and a Zone Signing Key (ZSK).
1. Generate the Key Signing Key (KSK): The KSK signs the DNSKEY record itself. It is the root of trust for your zone.
This generates two files:
2. Generate the Zone Signing Key (ZSK): The ZSK signs all the other operational records in your zone (A, AAAA, MX, etc.).
This generates:
Note: You can specify other curves such as P-384 or P-521 using the --curve argument.
If you are migrating an existing domain from standard BIND or NSD setups, you can import your existing DNSSEC keys directly into the lws JWK format without generating new ones.
The importnsd command takes your domain and the file prefixes of your existing .private and .key files (usually named like Kmydomain.com.+013+12345).
The utility automatically parses the DNSKEY flags (256 for ZSK, 257 for KSK) to assign the correct roles, extracts the cryptographic parameters, and exports standard mydomain.com.ksk.private.jwk and mydomain.com.zsk.private.jwk files. It also generates a mydomain.com.dnssec.txt summarizing your DS records.
To establish the chain of trust, the parent zone (e.g., the .com registry) must publish a Delegation Signer (DS) record containing a cryptographic hash of your public KSK.
You can extract this DS digest from your public KSK using the dsfromkey command:
Output Example:
You will provide the Keytag (5167), Algorithm (13), Digest Type (2 for SHA-256), and the resulting hex Digest to your domain registrar.
(Alternatively, the signzone command in the next step will conveniently print out this exact DS information to the console during signing).
Now, you will take the unsigned zone file, process it with your keys, and generate both the DNSSEC-signed .zone file and an outer JWS wrapper.
It reads mydomain.com.zone and the keys mydomain.com.ksk.private.jwk and mydomain.com.zsk.private.jwk. --duration is how many hours the signatures are valid for, 144 (6 days) if it is not given. Every version of the zone you sign verifies until its signatures expire, and a DHT node that never held the zone may be offered any of them, so keep it short and sign again well before it runs out.
What happens during this step:
Outputs:
In code, lws_auth_dns_verify_zone() checks signed zone text against the keys you trust for it, given as the same JWK paths (only their public parts are used). It passes the zone only if the apex DNSKEY RRset publishes the given KSK (and ZSK, if given) and is signed by that KSK, and every other authoritative RRset, including the NSEC3 chain, has an RRSIG from a key in that DNSKEY RRset. Every RRSIG in the zone must verify, be from the zone apex and be inside its validity period (at verify_time, or now). So records spliced into the zone after it was signed, a zone re-signed with other keys, and expired signatures all fail.
An NS RRset at a name below the apex delegates that name to a child zone. As RFC 4035 2.2 requires, the signer leaves that NS RRset and the glue (A / AAAA records at or below the delegation, for names an NS record points to) unsigned, keeps the names below the delegation out of the NSEC3 chain, and signs a DS RRset at the delegation, which is the parent's own data. It refuses to sign a zone with anything else at or below a delegation (data the delegation occludes), or a DS anywhere else.
The verifier agrees, and only exempts a delegation the signed zone itself attests: the zone's NSEC3 record for the name must list NS (and not SOA), otherwise adding an unsigned NS RRset at any name would exempt everything there from being signed. Zones using NSEC3 opt-out for insecure delegations therefore do not verify. Glue is not the zone's data and is not protected by its signatures, for lws as for any validator. RSASHA256 (8), ECDSAP256SHA256 (13) and ECDSAP384SHA384 (14), the algorithms the signer uses, are verified. The outer JWS is checked separately, with the KSK.