1package dns 2 3import ( 4 "crypto/sha1" 5 "hash" 6 "io" 7 "strings" 8) 9 10type saltWireFmt struct { 11 Salt string `dns:"size-hex"` 12} 13 14// HashName hashes a string (label) according to RFC 5155. It returns the hashed string in uppercase. 15func HashName(label string, ha uint8, iter uint16, salt string) string { 16 saltwire := new(saltWireFmt) 17 saltwire.Salt = salt 18 wire := make([]byte, DefaultMsgSize) 19 n, err := packSaltWire(saltwire, wire) 20 if err != nil { 21 return "" 22 } 23 wire = wire[:n] 24 name := make([]byte, 255) 25 off, err := PackDomainName(strings.ToLower(label), name, 0, nil, false) 26 if err != nil { 27 return "" 28 } 29 name = name[:off] 30 var s hash.Hash 31 switch ha { 32 case SHA1: 33 s = sha1.New() 34 default: 35 return "" 36 } 37 38 // k = 0 39 name = append(name, wire...) 40 io.WriteString(s, string(name)) 41 nsec3 := s.Sum(nil) 42 // k > 0 43 for k := uint16(0); k < iter; k++ { 44 s.Reset() 45 nsec3 = append(nsec3, wire...) 46 io.WriteString(s, string(nsec3)) 47 nsec3 = s.Sum(nil) 48 } 49 return toBase32(nsec3) 50} 51 52// Denialer is an interface that should be implemented by types that are used to denial 53// answers in DNSSEC. 54type Denialer interface { 55 // Cover will check if the (unhashed) name is being covered by this NSEC or NSEC3. 56 Cover(name string) bool 57 // Match will check if the ownername matches the (unhashed) name for this NSEC3 or NSEC3. 58 Match(name string) bool 59} 60 61// Cover implements the Denialer interface. 62func (rr *NSEC) Cover(name string) bool { 63 return true 64} 65 66// Match implements the Denialer interface. 67func (rr *NSEC) Match(name string) bool { 68 return true 69} 70 71// Cover implements the Denialer interface. 72func (rr *NSEC3) Cover(name string) bool { 73 // FIXME(miek): check if the zones match 74 // FIXME(miek): check if we're not dealing with parent nsec3 75 hname := HashName(name, rr.Hash, rr.Iterations, rr.Salt) 76 labels := Split(rr.Hdr.Name) 77 if len(labels) < 2 { 78 return false 79 } 80 hash := strings.ToUpper(rr.Hdr.Name[labels[0] : labels[1]-1]) // -1 to remove the dot 81 if hash == rr.NextDomain { 82 return false // empty interval 83 } 84 if hash > rr.NextDomain { // last name, points to apex 85 // hname > hash 86 // hname > rr.NextDomain 87 // TODO(miek) 88 } 89 if hname <= hash { 90 return false 91 } 92 if hname >= rr.NextDomain { 93 return false 94 } 95 return true 96} 97 98// Match implements the Denialer interface. 99func (rr *NSEC3) Match(name string) bool { 100 // FIXME(miek): Check if we are in the same zone 101 hname := HashName(name, rr.Hash, rr.Iterations, rr.Salt) 102 labels := Split(rr.Hdr.Name) 103 if len(labels) < 2 { 104 return false 105 } 106 hash := strings.ToUpper(rr.Hdr.Name[labels[0] : labels[1]-1]) // -1 to remove the . 107 if hash == hname { 108 return true 109 } 110 return false 111} 112 113func packSaltWire(sw *saltWireFmt, msg []byte) (int, error) { 114 off, err := packStringHex(sw.Salt, msg, 0) 115 if err != nil { 116 return off, err 117 } 118 return off, nil 119} 120