Class: Dnsruby::RR::NSEC3
- Inherits:
-
Dnsruby::RR
- Object
- Dnsruby::RR
- Dnsruby::RR::NSEC3
- Defined in:
- lib/Dnsruby/resource/NSEC3.rb
Overview
The NSEC3 Resource Record (RR) provides authenticated denial of existence for DNS Resource Record Sets.
The NSEC3 RR lists RR types present at the original owner name of the NSEC3 RR. It includes the next hashed owner name in the hash order of the zone. The complete set of NSEC3 RRs in a zone indicates which RRSets exist for the original owner name of the RR and form a chain of hashed owner names in the zone. This information is used to provide authenticated denial of existence for DNS data. To provide protection against zone enumeration, the owner names used in the NSEC3 RR are cryptographic hashes of the original owner name prepended as a single label to the name of the zone. The NSEC3 RR indicates which hash function is used to construct the hash, which salt is used, and how many iterations of the hash function are performed over the original owner name.
Constant Summary collapse
Constants inherited from Dnsruby::RR
Instance Attribute Summary collapse
-
#flags ⇒ Object
The Flags field contains 8 one-bit flags that can be used to indicate different processing.
-
#hash_alg ⇒ Object
The Hash Algorithm field identifies the cryptographic hash algorithm used to construct the hash-value.
-
#hash_length ⇒ Object
The Hash Length field defines the length of the Next Hashed Owner Name field, ranging in value from 1 to 255 octets.
-
#iterations ⇒ Object
The Iterations field defines the number of additional times the hash function has been performed.
-
#next_hashed ⇒ Object
The Next Hashed Owner Name field contains the next hashed owner name in hash order.
-
#salt_length ⇒ Object
readonly
The Salt Length field defines the length of the Salt field in octets, ranging in value from 0 to 255.
-
#types ⇒ Object
The Type Bit Maps field identifies the RRset types that exist at the NSEC RR’s owner name.
Attributes inherited from Dnsruby::RR
#klass, #name, #rdata, #ttl, #type
Class Method Summary collapse
- .calculate_hash(name, iterations, salt, hash_alg) ⇒ Object
- .decode_next_hashed(input) ⇒ Object
-
.decode_rdata(msg) ⇒ Object
:nodoc: all.
- .decode_salt(input) ⇒ Object
- .encode_next_hashed(n) ⇒ Object
- .encode_salt(s) ⇒ Object
-
.h(x, hash_alg) ⇒ Object
:nodoc: all.
Instance Method Summary collapse
- #add_type(t) ⇒ Object
- #calculate_hash ⇒ Object
- #check_name_in_range(name) ⇒ Object
- #check_name_in_wildcard_range(name) ⇒ Object
- #decode_next_hashed(input) ⇒ Object
- #encode_next_hashed(n) ⇒ Object
-
#encode_rdata(msg, canonical = false) ⇒ Object
:nodoc: all.
-
#from_data(data) ⇒ Object
:nodoc: all.
- #from_string(input) ⇒ Object
-
#h(x) ⇒ Object
:nodoc: all.
-
#opt_out? ⇒ Boolean
If the Opt-Out flag is set, the NSEC3 record covers zero or more unsigned delegations.
-
#rdata_to_string ⇒ Object
:nodoc: all.
-
#salt ⇒ Object
The Salt field is appended to the original owner name before hashing in order to defend against pre-calculated dictionary attacks.
- #salt=(s) ⇒ Object
Methods inherited from Dnsruby::RR
#<=>, #==, #clone, create, #eql?, find_class, #from_hash, get_class, get_num, #hash, implemented_rrs, #init_defaults, new_from_data, new_from_hash, new_from_string, #rdlength, #sameRRset, #to_s
Instance Attribute Details
#flags ⇒ Object
The Flags field contains 8 one-bit flags that can be used to indicate different processing. All undefined flags must be zero. The only flag defined by the NSEC3 specification is the Opt-Out flag.
70 71 72 |
# File 'lib/Dnsruby/resource/NSEC3.rb', line 70 def flags @flags end |
#hash_alg ⇒ Object
The Hash Algorithm field identifies the cryptographic hash algorithm used to construct the hash-value.
66 67 68 |
# File 'lib/Dnsruby/resource/NSEC3.rb', line 66 def hash_alg @hash_alg end |
#hash_length ⇒ Object
The Hash Length field defines the length of the Next Hashed Owner Name field, ranging in value from 1 to 255 octets.
79 80 81 |
# File 'lib/Dnsruby/resource/NSEC3.rb', line 79 def hash_length @hash_length end |
#iterations ⇒ Object
The Iterations field defines the number of additional times the hash function has been performed.
73 74 75 |
# File 'lib/Dnsruby/resource/NSEC3.rb', line 73 def iterations @iterations end |
#next_hashed ⇒ Object
The Next Hashed Owner Name field contains the next hashed owner name in hash order.
82 83 84 |
# File 'lib/Dnsruby/resource/NSEC3.rb', line 82 def next_hashed @next_hashed end |
#salt_length ⇒ Object (readonly)
The Salt Length field defines the length of the Salt field in octets, ranging in value from 0 to 255.
76 77 78 |
# File 'lib/Dnsruby/resource/NSEC3.rb', line 76 def salt_length @salt_length end |
#types ⇒ Object
The Type Bit Maps field identifies the RRset types that exist at the NSEC RR’s owner name
85 86 87 |
# File 'lib/Dnsruby/resource/NSEC3.rb', line 85 def types @types end |
Class Method Details
.calculate_hash(name, iterations, salt, hash_alg) ⇒ Object
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/Dnsruby/resource/NSEC3.rb', line 101 def NSEC3.calculate_hash(name, iterations, salt, hash_alg) # RFC5155 #5. Calculation of the Hash # Define H(x) to be the hash of x using the Hash Algorithm selected by # the NSEC3 RR, k to be the number of Iterations, and || to indicate # concatenation. Then define: # # IH(salt, x, 0) = H(x || salt), and # # IH(salt, x, k) = H(IH(salt, x, k-1) || salt), if k > 0 # # Then the calculated hash of an owner name is # # IH(salt, owner name, iterations), # # where the owner name is in the canonical form, defined as: # # The wire format of the owner name where: # # 1. The owner name is fully expanded (no DNS name compression) and # fully qualified; # 2. All uppercase US-ASCII letters are replaced by the corresponding # lowercase US-ASCII letters; # 3. If the owner name is a wildcard name, the owner name is in its # original unexpanded form, including the "*" label (no wildcard # substitution); # # This form is as defined in Section 6.2 of [RFC 4034]. # n = Name.create(name) out = n.canonical begin (0..iterations).each { out =NSEC3.h(out + salt, hash_alg); } return Base32.encode32hex(out).downcase rescue ArgumentError TheLog.error("Unknown hash algorithm #{hash_alg} used for NSEC3 hash") return "Unknown NSEC3 hash algorithm" end end |
.decode_next_hashed(input) ⇒ Object
253 254 255 |
# File 'lib/Dnsruby/resource/NSEC3.rb', line 253 def NSEC3.decode_next_hashed(input) return Base32.decode32hex(input) end |
.decode_rdata(msg) ⇒ Object
:nodoc: all
325 326 327 328 329 330 331 332 333 334 335 336 337 |
# File 'lib/Dnsruby/resource/NSEC3.rb', line 325 def self.decode_rdata(msg) #:nodoc: all hash_alg, flags, iterations, salt_length = msg.get_unpack("ccnc") # Salt may be omitted salt = [] if (salt_length > 0) salt = msg.get_bytes(salt_length) end hash_length, = msg.get_unpack("c") next_hashed = msg.get_bytes(hash_length) types = NSEC.decode_types(msg.get_bytes) return self.new( [hash_alg, flags, iterations, salt_length, salt, hash_length, next_hashed, types]) end |
.decode_salt(input) ⇒ Object
235 236 237 238 239 240 |
# File 'lib/Dnsruby/resource/NSEC3.rb', line 235 def NSEC3.decode_salt(input) if (input == "-") return "" end return [input].pack("H*") end |
.encode_next_hashed(n) ⇒ Object
261 262 263 |
# File 'lib/Dnsruby/resource/NSEC3.rb', line 261 def NSEC3.encode_next_hashed(n) return Base32.encode32hex(n).downcase end |
.encode_salt(s) ⇒ Object
242 243 244 245 246 247 |
# File 'lib/Dnsruby/resource/NSEC3.rb', line 242 def NSEC3.encode_salt(s) if (!s || s.length == 0) return "-" end return s.unpack("H*")[0] end |
.h(x, hash_alg) ⇒ Object
:nodoc: all
149 150 151 152 153 154 |
# File 'lib/Dnsruby/resource/NSEC3.rb', line 149 def NSEC3.h(x, hash_alg) # :nodoc: all if (Nsec3HashAlgorithms.SHA_1 == hash_alg) return Digest::SHA1.digest(x) end raise ArgumentError.new("Unknown hash algorithm") end |
Instance Method Details
#add_type(t) ⇒ Object
178 179 180 |
# File 'lib/Dnsruby/resource/NSEC3.rb', line 178 def add_type(t) self.types=(@types + [t]) end |
#calculate_hash ⇒ Object
97 98 99 |
# File 'lib/Dnsruby/resource/NSEC3.rb', line 97 def calculate_hash return NSEC3.calculate_hash(@name, @iterations, @salt, @hash_alg) end |
#check_name_in_range(name) ⇒ Object
87 88 89 90 |
# File 'lib/Dnsruby/resource/NSEC3.rb', line 87 def check_name_in_range(name) # @TODO@ Check if the name is covered by this record return false end |
#check_name_in_wildcard_range(name) ⇒ Object
92 93 94 95 |
# File 'lib/Dnsruby/resource/NSEC3.rb', line 92 def check_name_in_wildcard_range(name) # @TODO@ Check if the name is covered by this record return false end |
#decode_next_hashed(input) ⇒ Object
249 250 251 |
# File 'lib/Dnsruby/resource/NSEC3.rb', line 249 def decode_next_hashed(input) @next_hashed = NSEC3.decode_next_hashed(input) end |
#encode_next_hashed(n) ⇒ Object
257 258 259 |
# File 'lib/Dnsruby/resource/NSEC3.rb', line 257 def encode_next_hashed(n) return NSEC3.encode_next_hashed(n) end |
#encode_rdata(msg, canonical = false) ⇒ Object
:nodoc: all
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 |
# File 'lib/Dnsruby/resource/NSEC3.rb', line 308 def encode_rdata(msg, canonical=false) #:nodoc: all # s = salt() s = @salt sl = s.length() if (s == "-") sl = 0 end msg.put_pack("ccnc", @hash_alg.code, @flags, @iterations, sl) if (sl > 0) msg.put_bytes(s) end msg.put_pack("c", @hash_length) msg.put_bytes(@next_hashed) types = NSEC.encode_types(self) msg.put_bytes(types) end |
#from_data(data) ⇒ Object
:nodoc: all
211 212 213 214 215 216 217 218 219 220 221 222 |
# File 'lib/Dnsruby/resource/NSEC3.rb', line 211 def from_data(data) #:nodoc: all hash_alg, flags, iterations, salt_length, salt, hash_length, next_hashed, types = data self.hash_alg=(hash_alg) self.flags=(flags) self.iterations=(iterations) # self.salt_length=(salt_length) # self.salt=(salt) @salt=salt self.hash_length=(hash_length) self.next_hashed=(next_hashed) self.types=(types) end |
#from_string(input) ⇒ Object
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 |
# File 'lib/Dnsruby/resource/NSEC3.rb', line 265 def from_string(input) if (input.length > 0) data = input.split self.hash_alg=(data[0]).to_i self.flags=(data[1]).to_i self.iterations=(data[2]).to_i self.salt=(data[3]) len = data[0].length + data[1].length + data[2].length + data[3].length + 4 # There may or may not be brackets around next_hashed if (data[4] == "(") len = len + data[4].length + 1 end next_hashed_and_types = (input[len, input.length-len]) data2 = next_hashed_and_types.split() self.next_hashed=decode_next_hashed(data2[0]) self.hash_length=(@next_hashed.length) len2 = data2[0].length + 1 self.types = next_hashed_and_types[len2, next_hashed_and_types.length - len2] # self.types=data2[1] # # len = data[0].length + data[1].length + data[2].length + data[3].length + data[5].length + 7 # # self.types=(input[len, input.length-len]) end end |
#h(x) ⇒ Object
:nodoc: all
145 146 147 |
# File 'lib/Dnsruby/resource/NSEC3.rb', line 145 def h(x) # :nodoc: all return NSEC3.h(x, @hash_alg) end |
#opt_out? ⇒ Boolean
If the Opt-Out flag is set, the NSEC3 record covers zero or more unsigned delegations.
193 194 195 |
# File 'lib/Dnsruby/resource/NSEC3.rb', line 193 def opt_out? return (@flags==OPT_OUT) end |
#rdata_to_string ⇒ Object
:nodoc: all
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 |
# File 'lib/Dnsruby/resource/NSEC3.rb', line 292 def rdata_to_string #:nodoc: all if (@next_hashed!=nil) type_strings = [] @types.each do |t| type_strings.push(t.string) end # salt = NSEC3.encode_salt(@salt) salt = salt() next_hashed = encode_next_hashed(@next_hashed) types = type_strings.join(" ") return "#{@hash_alg.code} #{@flags} #{@iterations} #{salt} ( #{next_hashed} #{types} )" else return "" end end |
#salt ⇒ Object
The Salt field is appended to the original owner name before hashing in order to defend against pre-calculated dictionary attacks.
226 227 228 |
# File 'lib/Dnsruby/resource/NSEC3.rb', line 226 def salt return NSEC3.encode_salt(@salt) end |
#salt=(s) ⇒ Object
230 231 232 233 |
# File 'lib/Dnsruby/resource/NSEC3.rb', line 230 def salt=(s) @salt = NSEC3.decode_salt(s) @salt_length = @salt.length end |