Class: Dnsruby::Dnssec
- Inherits:
-
Object
- Object
- Dnsruby::Dnssec
- Defined in:
- lib/dnsruby/dnssec.rb
Overview
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.
Defined Under Namespace
Classes: ValidationPolicy
Constant Summary collapse
- @@validation_policy =
ValidationPolicy::LOCAL_ANCHORS_THEN_ROOT
- @@root_verifier =
SingleVerifier.new(SingleVerifier::VerifierType::ROOT)
- @@root_key =
#NOTE# You may wish to import these via a secure channel yourself, if
using Dnsruby for validation.
RR.create(". IN DS 19036 8 2 49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5")
- @@root_key_new =
RR.create(". IN DS 20326 8 2 E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D")
- @@dlv_verifier =
SingleVerifier.new(SingleVerifier::VerifierType::DLV)
- @@anchor_verifier =
@TODO@ Could add a new one of these for each anchor.
SingleVerifier.new(SingleVerifier::VerifierType::ANCHOR)
- @@do_validation_with_recursor =
Many nameservers don’t handle DNSSEC correctly yet
true
- @@default_resolver =
Resolver.new
Class Method Summary collapse
-
.add_dlv_key(dlv_key) ⇒ Object
Add a trusted Key Signing Key for the ISC DLV registry.
-
.add_trust_anchor(t) ⇒ Object
Add a new trust anchor.
-
.add_trust_anchor_with_expiration(k, expiration) ⇒ Object
Add the trusted key with the given expiration time.
- .anchor_verifier ⇒ Object
-
.clear_trust_anchors ⇒ Object
Wipes the cache of trusted keys.
- .clear_trusted_keys ⇒ Object
- .default_resolver ⇒ Object
-
.default_resolver=(res) ⇒ Object
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.
- .dlv_verifier ⇒ Object
-
.do_validation_with_recursor(on) ⇒ Object
This method defines the choice of Resolver or Recursor, when the validator is checking responses.
- .do_validation_with_recursor? ⇒ Boolean
- .no_keys? ⇒ Boolean
-
.remove_trust_anchor(t) ⇒ Object
Remove the trusted key.
- .reset ⇒ Object
- .root_verifier ⇒ Object
- .set_hints(hints) ⇒ Object
- .trust_anchors ⇒ Object
-
.try_validation(last_level, last_error, last_error_level, proc, msg, query) ⇒ Object
:nodoc:.
-
.validate(msg) ⇒ Object
Returns true for secure/insecure, false otherwise This method will set the security_level on msg to the appropriate value.
- .validate_with_anchors(msg, query) ⇒ Object
- .validate_with_dlv(msg, query) ⇒ Object
- .validate_with_query(query, msg) ⇒ Object
- .validate_with_root(msg, query) ⇒ Object
- .validation_policy ⇒ Object
- .validation_policy=(p) ⇒ Object
- .verify(msg, keys = nil) ⇒ Object
- .verify_rrset(rrset, keys = nil) ⇒ Object
Class Method Details
.add_dlv_key(dlv_key) ⇒ Object
Add a trusted Key Signing Key for the ISC DLV registry.
94 95 96 |
# File 'lib/dnsruby/dnssec.rb', line 94 def Dnssec.add_dlv_key(dlv_key) @@dlv_verifier.add_dlv_key(dlv_key) end |
.add_trust_anchor(t) ⇒ Object
Add a new trust anchor
98 99 100 101 |
# File 'lib/dnsruby/dnssec.rb', line 98 def Dnssec.add_trust_anchor(t) # @TODO@ Create a new verifier? @@anchor_verifier.add_trust_anchor(t) end |
.add_trust_anchor_with_expiration(k, expiration) ⇒ Object
Add the trusted key with the given expiration time
103 104 105 106 |
# File 'lib/dnsruby/dnssec.rb', line 103 def self.add_trust_anchor_with_expiration(k, expiration) # Create a new verifier? @@anchor_verifier.add_trust_anchor_with_expiration(k, expiration) end |
.anchor_verifier ⇒ Object
301 302 303 |
# File 'lib/dnsruby/dnssec.rb', line 301 def self.anchor_verifier return @@anchor_verifier end |
.clear_trust_anchors ⇒ Object
Wipes the cache of trusted keys
112 113 114 |
# File 'lib/dnsruby/dnssec.rb', line 112 def self.clear_trust_anchors @@anchor_verifier.clear_trust_anchors end |
.clear_trusted_keys ⇒ Object
120 121 122 123 124 |
# File 'lib/dnsruby/dnssec.rb', line 120 def self.clear_trusted_keys [@@anchor_verifier, @@root_verifier, @@dlv_verifier].each {|v| v.clear_trusted_keys } end |
.default_resolver ⇒ Object
175 176 177 |
# File 'lib/dnsruby/dnssec.rb', line 175 def self.default_resolver return @@default_resolver end |
.default_resolver=(res) ⇒ Object
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.
172 173 174 |
# File 'lib/dnsruby/dnssec.rb', line 172 def self.default_resolver=(res) @@default_resolver = res end |
.dlv_verifier ⇒ Object
304 305 306 |
# File 'lib/dnsruby/dnssec.rb', line 304 def self.dlv_verifier return @@dlv_verifier end |
.do_validation_with_recursor(on) ⇒ Object
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.
162 163 164 |
# File 'lib/dnsruby/dnssec.rb', line 162 def self.do_validation_with_recursor(on) @@do_validation_with_recursor = on end |
.do_validation_with_recursor? ⇒ Boolean
165 166 167 |
# File 'lib/dnsruby/dnssec.rb', line 165 def self.do_validation_with_recursor? return @@do_validation_with_recursor end |
.no_keys? ⇒ Boolean
145 146 147 148 149 150 151 152 153 154 |
# File 'lib/dnsruby/dnssec.rb', line 145 def self.no_keys? no_keys = true [@@anchor_verifier, @@root_verifier, @@dlv_verifier].each {|v| if (v.trusted_keys.length() > 0 || v.trust_anchors.length() > 0) no_keys = false end } return no_keys end |
.remove_trust_anchor(t) ⇒ Object
Remove the trusted key
108 109 110 |
# File 'lib/dnsruby/dnssec.rb', line 108 def Dnssec.remove_trust_anchor(t) @@anchor_verifier.remove_trust_anchor(t) end |
.reset ⇒ Object
126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/dnsruby/dnssec.rb', line 126 def self.reset @@validation_policy = ValidationPolicy::LOCAL_ANCHORS_THEN_ROOT @@root_verifier = SingleVerifier.new(SingleVerifier::VerifierType::ROOT) @@root_verifier.add_root_ds(@@root_key) @@root_verifier.add_root_ds(@@root_key_new) @@dlv_verifier = SingleVerifier.new(SingleVerifier::VerifierType::DLV) # @TODO@ Could add a new one of these for each anchor. @@anchor_verifier = SingleVerifier.new(SingleVerifier::VerifierType::ANCHOR) @@do_validation_with_recursor = true # Many nameservers don't handle DNSSEC correctly yet @@default_resolver = Resolver.new end |
.root_verifier ⇒ Object
307 308 309 |
# File 'lib/dnsruby/dnssec.rb', line 307 def self.root_verifier return @@root_verifier end |
.set_hints(hints) ⇒ Object
140 141 142 143 |
# File 'lib/dnsruby/dnssec.rb', line 140 def self.set_hints(hints) @@root_verifier.set_hints(hints) @@anchor_verifier.set_hints(hints) end |
.trust_anchors ⇒ Object
116 117 118 |
# File 'lib/dnsruby/dnssec.rb', line 116 def self.trust_anchors return @@anchor_verifier.trust_anchors end |
.try_validation(last_level, last_error, last_error_level, proc, msg, query) ⇒ Object
:nodoc:
264 265 266 267 268 269 270 271 272 273 274 275 |
# File 'lib/dnsruby/dnssec.rb', line 264 def self.try_validation(last_level, last_error, last_error_level, proc, msg, query) # :nodoc: begin proc.call(msg, query) last_level = Message::SecurityLevel.new([msg.security_level.code, last_level.code].max) rescue VerifyError => e if (last_error_level < last_level) last_error = e.to_s last_error_level = last_level end end return last_level, last_error, last_error_level end |
.validate(msg) ⇒ Object
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.
184 185 186 187 188 |
# File 'lib/dnsruby/dnssec.rb', line 184 def self.validate(msg) query = Message.new() query.header.cd=true return self.validate_with_query(query, msg) end |
.validate_with_anchors(msg, query) ⇒ Object
277 278 279 |
# File 'lib/dnsruby/dnssec.rb', line 277 def self.validate_with_anchors(msg, query) return @@anchor_verifier.validate(msg, query) end |
.validate_with_dlv(msg, query) ⇒ Object
285 286 287 |
# File 'lib/dnsruby/dnssec.rb', line 285 def self.validate_with_dlv(msg, query) return @@dlv_verifier.validate(msg, query) end |
.validate_with_query(query, msg) ⇒ Object
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 |
# File 'lib/dnsruby/dnssec.rb', line 190 def self.validate_with_query(query, msg) if (!msg) return false end # First, just check there is something to validate! found_sigs = false msg.each_resource {|rr| if (rr.type == Types::RRSIG) found_sigs = true end } if (found_sigs) begin if (verify(msg)) msg.security_level = Message::SecurityLevel.SECURE return true end rescue VerifyError => e msg.security_error = e msg.security_level = Message::SecurityLevel.BOGUS end end # SHOULD ALWAYS VERIFY DNSSEC-SIGNED RESPONSES? # Yes - if a trust anchor is configured. Otherwise, act on CD bit (in query) TheLog.debug("Checking whether to validate, query.cd = #{query.header.cd}") if (((@@validation_policy > ValidationPolicy::ALWAYS_ROOT_ONLY) && (self.trust_anchors().length > 0)) || # Check query here, and validate if CD is true ((query.header.cd == true))) # && (query.do_validation))) TheLog.debug("Starting validation") # Validate! # Need to think about trapping/storing exceptions and security_levels here last_error = "" last_level = Message::SecurityLevel.BOGUS last_error_level = Message::SecurityLevel.BOGUS if (@@validation_policy == ValidationPolicy::ALWAYS_LOCAL_ANCHORS_ONLY) last_level, last_error, last_error_level = try_validation(last_level, last_error, last_error_level, Proc.new{|m, q| validate_with_anchors(m, q)}, msg, query) elsif (@@validation_policy == ValidationPolicy::ALWAYS_ROOT_ONLY) last_level, last_error, last_error_level = try_validation(last_level, last_error, last_error_level, Proc.new{|m, q| validate_with_root(m, q)}, msg, query) elsif (@@validation_policy == ValidationPolicy::LOCAL_ANCHORS_THEN_ROOT) last_level, last_error, last_error_level = try_validation(last_level, last_error, last_error_level, Proc.new{|m, q| validate_with_anchors(m, q)}, msg, query) if (last_level != Message::SecurityLevel.SECURE) last_level, last_error, last_error_level = try_validation(last_level, last_error, last_error_level, Proc.new{|m, q| validate_with_root(m, q)}, msg, query) end elsif (@@validation_policy == ValidationPolicy::ROOT_THEN_LOCAL_ANCHORS) last_level, last_error, last_error_level = try_validation(last_level, last_error, last_error_level, Proc.new{|m, q| validate_with_root(m, q)}, msg, query) if (last_level != Message::SecurityLevel.SECURE) last_level, last_error, last_error_level = try_validation(last_level, last_error, last_error_level, Proc.new{|m, q| validate_with_anchors(m, q)}, msg, query) end end if (last_level != Message::SecurityLevel.SECURE && last_level != Message::SecurityLevel.BOGUS) last_level, last_error, last_error_level = try_validation(last_level, last_error, last_error_level, Proc.new{|m, q| validate_with_dlv(m, q)}, msg, query) end # Set the message security level! msg.security_level = last_level msg.security_error = last_error if (last_error && last_error.index("ification error")) msg.security_level = Message::SecurityLevel.BOGUS end raise VerifyError.new(last_error) if (last_level < 0) return (msg.security_level.code > Message::SecurityLevel::UNCHECKED) end msg.security_level = Message::SecurityLevel.UNCHECKED return true end |
.validate_with_root(msg, query) ⇒ Object
281 282 283 |
# File 'lib/dnsruby/dnssec.rb', line 281 def self.validate_with_root(msg, query) return @@root_verifier.validate(msg, query) end |
.validation_policy ⇒ Object
73 74 75 |
# File 'lib/dnsruby/dnssec.rb', line 73 def Dnssec.validation_policy @@validation_policy end |
.validation_policy=(p) ⇒ Object
67 68 69 70 71 72 |
# File 'lib/dnsruby/dnssec.rb', line 67 def Dnssec.validation_policy=(p) if ((p >= ValidationPolicy::ALWAYS_ROOT_ONLY) && (p <= ValidationPolicy::ALWAYS_LOCAL_ANCHORS_ONLY)) @@validation_policy = p # @TODO@ Should we be clearing the trusted keys now? end end |
.verify(msg, keys = nil) ⇒ Object
289 290 291 292 293 294 295 296 297 298 299 |
# File 'lib/dnsruby/dnssec.rb', line 289 def self.verify(msg, keys=nil) begin return true if @@anchor_verifier.verify(msg, keys) rescue VerifyError begin return true if @@root_verifier.verify(msg, keys) rescue VerifyError return true if @@dlv_verifier.verify(msg, keys) # Will carry error to client end end end |
.verify_rrset(rrset, keys = nil) ⇒ Object
314 315 316 317 318 |
# File 'lib/dnsruby/dnssec.rb', line 314 def self.verify_rrset(rrset, keys = nil) return ((@@anchor_verifier.verify_rrset(rrset, keys) || @@root_verifier.verify_rrset(rrset, keys) || @@dlv_verifier.verify_rrset(rrset, keys))) end |