Class Dnsruby::Dnssec
In: lib/Dnsruby/dnssec.rb
Parent: Object
Message Update ResolvError EncodeError OtherResolvError ServFail FormErr DecodeError NXRRSet YXDomain NotImp NXDomain VerifyError NotAuth YXRRSet NotZone Refused TsigError CodeMapper Types MetaTypes QTypes Nsec3HashAlgorithms Algorithms OpCode Classes ExtendedRCode Modes RCode Comparable Name RRSet TsigNotSignedResponseError Resolver SingleResolver StandardError TimeoutError ResolvTimeout DNS Dnssec Hosts RR\n[lib/Dnsruby/resource/A.rb\nlib/Dnsruby/resource/AAAA.rb\nlib/Dnsruby/resource/AFSDB.rb\nlib/Dnsruby/resource/CERT.rb\nlib/Dnsruby/resource/DHCID.rb\nlib/Dnsruby/resource/DLV.rb\nlib/Dnsruby/resource/DNSKEY.rb\nlib/Dnsruby/resource/DS.rb\nlib/Dnsruby/resource/HINFO.rb\nlib/Dnsruby/resource/HIP.rb\nlib/Dnsruby/resource/IN.rb\nlib/Dnsruby/resource/IPSECKEY.rb\nlib/Dnsruby/resource/ISDN.rb\nlib/Dnsruby/resource/KX.rb\nlib/Dnsruby/resource/LOC.rb\nlib/Dnsruby/resource/MINFO.rb\nlib/Dnsruby/resource/MX.rb\nlib/Dnsruby/resource/NAPTR.rb\nlib/Dnsruby/resource/NSAP.rb\nlib/Dnsruby/resource/NSEC.rb\nlib/Dnsruby/resource/NSEC3.rb\nlib/Dnsruby/resource/NSEC3PARAM.rb\nlib/Dnsruby/resource/OPT.rb\nlib/Dnsruby/resource/PX.rb\nlib/Dnsruby/resource/RP.rb\nlib/Dnsruby/resource/RRSIG.rb\nlib/Dnsruby/resource/RT.rb\nlib/Dnsruby/resource/SOA.rb\nlib/Dnsruby/resource/SPF.rb\nlib/Dnsruby/resource/SRV.rb\nlib/Dnsruby/resource/SSHFP.rb\nlib/Dnsruby/resource/TKEY.rb\nlib/Dnsruby/resource/TSIG.rb\nlib/Dnsruby/resource/TXT.rb\nlib/Dnsruby/resource/X25.rb\nlib/Dnsruby/resource/domain_name.rb\nlib/Dnsruby/resource/generic.rb\nlib/Dnsruby/resource/resource.rb] Recursor IPv6 IPv4 ZoneTransfer MessageDecoder MessageEncoder Question Header TheLog ValidatorThread PacketSender ResolverRuby Config KeyCache Cache SingleVerifier SelectThread Resolv ZoneReader lib/Dnsruby/DNS.rb lib/Dnsruby/dnssec.rb lib/Dnsruby/Hosts.rb lib/Dnsruby/resource/generic.rb lib/Dnsruby/Recursor.rb lib/Dnsruby/update.rb lib/Dnsruby/ipv6.rb lib/Dnsruby/ipv4.rb lib/Dnsruby/code_mapper.rb lib/Dnsruby/zone_transfer.rb lib/Dnsruby/message.rb lib/Dnsruby/TheLog.rb lib/Dnsruby/resource/resource.rb lib/Dnsruby/validator_thread.rb lib/Dnsruby/PacketSender.rb lib/Dnsruby/Resolver.rb lib/Dnsruby/Config.rb lib/Dnsruby/key_cache.rb lib/Dnsruby/Cache.rb lib/Dnsruby/single_verifier.rb lib/Dnsruby/SingleResolver.rb lib/Dnsruby/select_thread.rb lib/Dnsruby/name.rb lib/dnsruby.rb lib/Dnsruby/resource/TKEY.rb lib/Dnsruby/zone_reader.rb Dnsruby dot/m_61_0.png

RFC4033, section 7

  "There is one more step that a security-aware stub resolver can take
  if, for whatever reason, it is not able to establish a useful trust
  relationship with the recursive name servers that it uses: it can
  perform its own signature validation by setting the Checking Disabled
  (CD) bit in its query messages.  A validating stub resolver is thus
  able to treat the DNSSEC signatures as trust relationships between
  the zone administrators and the stub resolver itself. "

Dnsruby is configured to validate responses by default. However, it is not configured with any trusted keys by default. Applications may use the verify() method to perform verification with of RRSets of Messages with given keys. Alternatively, trusted keys may be added to this class (either directly, or by loading the IANA TAR or the DLV ISC ZSK). Validation will then be performed from these keys (or the DLV registry, if configured). Negative and positive responses are validation.

Messages are tagged with the current security_level (Message::SecurityLevel). UNCHECKED means Dnsruby has not attempted to validate the response. BOGUS means the response has been checked, and is bogus. INSECURE means the response has been validated to be insecure (e.g. in an unsigned zone) SECURE means that the response has been verfied to be correct.

Several validators are provided, with each maintaining its own cache of trusted keys. If validators are added or removed, the caches of the other validators are not affected.

Methods

Classes and Modules

Class Dnsruby::Dnssec::ValidationPolicy

Public Class methods

Add a trusted Key Signing Key for the ISC DLV registry.

[Source]

    # File lib/Dnsruby/dnssec.rb, line 88
88:     def Dnssec.add_dlv_key(dlv_key)
89:       @@dlv_verifier.add_dlv_key(dlv_key)
90:     end

Add a new trust anchor

[Source]

    # File lib/Dnsruby/dnssec.rb, line 92
92:     def Dnssec.add_trust_anchor(t)
93:       # @TODO@ Create a new verifier?
94:       @@anchor_verifier.add_trust_anchor(t)
95:     end

Add the trusted key with the given expiration time

[Source]

     # File lib/Dnsruby/dnssec.rb, line 97
 97:     def self.add_trust_anchor_with_expiration(k, expiration)
 98:       # Create a new verifier?
 99:       @@anchor_verifier.add_trust_anchor_with_expiration(k, expiration)
100:     end

[Source]

     # File lib/Dnsruby/dnssec.rb, line 315
315:     def self.anchor_verifier
316:       return @@anchor_verifier
317:     end

Wipes the cache of trusted keys

[Source]

     # File lib/Dnsruby/dnssec.rb, line 106
106:     def self.clear_trust_anchors
107:       @@anchor_verifier.clear_trust_anchors
108:     end

[Source]

     # File lib/Dnsruby/dnssec.rb, line 114
114:     def self.clear_trusted_keys
115:       [@@anchor_verifier, @@root_verifier, @@dlv_verifier].each {|v|
116:         v.clear_trusted_keys
117:       }
118:     end

[Source]

     # File lib/Dnsruby/dnssec.rb, line 193
193:     def self.default_resolver
194:       return @@default_resolver
195:     end

This method overrides the system default resolver configuration for validation If default_resolver is set, then it will be used to follow the chain of trust. If it is not, then the default system resolver will be used (unless do_validation_with_recursor is set.

[Source]

     # File lib/Dnsruby/dnssec.rb, line 190
190:     def self.default_resolver=(res)
191:       @@default_resolver = res
192:     end

[Source]

     # File lib/Dnsruby/dnssec.rb, line 318
318:     def self.dlv_verifier
319:       return @@dlv_verifier
320:     end

This method defines the choice of Resolver or Recursor, when the validator is checking responses. If set to true, then a Recursor will be used to query for the DNSSEC records. Otherwise, the default system resolver will be used.

[Source]

     # File lib/Dnsruby/dnssec.rb, line 180
180:     def self.do_validation_with_recursor(on)
181:       @@do_validation_with_recursor = on
182:     end

[Source]

     # File lib/Dnsruby/dnssec.rb, line 183
183:     def self.do_validation_with_recursor?
184:       return @@do_validation_with_recursor
185:     end

Load the IANA TAR. THIS METHOD IS NOT SECURE!!!

[Source]

     # File lib/Dnsruby/dnssec.rb, line 144
144:     def self.load_itar
145:       # @TODO@ THIS IS VERY INSECURE!! WRITE THIS PROPERLY!!
146:       # Should really check the signatures here to make sure the keys are good!
147:       Net::FTP::open("ftp.iana.org") { |ftp|
148:         ftp.login("anonymous")
149:         ftp.passive = true
150:         ftp.chdir("/itar")
151:         lastname=nil
152:         ftp.gettextfile("anchors.mf") {|line|
153:           next if (line.strip.length == 0)
154:           first = line[0]
155:           if (first.class == String)
156:             first = first.getbyte(0) # Ruby 1.9
157:           end
158:           #            print "Reading ITAR : #{line}, first : #{first}\n"
159:           next if (first==59) # ";")
160:           if (line.strip=~(/^DS /) || line.strip=~(/^DNSKEY /))
161:             line = lastname.to_s + ((lastname.absolute?)?".":"") + " " + line
162:           end
163:           ds = RR.create(line)
164:           if ((ds.type == Types::DS) || (ds.type == Types::DNSKEY))
165:             #            assert(ds.name.absolute?)
166:             Dnssec.add_trust_anchor(ds)
167:           end
168:           lastname = ds.name
169:         }
170:       }
171:     end

[Source]

     # File lib/Dnsruby/dnssec.rb, line 132
132:     def self.no_keys?
133:       no_keys = true
134:       [@@anchor_verifier, @@root_verifier, @@dlv_verifier].each {|v|
135:         if (v.trusted_keys.length() > 0 ||
136:               v.trust_anchors.length() > 0)
137:           no_keys = false
138:         end
139:       }
140:       return no_keys
141:     end

Remove the trusted key

[Source]

     # File lib/Dnsruby/dnssec.rb, line 102
102:     def Dnssec.remove_trust_anchor(t)
103:       @@anchor_verifier.remove_trust_anchor(t)
104:     end

[Source]

     # File lib/Dnsruby/dnssec.rb, line 120
120:     def self.reset
121:       @@validation_policy = ValidationPolicy::LOCAL_ANCHORS_THEN_ROOT
122:       @@root_verifier = SingleVerifier.new(SingleVerifier::VerifierType::ROOT)
123: 
124:       @@dlv_verifier = SingleVerifier.new(SingleVerifier::VerifierType::DLV)
125: 
126:       # @TODO@ Could add a new one of these for each anchor.
127:       @@anchor_verifier = SingleVerifier.new(SingleVerifier::VerifierType::ANCHOR)
128:       @@do_validation_with_recursor = true # Many nameservers don't handle DNSSEC correctly yet
129:       @@default_resolver = Resolver.new
130:     end

[Source]

     # File lib/Dnsruby/dnssec.rb, line 321
321:     def self.root_verifier
322:       return @@root_verifier
323:     end

[Source]

     # File lib/Dnsruby/dnssec.rb, line 110
110:     def self.trust_anchors
111:       return @@anchor_verifier.trust_anchors
112:     end

Returns true for secure/insecure, false otherwise This method will set the security_level on msg to the appropriate value. Could be : secure, insecure, bogus or indeterminate If an error is encountered during verification, then the thrown exception will define the error.

[Source]

     # File lib/Dnsruby/dnssec.rb, line 202
202:     def self.validate(msg)
203:       query = Message.new()
204:       query.header.cd=true
205:       return self.validate_with_query(query, msg)
206:     end

[Source]

     # File lib/Dnsruby/dnssec.rb, line 291
291:     def self.validate_with_anchors(msg, query)
292:       return @@anchor_verifier.validate(msg, query)
293:     end

[Source]

     # File lib/Dnsruby/dnssec.rb, line 299
299:     def self.validate_with_dlv(msg, query)
300:       return @@dlv_verifier.validate(msg, query)
301:     end

[Source]

     # File lib/Dnsruby/dnssec.rb, line 208
208:     def self.validate_with_query(query, msg)
209:       if (!msg)
210:         return false
211:       end
212:       # First, just check there is something to validate!
213:       found_sigs = false
214:       msg.each_resource {|rr|
215:         if (rr.type == Types::RRSIG)
216:           found_sigs = true
217:         end
218:       }
219:       if (found_sigs)
220:         begin
221:           if (verify(msg))
222:             msg.security_level = Message::SecurityLevel.SECURE
223:             return true
224:           end
225:         rescue VerifyError => e
226:           msg.security_error = e
227:         end
228:       end
229: 
230:       # SHOULD ALWAYS VERIFY DNSSEC-SIGNED RESPONSES?
231:       # Yes - if a trust anchor is configured. Otherwise, act on CD bit (in query)
232:       TheLog.debug("Checking whether to validate, query.cd = #{query.header.cd}")
233:       if (((@@validation_policy > ValidationPolicy::ALWAYS_ROOT_ONLY) && (self.trust_anchors().length > 0)) ||
234:             # Check query here, and validate if CD is true
235:           (query.header.cd == true))
236:         TheLog.debug("Starting validation")
237: 
238:         # Validate!
239:         # Need to think about trapping/storing exceptions and security_levels here
240:         last_error = ""
241:         last_level = Message::SecurityLevel.BOGUS
242:         last_error_level = Message::SecurityLevel.BOGUS
243:         if (@@validation_policy == ValidationPolicy::ALWAYS_LOCAL_ANCHORS_ONLY)
244:           last_level, last_error, last_error_level = try_validation(last_level, last_error, last_error_level,
245:             Proc.new{|m, q| validate_with_anchors(m, q)}, msg, query)
246:         elsif (@@validation_policy == ValidationPolicy::ALWAYS_ROOT_ONLY)
247:           last_level, last_error, last_error_level = try_validation(last_level, last_error, last_error_level,
248:             Proc.new{|m, q| validate_with_root(m, q)}, msg, query)
249:         elsif (@@validation_policy == ValidationPolicy::LOCAL_ANCHORS_THEN_ROOT)
250:           last_level, last_error, last_error_level = try_validation(last_level, last_error, last_error_level, 
251:             Proc.new{|m, q| validate_with_anchors(m, q)}, msg, query)
252:           if (last_level != Message::SecurityLevel.SECURE)
253:             last_level, last_error, last_error_level = try_validation(last_level, last_error, last_error_level,
254:               Proc.new{|m, q| validate_with_root(m, q)}, msg, query)
255:           end
256:         elsif (@@validation_policy == ValidationPolicy::ROOT_THEN_LOCAL_ANCHORS)
257:           last_level, last_error, last_error_level = try_validation(last_level, last_error, last_error_level,
258:             Proc.new{|m, q| validate_with_root(m, q)}, msg, query)
259:           if (last_level != Message::SecurityLevel.SECURE)
260:             last_level, last_error, last_error_level = try_validation(last_level, last_error, last_error_level,
261:               Proc.new{|m, q| validate_with_anchors(m, q)}, msg, query)
262:           end
263:         end
264:         if (last_level != Message::SecurityLevel.SECURE)
265:           last_level, last_error, last_error_level = try_validation(last_level, last_error, last_error_level, 
266:             Proc.new{|m, q| validate_with_dlv(m, q)}, msg, query)
267:         end
268:         # Set the message security level!
269:         msg.security_level = last_level
270:         msg.security_error = last_error
271:         raise VerifyError.new(last_error) if (last_level < 0)
272:         return (msg.security_level.code > Message::SecurityLevel::UNCHECKED)
273:       end
274:       msg.security_level = Message::SecurityLevel.UNCHECKED
275:       return true
276:     end

[Source]

     # File lib/Dnsruby/dnssec.rb, line 295
295:     def self.validate_with_root(msg, query)
296:       return @@root_verifier.validate(msg, query)
297:     end

[Source]

    # File lib/Dnsruby/dnssec.rb, line 74
74:     def Dnssec.validation_policy
75:       @@validation_policy
76:     end

[Source]

    # File lib/Dnsruby/dnssec.rb, line 68
68:     def Dnssec.validation_policy=(p)
69:       if ((p >= ALWAYS_ROOT_ONY) && (p <= ALWAYS_LOCAL_ANCHORS))
70:         @@validation_policy = p
71:         # @TODO@ Should we be clearing the trusted keys now?
72:       end
73:     end

[Source]

     # File lib/Dnsruby/dnssec.rb, line 303
303:     def self.verify(msg, keys=nil)
304:       begin
305:         return true if @@anchor_verifier.verify(msg, keys=nil)
306:       rescue VerifyError
307:         begin
308:           return true if @@root_verifier.verify(msg, keys=nil)
309:         rescue VerifyError
310:           return true if @@dlv_verifier.verify(msg, keys=nil) # Will carry error to client
311:         end
312:       end
313:     end

[Source]

     # File lib/Dnsruby/dnssec.rb, line 328
328:     def self.verify_rrset(rrset, keys = nil)
329:       return ((@@anchor_verifier.verify_rrset(rrset, keys) ||
330:             @@root_verifier.verify_rrset(rrset, keys) ||
331:             @@dlv_verifier.verify_rrset(rrset, keys)))
332:     end

[Validate]