You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
635 lines
15 KiB
635 lines
15 KiB
9 years ago
|
package dns
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"crypto"
|
||
|
"crypto/dsa"
|
||
|
"crypto/ecdsa"
|
||
|
"crypto/elliptic"
|
||
|
"crypto/md5"
|
||
|
"crypto/rsa"
|
||
|
"crypto/sha1"
|
||
|
"crypto/sha256"
|
||
|
"crypto/sha512"
|
||
|
"encoding/hex"
|
||
|
"hash"
|
||
|
"io"
|
||
|
"math/big"
|
||
|
"sort"
|
||
|
"strings"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
// DNSSEC encryption algorithm codes.
|
||
|
const (
|
||
|
_ uint8 = iota
|
||
|
RSAMD5
|
||
|
DH
|
||
|
DSA
|
||
|
_ // Skip 4, RFC 6725, section 2.1
|
||
|
RSASHA1
|
||
|
DSANSEC3SHA1
|
||
|
RSASHA1NSEC3SHA1
|
||
|
RSASHA256
|
||
|
_ // Skip 9, RFC 6725, section 2.1
|
||
|
RSASHA512
|
||
|
_ // Skip 11, RFC 6725, section 2.1
|
||
|
ECCGOST
|
||
|
ECDSAP256SHA256
|
||
|
ECDSAP384SHA384
|
||
|
INDIRECT uint8 = 252
|
||
|
PRIVATEDNS uint8 = 253 // Private (experimental keys)
|
||
|
PRIVATEOID uint8 = 254
|
||
|
)
|
||
|
|
||
|
// DNSSEC hashing algorithm codes.
|
||
|
const (
|
||
|
_ uint8 = iota
|
||
|
SHA1 // RFC 4034
|
||
|
SHA256 // RFC 4509
|
||
|
GOST94 // RFC 5933
|
||
|
SHA384 // Experimental
|
||
|
SHA512 // Experimental
|
||
|
)
|
||
|
|
||
|
// DNSKEY flag values.
|
||
|
const (
|
||
|
SEP = 1
|
||
|
REVOKE = 1 << 7
|
||
|
ZONE = 1 << 8
|
||
|
)
|
||
|
|
||
|
// The RRSIG needs to be converted to wireformat with some of
|
||
|
// the rdata (the signature) missing. Use this struct to easy
|
||
|
// the conversion (and re-use the pack/unpack functions).
|
||
|
type rrsigWireFmt struct {
|
||
|
TypeCovered uint16
|
||
|
Algorithm uint8
|
||
|
Labels uint8
|
||
|
OrigTtl uint32
|
||
|
Expiration uint32
|
||
|
Inception uint32
|
||
|
KeyTag uint16
|
||
|
SignerName string `dns:"domain-name"`
|
||
|
/* No Signature */
|
||
|
}
|
||
|
|
||
|
// Used for converting DNSKEY's rdata to wirefmt.
|
||
|
type dnskeyWireFmt struct {
|
||
|
Flags uint16
|
||
|
Protocol uint8
|
||
|
Algorithm uint8
|
||
|
PublicKey string `dns:"base64"`
|
||
|
/* Nothing is left out */
|
||
|
}
|
||
|
|
||
|
func divRoundUp(a, b int) int {
|
||
|
return (a + b - 1) / b
|
||
|
}
|
||
|
|
||
|
// KeyTag calculates the keytag (or key-id) of the DNSKEY.
|
||
|
func (k *DNSKEY) KeyTag() uint16 {
|
||
|
if k == nil {
|
||
|
return 0
|
||
|
}
|
||
|
var keytag int
|
||
|
switch k.Algorithm {
|
||
|
case RSAMD5:
|
||
|
// Look at the bottom two bytes of the modules, which the last
|
||
|
// item in the pubkey. We could do this faster by looking directly
|
||
|
// at the base64 values. But I'm lazy.
|
||
|
modulus, _ := fromBase64([]byte(k.PublicKey))
|
||
|
if len(modulus) > 1 {
|
||
|
x, _ := unpackUint16(modulus, len(modulus)-2)
|
||
|
keytag = int(x)
|
||
|
}
|
||
|
default:
|
||
|
keywire := new(dnskeyWireFmt)
|
||
|
keywire.Flags = k.Flags
|
||
|
keywire.Protocol = k.Protocol
|
||
|
keywire.Algorithm = k.Algorithm
|
||
|
keywire.PublicKey = k.PublicKey
|
||
|
wire := make([]byte, DefaultMsgSize)
|
||
|
n, err := PackStruct(keywire, wire, 0)
|
||
|
if err != nil {
|
||
|
return 0
|
||
|
}
|
||
|
wire = wire[:n]
|
||
|
for i, v := range wire {
|
||
|
if i&1 != 0 {
|
||
|
keytag += int(v) // must be larger than uint32
|
||
|
} else {
|
||
|
keytag += int(v) << 8
|
||
|
}
|
||
|
}
|
||
|
keytag += (keytag >> 16) & 0xFFFF
|
||
|
keytag &= 0xFFFF
|
||
|
}
|
||
|
return uint16(keytag)
|
||
|
}
|
||
|
|
||
|
// ToDS converts a DNSKEY record to a DS record.
|
||
|
func (k *DNSKEY) ToDS(h uint8) *DS {
|
||
|
if k == nil {
|
||
|
return nil
|
||
|
}
|
||
|
ds := new(DS)
|
||
|
ds.Hdr.Name = k.Hdr.Name
|
||
|
ds.Hdr.Class = k.Hdr.Class
|
||
|
ds.Hdr.Rrtype = TypeDS
|
||
|
ds.Hdr.Ttl = k.Hdr.Ttl
|
||
|
ds.Algorithm = k.Algorithm
|
||
|
ds.DigestType = h
|
||
|
ds.KeyTag = k.KeyTag()
|
||
|
|
||
|
keywire := new(dnskeyWireFmt)
|
||
|
keywire.Flags = k.Flags
|
||
|
keywire.Protocol = k.Protocol
|
||
|
keywire.Algorithm = k.Algorithm
|
||
|
keywire.PublicKey = k.PublicKey
|
||
|
wire := make([]byte, DefaultMsgSize)
|
||
|
n, err := PackStruct(keywire, wire, 0)
|
||
|
if err != nil {
|
||
|
return nil
|
||
|
}
|
||
|
wire = wire[:n]
|
||
|
|
||
|
owner := make([]byte, 255)
|
||
|
off, err1 := PackDomainName(strings.ToLower(k.Hdr.Name), owner, 0, nil, false)
|
||
|
if err1 != nil {
|
||
|
return nil
|
||
|
}
|
||
|
owner = owner[:off]
|
||
|
// RFC4034:
|
||
|
// digest = digest_algorithm( DNSKEY owner name | DNSKEY RDATA);
|
||
|
// "|" denotes concatenation
|
||
|
// DNSKEY RDATA = Flags | Protocol | Algorithm | Public Key.
|
||
|
|
||
|
// digest buffer
|
||
|
digest := append(owner, wire...) // another copy
|
||
|
|
||
|
switch h {
|
||
|
case SHA1:
|
||
|
s := sha1.New()
|
||
|
io.WriteString(s, string(digest))
|
||
|
ds.Digest = hex.EncodeToString(s.Sum(nil))
|
||
|
case SHA256:
|
||
|
s := sha256.New()
|
||
|
io.WriteString(s, string(digest))
|
||
|
ds.Digest = hex.EncodeToString(s.Sum(nil))
|
||
|
case SHA384:
|
||
|
s := sha512.New384()
|
||
|
io.WriteString(s, string(digest))
|
||
|
ds.Digest = hex.EncodeToString(s.Sum(nil))
|
||
|
case GOST94:
|
||
|
/* I have no clue */
|
||
|
default:
|
||
|
return nil
|
||
|
}
|
||
|
return ds
|
||
|
}
|
||
|
|
||
|
// ToCDNSKEY converts a DNSKEY record to a CDNSKEY record.
|
||
|
func (k *DNSKEY) ToCDNSKEY() *CDNSKEY {
|
||
|
c := &CDNSKEY{DNSKEY: *k}
|
||
|
c.Hdr = *k.Hdr.copyHeader()
|
||
|
c.Hdr.Rrtype = TypeCDNSKEY
|
||
|
return c
|
||
|
}
|
||
|
|
||
|
// ToCDS converts a DS record to a CDS record.
|
||
|
func (d *DS) ToCDS() *CDS {
|
||
|
c := &CDS{DS: *d}
|
||
|
c.Hdr = *d.Hdr.copyHeader()
|
||
|
c.Hdr.Rrtype = TypeCDS
|
||
|
return c
|
||
|
}
|
||
|
|
||
|
// Sign signs an RRSet. The signature needs to be filled in with
|
||
|
// the values: Inception, Expiration, KeyTag, SignerName and Algorithm.
|
||
|
// The rest is copied from the RRset. Sign returns true when the signing went OK,
|
||
|
// otherwise false.
|
||
|
// There is no check if RRSet is a proper (RFC 2181) RRSet.
|
||
|
// If OrigTTL is non zero, it is used as-is, otherwise the TTL of the RRset
|
||
|
// is used as the OrigTTL.
|
||
|
func (rr *RRSIG) Sign(k PrivateKey, rrset []RR) error {
|
||
|
if k == nil {
|
||
|
return ErrPrivKey
|
||
|
}
|
||
|
// s.Inception and s.Expiration may be 0 (rollover etc.), the rest must be set
|
||
|
if rr.KeyTag == 0 || len(rr.SignerName) == 0 || rr.Algorithm == 0 {
|
||
|
return ErrKey
|
||
|
}
|
||
|
|
||
|
rr.Hdr.Rrtype = TypeRRSIG
|
||
|
rr.Hdr.Name = rrset[0].Header().Name
|
||
|
rr.Hdr.Class = rrset[0].Header().Class
|
||
|
if rr.OrigTtl == 0 { // If set don't override
|
||
|
rr.OrigTtl = rrset[0].Header().Ttl
|
||
|
}
|
||
|
rr.TypeCovered = rrset[0].Header().Rrtype
|
||
|
rr.Labels = uint8(CountLabel(rrset[0].Header().Name))
|
||
|
|
||
|
if strings.HasPrefix(rrset[0].Header().Name, "*") {
|
||
|
rr.Labels-- // wildcard, remove from label count
|
||
|
}
|
||
|
|
||
|
sigwire := new(rrsigWireFmt)
|
||
|
sigwire.TypeCovered = rr.TypeCovered
|
||
|
sigwire.Algorithm = rr.Algorithm
|
||
|
sigwire.Labels = rr.Labels
|
||
|
sigwire.OrigTtl = rr.OrigTtl
|
||
|
sigwire.Expiration = rr.Expiration
|
||
|
sigwire.Inception = rr.Inception
|
||
|
sigwire.KeyTag = rr.KeyTag
|
||
|
// For signing, lowercase this name
|
||
|
sigwire.SignerName = strings.ToLower(rr.SignerName)
|
||
|
|
||
|
// Create the desired binary blob
|
||
|
signdata := make([]byte, DefaultMsgSize)
|
||
|
n, err := PackStruct(sigwire, signdata, 0)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
signdata = signdata[:n]
|
||
|
wire, err := rawSignatureData(rrset, rr)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
signdata = append(signdata, wire...)
|
||
|
|
||
|
var h hash.Hash
|
||
|
switch rr.Algorithm {
|
||
|
case DSA, DSANSEC3SHA1:
|
||
|
// TODO: this seems bugged, will panic
|
||
|
case RSASHA1, RSASHA1NSEC3SHA1:
|
||
|
h = sha1.New()
|
||
|
case RSASHA256, ECDSAP256SHA256:
|
||
|
h = sha256.New()
|
||
|
case ECDSAP384SHA384:
|
||
|
h = sha512.New384()
|
||
|
case RSASHA512:
|
||
|
h = sha512.New()
|
||
|
case RSAMD5:
|
||
|
fallthrough // Deprecated in RFC 6725
|
||
|
default:
|
||
|
return ErrAlg
|
||
|
}
|
||
|
|
||
|
_, err = h.Write(signdata)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
sighash := h.Sum(nil)
|
||
|
|
||
|
signature, err := k.Sign(sighash, rr.Algorithm)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
rr.Signature = toBase64(signature)
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// Verify validates an RRSet with the signature and key. This is only the
|
||
|
// cryptographic test, the signature validity period must be checked separately.
|
||
|
// This function copies the rdata of some RRs (to lowercase domain names) for the validation to work.
|
||
|
func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
|
||
|
// First the easy checks
|
||
|
if len(rrset) == 0 {
|
||
|
return ErrRRset
|
||
|
}
|
||
|
if rr.KeyTag != k.KeyTag() {
|
||
|
return ErrKey
|
||
|
}
|
||
|
if rr.Hdr.Class != k.Hdr.Class {
|
||
|
return ErrKey
|
||
|
}
|
||
|
if rr.Algorithm != k.Algorithm {
|
||
|
return ErrKey
|
||
|
}
|
||
|
if strings.ToLower(rr.SignerName) != strings.ToLower(k.Hdr.Name) {
|
||
|
return ErrKey
|
||
|
}
|
||
|
if k.Protocol != 3 {
|
||
|
return ErrKey
|
||
|
}
|
||
|
for _, r := range rrset {
|
||
|
if r.Header().Class != rr.Hdr.Class {
|
||
|
return ErrRRset
|
||
|
}
|
||
|
if r.Header().Rrtype != rr.TypeCovered {
|
||
|
return ErrRRset
|
||
|
}
|
||
|
}
|
||
|
// RFC 4035 5.3.2. Reconstructing the Signed Data
|
||
|
// Copy the sig, except the rrsig data
|
||
|
sigwire := new(rrsigWireFmt)
|
||
|
sigwire.TypeCovered = rr.TypeCovered
|
||
|
sigwire.Algorithm = rr.Algorithm
|
||
|
sigwire.Labels = rr.Labels
|
||
|
sigwire.OrigTtl = rr.OrigTtl
|
||
|
sigwire.Expiration = rr.Expiration
|
||
|
sigwire.Inception = rr.Inception
|
||
|
sigwire.KeyTag = rr.KeyTag
|
||
|
sigwire.SignerName = strings.ToLower(rr.SignerName)
|
||
|
// Create the desired binary blob
|
||
|
signeddata := make([]byte, DefaultMsgSize)
|
||
|
n, err := PackStruct(sigwire, signeddata, 0)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
signeddata = signeddata[:n]
|
||
|
wire, err := rawSignatureData(rrset, rr)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
signeddata = append(signeddata, wire...)
|
||
|
|
||
|
sigbuf := rr.sigBuf() // Get the binary signature data
|
||
|
if rr.Algorithm == PRIVATEDNS { // PRIVATEOID
|
||
|
// TODO(mg)
|
||
|
// remove the domain name and assume its our
|
||
|
}
|
||
|
|
||
|
switch rr.Algorithm {
|
||
|
case RSASHA1, RSASHA1NSEC3SHA1, RSASHA256, RSASHA512, RSAMD5:
|
||
|
// TODO(mg): this can be done quicker, ie. cache the pubkey data somewhere??
|
||
|
pubkey := k.publicKeyRSA() // Get the key
|
||
|
if pubkey == nil {
|
||
|
return ErrKey
|
||
|
}
|
||
|
// Setup the hash as defined for this alg.
|
||
|
var h hash.Hash
|
||
|
var ch crypto.Hash
|
||
|
switch rr.Algorithm {
|
||
|
case RSAMD5:
|
||
|
h = md5.New()
|
||
|
ch = crypto.MD5
|
||
|
case RSASHA1, RSASHA1NSEC3SHA1:
|
||
|
h = sha1.New()
|
||
|
ch = crypto.SHA1
|
||
|
case RSASHA256:
|
||
|
h = sha256.New()
|
||
|
ch = crypto.SHA256
|
||
|
case RSASHA512:
|
||
|
h = sha512.New()
|
||
|
ch = crypto.SHA512
|
||
|
}
|
||
|
io.WriteString(h, string(signeddata))
|
||
|
sighash := h.Sum(nil)
|
||
|
return rsa.VerifyPKCS1v15(pubkey, ch, sighash, sigbuf)
|
||
|
case ECDSAP256SHA256, ECDSAP384SHA384:
|
||
|
pubkey := k.publicKeyECDSA()
|
||
|
if pubkey == nil {
|
||
|
return ErrKey
|
||
|
}
|
||
|
var h hash.Hash
|
||
|
switch rr.Algorithm {
|
||
|
case ECDSAP256SHA256:
|
||
|
h = sha256.New()
|
||
|
case ECDSAP384SHA384:
|
||
|
h = sha512.New384()
|
||
|
}
|
||
|
io.WriteString(h, string(signeddata))
|
||
|
sighash := h.Sum(nil)
|
||
|
// Split sigbuf into the r and s coordinates
|
||
|
r := big.NewInt(0)
|
||
|
r.SetBytes(sigbuf[:len(sigbuf)/2])
|
||
|
s := big.NewInt(0)
|
||
|
s.SetBytes(sigbuf[len(sigbuf)/2:])
|
||
|
if ecdsa.Verify(pubkey, sighash, r, s) {
|
||
|
return nil
|
||
|
}
|
||
|
return ErrSig
|
||
|
}
|
||
|
// Unknown alg
|
||
|
return ErrAlg
|
||
|
}
|
||
|
|
||
|
// ValidityPeriod uses RFC1982 serial arithmetic to calculate
|
||
|
// if a signature period is valid. If t is the zero time, the
|
||
|
// current time is taken other t is.
|
||
|
func (rr *RRSIG) ValidityPeriod(t time.Time) bool {
|
||
|
var utc int64
|
||
|
if t.IsZero() {
|
||
|
utc = time.Now().UTC().Unix()
|
||
|
} else {
|
||
|
utc = t.UTC().Unix()
|
||
|
}
|
||
|
modi := (int64(rr.Inception) - utc) / year68
|
||
|
mode := (int64(rr.Expiration) - utc) / year68
|
||
|
ti := int64(rr.Inception) + (modi * year68)
|
||
|
te := int64(rr.Expiration) + (mode * year68)
|
||
|
return ti <= utc && utc <= te
|
||
|
}
|
||
|
|
||
|
// Return the signatures base64 encodedig sigdata as a byte slice.
|
||
|
func (rr *RRSIG) sigBuf() []byte {
|
||
|
sigbuf, err := fromBase64([]byte(rr.Signature))
|
||
|
if err != nil {
|
||
|
return nil
|
||
|
}
|
||
|
return sigbuf
|
||
|
}
|
||
|
|
||
|
// publicKeyRSA returns the RSA public key from a DNSKEY record.
|
||
|
func (k *DNSKEY) publicKeyRSA() *rsa.PublicKey {
|
||
|
keybuf, err := fromBase64([]byte(k.PublicKey))
|
||
|
if err != nil {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// RFC 2537/3110, section 2. RSA Public KEY Resource Records
|
||
|
// Length is in the 0th byte, unless its zero, then it
|
||
|
// it in bytes 1 and 2 and its a 16 bit number
|
||
|
explen := uint16(keybuf[0])
|
||
|
keyoff := 1
|
||
|
if explen == 0 {
|
||
|
explen = uint16(keybuf[1])<<8 | uint16(keybuf[2])
|
||
|
keyoff = 3
|
||
|
}
|
||
|
pubkey := new(rsa.PublicKey)
|
||
|
|
||
|
pubkey.N = big.NewInt(0)
|
||
|
shift := uint64((explen - 1) * 8)
|
||
|
expo := uint64(0)
|
||
|
for i := int(explen - 1); i > 0; i-- {
|
||
|
expo += uint64(keybuf[keyoff+i]) << shift
|
||
|
shift -= 8
|
||
|
}
|
||
|
// Remainder
|
||
|
expo += uint64(keybuf[keyoff])
|
||
|
if expo > 2<<31 {
|
||
|
// Larger expo than supported.
|
||
|
// println("dns: F5 primes (or larger) are not supported")
|
||
|
return nil
|
||
|
}
|
||
|
pubkey.E = int(expo)
|
||
|
|
||
|
pubkey.N.SetBytes(keybuf[keyoff+int(explen):])
|
||
|
return pubkey
|
||
|
}
|
||
|
|
||
|
// publicKeyECDSA returns the Curve public key from the DNSKEY record.
|
||
|
func (k *DNSKEY) publicKeyECDSA() *ecdsa.PublicKey {
|
||
|
keybuf, err := fromBase64([]byte(k.PublicKey))
|
||
|
if err != nil {
|
||
|
return nil
|
||
|
}
|
||
|
pubkey := new(ecdsa.PublicKey)
|
||
|
switch k.Algorithm {
|
||
|
case ECDSAP256SHA256:
|
||
|
pubkey.Curve = elliptic.P256()
|
||
|
if len(keybuf) != 64 {
|
||
|
// wrongly encoded key
|
||
|
return nil
|
||
|
}
|
||
|
case ECDSAP384SHA384:
|
||
|
pubkey.Curve = elliptic.P384()
|
||
|
if len(keybuf) != 96 {
|
||
|
// Wrongly encoded key
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
pubkey.X = big.NewInt(0)
|
||
|
pubkey.X.SetBytes(keybuf[:len(keybuf)/2])
|
||
|
pubkey.Y = big.NewInt(0)
|
||
|
pubkey.Y.SetBytes(keybuf[len(keybuf)/2:])
|
||
|
return pubkey
|
||
|
}
|
||
|
|
||
|
func (k *DNSKEY) publicKeyDSA() *dsa.PublicKey {
|
||
|
keybuf, err := fromBase64([]byte(k.PublicKey))
|
||
|
if err != nil {
|
||
|
return nil
|
||
|
}
|
||
|
if len(keybuf) < 22 {
|
||
|
return nil
|
||
|
}
|
||
|
t, keybuf := int(keybuf[0]), keybuf[1:]
|
||
|
size := 64 + t*8
|
||
|
q, keybuf := keybuf[:20], keybuf[20:]
|
||
|
if len(keybuf) != 3*size {
|
||
|
return nil
|
||
|
}
|
||
|
p, keybuf := keybuf[:size], keybuf[size:]
|
||
|
g, y := keybuf[:size], keybuf[size:]
|
||
|
pubkey := new(dsa.PublicKey)
|
||
|
pubkey.Parameters.Q = big.NewInt(0).SetBytes(q)
|
||
|
pubkey.Parameters.P = big.NewInt(0).SetBytes(p)
|
||
|
pubkey.Parameters.G = big.NewInt(0).SetBytes(g)
|
||
|
pubkey.Y = big.NewInt(0).SetBytes(y)
|
||
|
return pubkey
|
||
|
}
|
||
|
|
||
|
type wireSlice [][]byte
|
||
|
|
||
|
func (p wireSlice) Len() int { return len(p) }
|
||
|
func (p wireSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
|
||
|
func (p wireSlice) Less(i, j int) bool {
|
||
|
_, ioff, _ := UnpackDomainName(p[i], 0)
|
||
|
_, joff, _ := UnpackDomainName(p[j], 0)
|
||
|
return bytes.Compare(p[i][ioff+10:], p[j][joff+10:]) < 0
|
||
|
}
|
||
|
|
||
|
// Return the raw signature data.
|
||
|
func rawSignatureData(rrset []RR, s *RRSIG) (buf []byte, err error) {
|
||
|
wires := make(wireSlice, len(rrset))
|
||
|
for i, r := range rrset {
|
||
|
r1 := r.copy()
|
||
|
r1.Header().Ttl = s.OrigTtl
|
||
|
labels := SplitDomainName(r1.Header().Name)
|
||
|
// 6.2. Canonical RR Form. (4) - wildcards
|
||
|
if len(labels) > int(s.Labels) {
|
||
|
// Wildcard
|
||
|
r1.Header().Name = "*." + strings.Join(labels[len(labels)-int(s.Labels):], ".") + "."
|
||
|
}
|
||
|
// RFC 4034: 6.2. Canonical RR Form. (2) - domain name to lowercase
|
||
|
r1.Header().Name = strings.ToLower(r1.Header().Name)
|
||
|
// 6.2. Canonical RR Form. (3) - domain rdata to lowercase.
|
||
|
// NS, MD, MF, CNAME, SOA, MB, MG, MR, PTR,
|
||
|
// HINFO, MINFO, MX, RP, AFSDB, RT, SIG, PX, NXT, NAPTR, KX,
|
||
|
// SRV, DNAME, A6
|
||
|
switch x := r1.(type) {
|
||
|
case *NS:
|
||
|
x.Ns = strings.ToLower(x.Ns)
|
||
|
case *CNAME:
|
||
|
x.Target = strings.ToLower(x.Target)
|
||
|
case *SOA:
|
||
|
x.Ns = strings.ToLower(x.Ns)
|
||
|
x.Mbox = strings.ToLower(x.Mbox)
|
||
|
case *MB:
|
||
|
x.Mb = strings.ToLower(x.Mb)
|
||
|
case *MG:
|
||
|
x.Mg = strings.ToLower(x.Mg)
|
||
|
case *MR:
|
||
|
x.Mr = strings.ToLower(x.Mr)
|
||
|
case *PTR:
|
||
|
x.Ptr = strings.ToLower(x.Ptr)
|
||
|
case *MINFO:
|
||
|
x.Rmail = strings.ToLower(x.Rmail)
|
||
|
x.Email = strings.ToLower(x.Email)
|
||
|
case *MX:
|
||
|
x.Mx = strings.ToLower(x.Mx)
|
||
|
case *NAPTR:
|
||
|
x.Replacement = strings.ToLower(x.Replacement)
|
||
|
case *KX:
|
||
|
x.Exchanger = strings.ToLower(x.Exchanger)
|
||
|
case *SRV:
|
||
|
x.Target = strings.ToLower(x.Target)
|
||
|
case *DNAME:
|
||
|
x.Target = strings.ToLower(x.Target)
|
||
|
}
|
||
|
// 6.2. Canonical RR Form. (5) - origTTL
|
||
|
wire := make([]byte, r1.len()+1) // +1 to be safe(r)
|
||
|
off, err1 := PackRR(r1, wire, 0, nil, false)
|
||
|
if err1 != nil {
|
||
|
return nil, err1
|
||
|
}
|
||
|
wire = wire[:off]
|
||
|
wires[i] = wire
|
||
|
}
|
||
|
sort.Sort(wires)
|
||
|
for i, wire := range wires {
|
||
|
if i > 0 && bytes.Equal(wire, wires[i-1]) {
|
||
|
continue
|
||
|
}
|
||
|
buf = append(buf, wire...)
|
||
|
}
|
||
|
return buf, nil
|
||
|
}
|
||
|
|
||
|
// Map for algorithm 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",
|
||
|
INDIRECT: "INDIRECT",
|
||
|
PRIVATEDNS: "PRIVATEDNS",
|
||
|
PRIVATEOID: "PRIVATEOID",
|
||
|
}
|
||
|
|
||
|
// Map of algorithm strings.
|
||
|
var StringToAlgorithm = reverseInt8(AlgorithmToString)
|
||
|
|
||
|
// Map for hash names.
|
||
|
var HashToString = map[uint8]string{
|
||
|
SHA1: "SHA1",
|
||
|
SHA256: "SHA256",
|
||
|
GOST94: "GOST94",
|
||
|
SHA384: "SHA384",
|
||
|
SHA512: "SHA512",
|
||
|
}
|
||
|
|
||
|
// Map of hash strings.
|
||
|
var StringToHash = reverseInt8(HashToString)
|