2011-01-28 01:52:58 +11:00
|
|
|
package dns
|
|
|
|
|
2011-03-08 07:56:36 +11:00
|
|
|
import (
|
2011-12-10 07:45:57 +11:00
|
|
|
"crypto/sha1"
|
2011-03-08 08:47:20 +11:00
|
|
|
"hash"
|
|
|
|
"strings"
|
2011-03-08 07:56:36 +11:00
|
|
|
)
|
|
|
|
|
2011-03-08 08:47:20 +11:00
|
|
|
type saltWireFmt struct {
|
2012-04-30 05:55:29 +10:00
|
|
|
Salt string `dns:"size-hex"`
|
2011-03-08 08:47:20 +11:00
|
|
|
}
|
2011-01-28 01:52:58 +11:00
|
|
|
|
2016-06-14 04:44:38 +10:00
|
|
|
// HashName hashes a string (label) according to RFC 5155. It returns the hashed string in uppercase.
|
2012-01-22 20:52:06 +11:00
|
|
|
func HashName(label string, ha uint8, iter uint16, salt string) string {
|
2011-03-08 08:47:20 +11:00
|
|
|
saltwire := new(saltWireFmt)
|
|
|
|
saltwire.Salt = salt
|
|
|
|
wire := make([]byte, DefaultMsgSize)
|
2016-06-13 06:06:46 +10:00
|
|
|
n, err := packSaltWire(saltwire, wire)
|
2012-10-10 06:17:54 +11:00
|
|
|
if err != nil {
|
2011-03-08 08:47:20 +11:00
|
|
|
return ""
|
|
|
|
}
|
|
|
|
wire = wire[:n]
|
2011-03-10 00:27:41 +11:00
|
|
|
name := make([]byte, 255)
|
2012-10-10 06:17:54 +11:00
|
|
|
off, err := PackDomainName(strings.ToLower(label), name, 0, nil, false)
|
|
|
|
if err != nil {
|
2011-03-08 08:47:20 +11:00
|
|
|
return ""
|
|
|
|
}
|
2011-03-10 00:27:41 +11:00
|
|
|
name = name[:off]
|
2011-03-08 08:47:20 +11:00
|
|
|
var s hash.Hash
|
|
|
|
switch ha {
|
2011-07-09 01:27:44 +10:00
|
|
|
case SHA1:
|
2011-03-08 08:47:20 +11:00
|
|
|
s = sha1.New()
|
2011-03-24 19:24:49 +11:00
|
|
|
default:
|
|
|
|
return ""
|
2011-03-08 08:47:20 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
// k = 0
|
2017-02-02 18:33:49 +11:00
|
|
|
s.Write(name)
|
|
|
|
s.Write(wire)
|
2011-12-17 01:08:44 +11:00
|
|
|
nsec3 := s.Sum(nil)
|
2011-03-24 19:24:49 +11:00
|
|
|
// k > 0
|
2012-01-22 20:52:06 +11:00
|
|
|
for k := uint16(0); k < iter; k++ {
|
2011-03-24 19:24:49 +11:00
|
|
|
s.Reset()
|
2017-02-02 18:33:49 +11:00
|
|
|
s.Write(nsec3)
|
|
|
|
s.Write(wire)
|
|
|
|
nsec3 = s.Sum(nsec3[:0])
|
2011-03-24 19:24:49 +11:00
|
|
|
}
|
2014-12-06 06:15:17 +11:00
|
|
|
return toBase32(nsec3)
|
2011-03-08 07:56:36 +11:00
|
|
|
}
|
2013-12-25 03:52:39 +11:00
|
|
|
|
2015-02-19 20:58:33 +11:00
|
|
|
// Denialer is an interface that should be implemented by types that are used to denial
|
|
|
|
// answers in DNSSEC.
|
2013-12-26 03:01:39 +11:00
|
|
|
type Denialer interface {
|
|
|
|
// Cover will check if the (unhashed) name is being covered by this NSEC or NSEC3.
|
|
|
|
Cover(name string) bool
|
|
|
|
// Match will check if the ownername matches the (unhashed) name for this NSEC3 or NSEC3.
|
|
|
|
Match(name string) bool
|
|
|
|
}
|
|
|
|
|
2013-12-25 03:52:39 +11:00
|
|
|
// Cover implements the Denialer interface.
|
|
|
|
func (rr *NSEC) Cover(name string) bool {
|
2013-12-25 03:54:20 +11:00
|
|
|
return true
|
|
|
|
}
|
2013-12-25 03:52:39 +11:00
|
|
|
|
2013-12-25 03:54:20 +11:00
|
|
|
// Match implements the Denialer interface.
|
|
|
|
func (rr *NSEC) Match(name string) bool {
|
2013-12-25 03:52:39 +11:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2013-12-25 03:54:20 +11:00
|
|
|
// Cover implements the Denialer interface.
|
2013-12-25 03:52:39 +11:00
|
|
|
func (rr *NSEC3) Cover(name string) bool {
|
|
|
|
// FIXME(miek): check if the zones match
|
|
|
|
// FIXME(miek): check if we're not dealing with parent nsec3
|
|
|
|
hname := HashName(name, rr.Hash, rr.Iterations, rr.Salt)
|
|
|
|
labels := Split(rr.Hdr.Name)
|
|
|
|
if len(labels) < 2 {
|
|
|
|
return false
|
|
|
|
}
|
2013-12-26 03:01:39 +11:00
|
|
|
hash := strings.ToUpper(rr.Hdr.Name[labels[0] : labels[1]-1]) // -1 to remove the dot
|
|
|
|
if hash == rr.NextDomain {
|
|
|
|
return false // empty interval
|
2013-12-25 03:52:39 +11:00
|
|
|
}
|
|
|
|
if hash > rr.NextDomain { // last name, points to apex
|
|
|
|
// hname > hash
|
|
|
|
// hname > rr.NextDomain
|
|
|
|
// TODO(miek)
|
|
|
|
}
|
|
|
|
if hname <= hash {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if hname >= rr.NextDomain {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2013-12-25 03:54:20 +11:00
|
|
|
// Match implements the Denialer interface.
|
2013-12-25 03:52:39 +11:00
|
|
|
func (rr *NSEC3) Match(name string) bool {
|
|
|
|
// FIXME(miek): Check if we are in the same zone
|
|
|
|
hname := HashName(name, rr.Hash, rr.Iterations, rr.Salt)
|
|
|
|
labels := Split(rr.Hdr.Name)
|
|
|
|
if len(labels) < 2 {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
hash := strings.ToUpper(rr.Hdr.Name[labels[0] : labels[1]-1]) // -1 to remove the .
|
|
|
|
if hash == hname {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
2016-06-13 06:06:46 +10:00
|
|
|
|
|
|
|
func packSaltWire(sw *saltWireFmt, msg []byte) (int, error) {
|
|
|
|
off, err := packStringHex(sw.Salt, msg, 0)
|
|
|
|
if err != nil {
|
|
|
|
return off, err
|
|
|
|
}
|
|
|
|
return off, nil
|
|
|
|
}
|