dns/nsec3.go

161 lines
4.4 KiB
Go
Raw Normal View History

2011-01-27 14:52:58 +00:00
package dns
2011-03-07 20:56:36 +00:00
import (
2012-01-22 09:52:06 +00:00
"bytes"
2011-12-09 20:45:57 +00:00
"crypto/sha1"
2011-03-07 21:47:20 +00:00
"hash"
"io"
2011-03-07 21:47:20 +00:00
"strings"
2011-03-07 20:56:36 +00:00
)
2011-03-07 21:47:20 +00:00
type saltWireFmt struct {
Salt string "size-hex"
}
2011-01-27 14:52:58 +00:00
2012-01-16 21:08:02 +00:00
// HashName hashes a string (label) according to RFC5155. It returns the hashed string.
2012-01-22 09:52:06 +00:00
func HashName(label string, ha uint8, iter uint16, salt string) string {
2011-03-07 21:47:20 +00:00
saltwire := new(saltWireFmt)
saltwire.Salt = salt
wire := make([]byte, DefaultMsgSize)
n, ok := packStruct(saltwire, wire, 0)
2011-03-07 21:47:20 +00:00
if !ok {
return ""
}
wire = wire[:n]
2011-03-09 13:27:41 +00:00
name := make([]byte, 255)
off, ok1 := PackDomainName(strings.ToLower(label), name, 0, nil, false)
2011-03-07 21:47:20 +00:00
if !ok1 {
return ""
}
2011-03-09 13:27:41 +00:00
name = name[:off]
2011-03-07 21:47:20 +00:00
var s hash.Hash
switch ha {
2011-07-08 15:27:44 +00:00
case SHA1:
2011-03-07 21:47:20 +00:00
s = sha1.New()
2011-03-24 08:24:49 +00:00
default:
return ""
2011-03-07 21:47:20 +00:00
}
// k = 0
2011-03-09 13:27:41 +00:00
name = append(name, wire...)
2011-12-16 18:42:30 +00:00
io.WriteString(s, string(name))
nsec3 := s.Sum(nil)
2011-03-24 08:24:49 +00:00
// k > 0
2012-01-22 09:52:06 +00:00
for k := uint16(0); k < iter; k++ {
2011-03-24 08:24:49 +00:00
s.Reset()
nsec3 = append(nsec3, wire...)
2011-12-16 18:42:30 +00:00
io.WriteString(s, string(nsec3))
2011-12-16 14:12:01 +00:00
nsec3 = s.Sum(nil)
2011-03-24 08:24:49 +00:00
}
2011-03-07 21:47:20 +00:00
return unpackBase32(nsec3)
2011-03-07 20:56:36 +00:00
}
2011-03-09 17:54:55 +00:00
2012-01-14 09:52:37 +00:00
// HashNames hashes the ownername and the next owner name in an NSEC3 record according to RFC 5155.
// It uses the paramaters as set in the NSEC3 record. The string zone is appended to the hashed
// ownername.
func (nsec3 *RR_NSEC3) HashNames(zone string) {
2012-01-22 09:52:06 +00:00
nsec3.Header().Name = strings.ToLower(HashName(nsec3.Header().Name, nsec3.Hash, nsec3.Iterations, nsec3.Salt)) + "." + zone
nsec3.NextDomain = HashName(nsec3.NextDomain, nsec3.Hash, nsec3.Iterations, nsec3.Salt)
}
func (nsec3 *RR_NSEC3) Match(domain string) bool {
return strings.ToUpper(SplitLabels(nsec3.Header().Name)[0]) == strings.ToUpper(HashName(domain, nsec3.Hash, nsec3.Iterations, nsec3.Salt))
2011-03-09 17:54:55 +00:00
}
2011-09-15 18:13:21 +00:00
2012-01-17 18:16:58 +00:00
// NsecVerify verifies an denial of existence response with NSECs
2011-09-15 18:13:21 +00:00
// NsecVerify returns nil when the NSECs in the message contain
2012-01-17 17:48:40 +00:00
// the correct proof. This function does not validates the NSECs.
2011-11-02 22:06:54 +00:00
func (m *Msg) NsecVerify(q Question) error {
2011-09-15 18:13:21 +00:00
2011-11-02 22:06:54 +00:00
return nil
2011-09-15 18:13:21 +00:00
}
2012-01-17 18:16:58 +00:00
// Nsec3Verify verifies an denial of existence response with NSEC3s.
// This function does not validate the NSEC3s.
2011-11-02 22:06:54 +00:00
func (m *Msg) Nsec3Verify(q Question) error {
2012-01-19 18:48:09 +00:00
var (
nsec3 []*RR_NSEC3
ncdenied = false // next closer denied
sodenied = false // source of synthesis denied
)
2012-01-17 18:16:58 +00:00
if len(m.Answer) > 0 && len(m.Ns) > 0 {
// Wildcard expansion
// Closest encloser inferred from SIG in authority and qname
2012-01-19 18:48:09 +00:00
// println("EXPANDED WILDCARD PROOF or DNAME CNAME")
// println("NODATA")
2012-01-17 18:16:58 +00:00
// I need to check the type bitmap
// wildcard bit not set?
// MM: No need to check the wildcard bit here:
// This response has only 1 NSEC4 and it does not match
// the closest encloser (it covers next closer).
}
if len(m.Answer) == 0 && len(m.Ns) > 0 {
// Maybe an NXDOMAIN, we only know when we check
2012-01-19 18:48:09 +00:00
for _, n := range m.Ns {
if n.Header().Rrtype == TypeNSEC3 {
nsec3 = append(nsec3, n.(*RR_NSEC3))
2012-01-17 18:16:58 +00:00
}
}
2012-01-19 18:48:09 +00:00
if len(nsec3) == 0 {
return ErrDenialNsec3
}
2012-01-17 18:16:58 +00:00
2012-01-22 09:52:06 +00:00
hash := nsec3[0].Hash
iter := nsec3[0].Iterations
2012-01-19 18:48:09 +00:00
salt := nsec3[0].Salt
ce := "" // closest encloser
nc := "" // next closer
so := "" // source of synthesis
lastchopped := ""
labels := SplitLabels(q.Name)
2012-01-17 18:16:58 +00:00
2012-01-19 18:48:09 +00:00
// Find the closest encloser and create the next closer
for _, nsec := range nsec3 {
candidate := ""
for i := len(labels) - 1; i >= 0; i-- {
candidate = labels[i] + "." + candidate
2012-01-22 09:52:06 +00:00
if nsec.Match(candidate) {
2012-01-19 18:48:09 +00:00
ce = candidate
2012-01-17 18:16:58 +00:00
}
2012-01-19 18:48:09 +00:00
lastchopped = labels[i]
2012-01-17 18:16:58 +00:00
}
}
2012-01-19 18:48:09 +00:00
if ce == "" { // what about root label?
return ErrDenialCe
}
nc = lastchopped + "." + ce
so = "*." + ce
2012-01-17 17:48:40 +00:00
2012-01-19 18:48:09 +00:00
// Check if the next closer is covered and thus denied
for _, nsec := range nsec3 {
2012-01-22 09:52:06 +00:00
firstlab := []byte(strings.ToUpper(SplitLabels(nsec.Header().Name)[0]))
nextdom := []byte(strings.ToUpper(nsec.NextDomain))
hashednc := []byte(HashName(nc, hash, iter, salt))
if bytes.Compare(hashednc, firstlab) == 1 &&
bytes.Compare(hashednc, nextdom) == -1 {
2012-01-19 18:48:09 +00:00
ncdenied = true
2012-01-20 11:24:20 +00:00
break
2012-01-17 18:16:58 +00:00
}
2012-01-19 18:48:09 +00:00
}
if !ncdenied {
2012-01-22 09:52:06 +00:00
return ErrDenialNc // add next closer name here
2012-01-17 18:16:58 +00:00
}
2011-09-15 18:13:21 +00:00
2012-01-20 11:24:20 +00:00
// Check if the source of synthesis is covered and thus denied
2012-01-19 18:48:09 +00:00
for _, nsec := range nsec3 {
firstlab := strings.ToUpper(SplitLabels(nsec.Header().Name)[0])
nextdom := strings.ToUpper(nsec.NextDomain)
hashedso := HashName(so, hash, iter, salt)
if hashedso > firstlab && hashedso < nextdom {
sodenied = true
2012-01-20 11:24:20 +00:00
break
2012-01-17 18:16:58 +00:00
}
}
2012-01-19 18:48:09 +00:00
if !sodenied {
return ErrDenialSo
}
2012-01-20 11:24:20 +00:00
return nil
2012-01-17 18:16:58 +00:00
}
2011-11-02 22:06:54 +00:00
return nil
2011-09-15 18:13:21 +00:00
}