tessl install tessl/golang-github-com-miekg--dns@1.1.1Complete DNS library for Go with full protocol control, DNSSEC support, and both client and server programming capabilities
Complete DNSSEC support including signing, validation, key generation, and all standard algorithms.
const (
RSAMD5 uint8 = 1 // RSA/MD5 (deprecated)
DH uint8 = 2 // Diffie-Hellman
DSA uint8 = 3 // DSA/SHA1
RSASHA1 uint8 = 5 // RSA/SHA-1
DSANSEC3SHA1 uint8 = 6 // DSA-NSEC3-SHA1
RSASHA1NSEC3SHA1 uint8 = 7 // RSASHA1-NSEC3-SHA1
RSASHA256 uint8 = 8 // RSA/SHA-256
RSASHA512 uint8 = 10 // RSA/SHA-512
ECCGOST uint8 = 12 // GOST R 34.10-2001
ECDSAP256SHA256 uint8 = 13 // ECDSA Curve P-256 with SHA-256
ECDSAP384SHA384 uint8 = 14 // ECDSA Curve P-384 with SHA-384
ED25519 uint8 = 15 // Ed25519
ED448 uint8 = 16 // Ed448
INDIRECT uint8 = 252 // Reserved for Indirect Keys
PRIVATEDNS uint8 = 253 // Private algorithm
PRIVATEOID uint8 = 254 // Private algorithm OID
)const (
SHA1 uint8 = 1 // SHA-1 (RFC 4034)
SHA256 uint8 = 2 // SHA-256 (RFC 4509)
GOST94 uint8 = 3 // GOST R 34.11-94 (RFC 5933)
SHA384 uint8 = 4 // SHA-384 (Experimental)
SHA512 uint8 = 5 // SHA-512 (Experimental)
)const (
SEP = 1 // Secure Entry Point
REVOKE = 1 << 7 // Key has been revoked
ZONE = 1 << 8 // Zone Key flag
)// AlgorithmToString maps algorithm IDs to names
var AlgorithmToString = map[uint8]string{
RSAMD5: "RSAMD5",
DH: "DH",
DSA: "DSA",
RSASHA1: "RSASHA1",
DSANSEC3SHA1: "DSA-NSEC3-SHA1",
RSASHA1NSEC3SHA1: "RSASHA1-NSEC3-SHA1",
RSASHA256: "RSASHA256",
RSASHA512: "RSASHA512",
ECCGOST: "ECC-GOST",
ECDSAP256SHA256: "ECDSAP256SHA256",
ECDSAP384SHA384: "ECDSAP384SHA384",
ED25519: "ED25519",
ED448: "ED448",
INDIRECT: "INDIRECT",
PRIVATEDNS: "PRIVATEDNS",
PRIVATEOID: "PRIVATEOID",
}
// AlgorithmToHash maps algorithms to crypto.Hash
var AlgorithmToHash = map[uint8]crypto.Hash{
RSAMD5: crypto.MD5,
DSA: crypto.SHA1,
RSASHA1: crypto.SHA1,
RSASHA1NSEC3SHA1: crypto.SHA1,
RSASHA256: crypto.SHA256,
ECDSAP256SHA256: crypto.SHA256,
ECDSAP384SHA384: crypto.SHA384,
RSASHA512: crypto.SHA512,
ED25519: 0, // ED25519 does its own hashing
}
// HashToString maps hash IDs to names
var HashToString = map[uint8]string{
SHA1: "SHA1",
SHA256: "SHA256",
GOST94: "GOST94",
SHA384: "SHA384",
SHA512: "SHA512",
}
// StringToAlgorithm maps names to algorithm IDs
var StringToAlgorithm = map[string]uint8{
"RSAMD5": RSAMD5,
"DH": DH,
"DSA": DSA,
"RSASHA1": RSASHA1,
"DSA-NSEC3-SHA1": DSANSEC3SHA1,
"RSASHA1-NSEC3-SHA1": RSASHA1NSEC3SHA1,
"RSASHA256": RSASHA256,
"RSASHA512": RSASHA512,
"ECC-GOST": ECCGOST,
"ECDSAP256SHA256": ECDSAP256SHA256,
"ECDSAP384SHA384": ECDSAP384SHA384,
"ED25519": ED25519,
"ED448": ED448,
"INDIRECT": INDIRECT,
"PRIVATEDNS": PRIVATEDNS,
"PRIVATEOID": PRIVATEOID,
}
// StringToHash maps names to hash IDs
var StringToHash = map[string]uint8{
"SHA1": SHA1,
"SHA256": SHA256,
"GOST94": GOST94,
"SHA384": SHA384,
"SHA512": SHA512,
}// KeyTag calculates the keytag (key ID) of DNSKEY
func (k *DNSKEY) KeyTag() uint16
// ToDS converts DNSKEY to DS record with specified hash
func (k *DNSKEY) ToDS(h uint8) *DS
// ToCDNSKEY converts DNSKEY to CDNSKEY record
func (k *DNSKEY) ToCDNSKEY() *CDNSKEY
// Generate generates a new private key for the DNSKEY
// bits: key size in bits (e.g., 2048 for RSA, 256 for ECDSA P-256)
// Returns private key suitable for signing
func (k *DNSKEY) Generate(bits int) (crypto.PrivateKey, error)
// NewPrivateKey parses private key from BIND-style string format
// s: private key string
// Returns parsed private key
func (k *DNSKEY) NewPrivateKey(s string) (crypto.PrivateKey, error)
// ReadPrivateKey reads BIND-style private key from reader
// q: reader containing private key
// file: filename for error reporting
// Returns parsed private key
func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (crypto.PrivateKey, error)
// PrivateKeyString converts private key to BIND-style string format
// p: private key to convert
// Returns BIND-style private key string
func (k *DNSKEY) PrivateKeyString(p crypto.PrivateKey) string// ToCDS converts DS to CDS record
func (ds *DS) ToCDS() *CDS// GeneratePrivateKey generates a DNSSEC private key
// algorithm: encryption algorithm (RSASHA256, ECDSAP256SHA256, ED25519, etc.)
// bits: key size in bits (e.g., 2048 for RSA, 256 for ECDSA P-256)
func GeneratePrivateKey(algorithm uint8, bits int) (crypto.PrivateKey, error)// Sign signs an RRSet with the provided private key
// The RRSIG must have Inception, Expiration, KeyTag, SignerName, and Algorithm set
// If OrigTtl is zero, it uses the TTL from the RRset
func (rr *RRSIG) Sign(k crypto.Signer, rrset []RR) error
// Verify verifies the signature on an RRSet
func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error
// ValidityPeriod checks if signature is valid at time t
func (rr *RRSIG) ValidityPeriod(t time.Time) bool// Sign creates SIG(0) signature for message
func (rr *SIG) Sign(k crypto.Signer, m *Msg) ([]byte, error)
// Verify verifies SIG(0) signature on message
func (rr *SIG) Verify(k *KEY, msg []byte) error// Cover checks if NSEC3 record covers the name
func (rr *NSEC3) Cover(name string) bool
// Match checks if NSEC3 record matches the name
func (rr *NSEC3) Match(name string) bool
// HashName hashes a domain name for NSEC3
// name: domain name to hash
// hash: hash algorithm
// iterations: number of iterations
// salt: hex encoded salt
func HashName(name string, hash uint8, iterations uint16, salt string) string// Generate RSA key
rsaKey, err := dns.GeneratePrivateKey(dns.RSASHA256, 2048)
if err != nil {
log.Fatal(err)
}
// Generate ECDSA P-256 key
ecdsaKey, err := dns.GeneratePrivateKey(dns.ECDSAP256SHA256, 256)
if err != nil {
log.Fatal(err)
}
// Generate Ed25519 key
ed25519Key, err := dns.GeneratePrivateKey(dns.ED25519, 256)
if err != nil {
log.Fatal(err)
}import (
"crypto/rsa"
"encoding/base64"
)
// Assuming you have a private key
privKey := rsaKey.(*rsa.PrivateKey)
pubKeyBytes, _ := pubKeyToBytes(privKey.PublicKey)
dnskey := &dns.DNSKEY{
Hdr: dns.RR_Header{
Name: "example.com.",
Rrtype: dns.TypeDNSKEY,
Class: dns.ClassINET,
Ttl: 3600,
},
Flags: dns.ZONE | dns.SEP, // Zone key with SEP flag (KSK)
Protocol: 3,
Algorithm: dns.RSASHA256,
PublicKey: base64.StdEncoding.EncodeToString(pubKeyBytes),
}
// Calculate key tag
keyTag := dnskey.KeyTag()
fmt.Printf("Key tag: %d\n", keyTag)// Create DS record with SHA-256
ds := dnskey.ToDS(dns.SHA256)
fmt.Printf("DS record: %s\n", ds.String())
// Output: example.com. 3600 IN DS 12345 8 2 ABC123...// Create RRset to sign
rrset := []dns.RR{
&dns.A{
Hdr: dns.RR_Header{
Name: "example.com.",
Rrtype: dns.TypeA,
Class: dns.ClassINET,
Ttl: 3600,
},
A: net.ParseIP("192.0.2.1"),
},
&dns.A{
Hdr: dns.RR_Header{
Name: "example.com.",
Rrtype: dns.TypeA,
Class: dns.ClassINET,
Ttl: 3600,
},
A: net.ParseIP("192.0.2.2"),
},
}
// Create RRSIG
now := time.Now()
rrsig := &dns.RRSIG{
Hdr: dns.RR_Header{
Name: "example.com.",
Rrtype: dns.TypeRRSIG,
Class: dns.ClassINET,
Ttl: 3600,
},
TypeCovered: dns.TypeA,
Algorithm: dns.RSASHA256,
Labels: 2,
OrigTtl: 3600,
Expiration: uint32(now.Add(30 * 24 * time.Hour).Unix()),
Inception: uint32(now.Unix()),
KeyTag: dnskey.KeyTag(),
SignerName: "example.com.",
}
// Sign the RRset
err := rrsig.Sign(privKey.(crypto.Signer), rrset)
if err != nil {
log.Fatal(err)
}
fmt.Printf("RRSIG: %s\n", rrsig.String())// Verify RRSIG
err := rrsig.Verify(dnskey, rrset)
if err != nil {
log.Printf("Signature verification failed: %v", err)
} else {
log.Println("Signature valid")
}
// Check validity period
if rrsig.ValidityPeriod(time.Now()) {
log.Println("Signature is currently valid")
} else {
log.Println("Signature expired or not yet valid")
}nsec3 := &dns.NSEC3{
Hdr: dns.RR_Header{
Name: "abc123.example.com.",
Rrtype: dns.TypeNSEC3,
Class: dns.ClassINET,
Ttl: 3600,
},
Hash: dns.SHA1,
Flags: 0,
Iterations: 10,
Salt: "AABBCCDD",
NextDomain: "def456",
TypeBitMap: []uint16{dns.TypeA, dns.TypeRRSIG},
}
// Check if name is covered
if nsec3.Cover("www.example.com.") {
log.Println("Name is covered by NSEC3")
}
// Check if name matches
if nsec3.Match("www.example.com.") {
log.Println("Name matches NSEC3")
}// Hash a name for NSEC3
salt := "AABBCCDD"
iterations := uint16(10)
hash := dns.HashName("www.example.com.", dns.SHA1, iterations, salt)
fmt.Printf("Hashed name: %s\n", hash)nsec := &dns.NSEC{
Hdr: dns.RR_Header{
Name: "example.com.",
Rrtype: dns.TypeNSEC,
Class: dns.ClassINET,
Ttl: 3600,
},
NextDomain: "www.example.com.",
TypeBitMap: []uint16{
dns.TypeA,
dns.TypeNS,
dns.TypeSOA,
dns.TypeRRSIG,
dns.TypeNSEC,
dns.TypeDNSKEY,
},
}// Create SIG(0) for message authentication
m := new(dns.Msg)
m.SetQuestion(dns.Fqdn("example.com"), dns.TypeA)
sig := &dns.SIG{
RRSIG: dns.RRSIG{
Hdr: dns.RR_Header{
Name: ".",
Rrtype: dns.TypeSIG,
Class: dns.ClassANY,
Ttl: 0,
},
TypeCovered: 0,
Algorithm: dns.RSASHA256,
Labels: 0,
OrigTtl: 0,
Expiration: uint32(time.Now().Add(5 * time.Minute).Unix()),
Inception: uint32(time.Now().Unix()),
KeyTag: key.KeyTag(),
SignerName: "example.com.",
},
}
// Sign message
signedMsg, err := sig.Sign(privKey.(crypto.Signer), m)
if err != nil {
log.Fatal(err)
}// Zone signing workflow
zone := "example.com."
zsk, _ := dns.GeneratePrivateKey(dns.RSASHA256, 2048) // Zone Signing Key
ksk, _ := dns.GeneratePrivateKey(dns.RSASHA256, 4096) // Key Signing Key
// Create DNSKEY records
zskDNSKEY := createDNSKEY(zone, zsk, dns.ZONE)
kskDNSKEY := createDNSKEY(zone, ksk, dns.ZONE|dns.SEP)
// Create DS from KSK
ds := kskDNSKEY.ToDS(dns.SHA256)
// Sign DNSKEY RRset with KSK
dnskeyRRset := []dns.RR{zskDNSKEY, kskDNSKEY}
dnskeyRRSIG := createRRSIG(zone, dns.TypeDNSKEY, kskDNSKEY.KeyTag())
err := dnskeyRRSIG.Sign(ksk.(crypto.Signer), dnskeyRRset)
// Sign other RRsets with ZSK
aRRset := []dns.RR{/* ... */}
aRRSIG := createRRSIG(zone, dns.TypeA, zskDNSKEY.KeyTag())
err = aRRSIG.Sign(zsk.(crypto.Signer), aRRset)// KSK rollover: double signature method
oldKSK, _ := loadKey("Kexample.com.+008+12345")
newKSK, _ := dns.GeneratePrivateKey(dns.RSASHA256, 4096)
oldKSKDNSKEY := createDNSKEY(zone, oldKSK, dns.ZONE|dns.SEP)
newKSKDNSKEY := createDNSKEY(zone, newKSK, dns.ZONE|dns.SEP)
// Publish both keys
dnskeyRRset := []dns.RR{zskDNSKEY, oldKSKDNSKEY, newKSKDNSKEY}
// Sign with both KSKs
oldRRSIG := createRRSIG(zone, dns.TypeDNSKEY, oldKSKDNSKEY.KeyTag())
oldRRSIG.Sign(oldKSK.(crypto.Signer), dnskeyRRset)
newRRSIG := createRRSIG(zone, dns.TypeDNSKEY, newKSKDNSKEY.KeyTag())
newRRSIG.Sign(newKSK.(crypto.Signer), dnskeyRRset)
// Publish both DS records at parent
oldDS := oldKSKDNSKEY.ToDS(dns.SHA256)
newDS := newKSKDNSKEY.ToDS(dns.SHA256)// TimeToString converts Unix timestamp to DNSSEC time format (YYYYMMDDHHmmSS)
func TimeToString(t uint32) string
// StringToTime converts DNSSEC time format to Unix timestamp
func StringToTime(s string) (uint32, error)// Convert current time to DNSSEC format
now := uint32(time.Now().Unix())
timeStr := dns.TimeToString(now)
fmt.Printf("DNSSEC time: %s\n", timeStr) // e.g., "20240115120000"
// Parse DNSSEC time
timestamp, err := dns.StringToTime("20240115120000")
if err != nil {
log.Fatal(err)
}var (
ErrAlg error // Bad algorithm
ErrKey error // Bad key
ErrKeyAlg error // Bad key algorithm
ErrKeySize error // Bad key size
ErrNoSig error // No signature found
ErrPrivKey error // Bad private key
ErrSig error // Bad signature
)