RRSIG validation back to the root
This commit is contained in:
BIN
Kjqmt7v.csr
Normal file
BIN
Kjqmt7v.csr
Normal file
Binary file not shown.
38
README.md
38
README.md
@@ -20,16 +20,28 @@ ground up.
|
|||||||
|
|
||||||
# Status:
|
# Status:
|
||||||
|
|
||||||
WARNING!!! Under active development!
|
Using the client should be safe. The client is currently hardcoded to a 5 second,
|
||||||
|
timeout. I'll make this configurable if people ask for that, but this allows me
|
||||||
The client now supports timeouts (thanks mio!). Currently hardcoded to 5 seconds,
|
to move on. Please send feedback! It currently does not cache responses, if
|
||||||
I'll make this configurable if people ask for that, but this allows me to move on.
|
this is a feature you'd like earlier rather than later, post a request. The
|
||||||
|
validation of DNSSec is complete, but negative responses are not yet.
|
||||||
|
The plan is to support NSEC3 primarily, but allow NSEC records to be validated.
|
||||||
|
|
||||||
The server code is complete, the daemon supports IPv4 and IPv6, UDP and TCP.
|
The server code is complete, the daemon supports IPv4 and IPv6, UDP and TCP.
|
||||||
There currently is no way to limit TCP and AXFR operations, so it is still not
|
There currently is no way to limit TCP and AXFR operations, so it is still not
|
||||||
recommended to put into production as TCP can be used to DOS the service.
|
recommended to put into production as TCP can be used to DOS the service.
|
||||||
Master file parsing is complete and supported. There is currently no forking
|
Master file parsing is complete and supported. There is currently no forking
|
||||||
option, and the server is not yet threaded.
|
option, and the server is not yet threaded. There is still a lot of work to do
|
||||||
|
before a server can be trusted with this externally. Running it behind a firewall
|
||||||
|
on a private network would be safe.
|
||||||
|
|
||||||
|
## DNSSec status
|
||||||
|
|
||||||
|
Currently the root key is hardcoded into the system. This gives validation of
|
||||||
|
DNSKEY and DS records back to the root. NSEC and NSEC3 are not yet implemented.
|
||||||
|
Because caching is not yet enabled, it has been noticed that some DNS servers
|
||||||
|
appear to rate limit the connections, validating RRSIG records back to the root
|
||||||
|
can require a significant number of additional queries for those records.
|
||||||
|
|
||||||
## RFC's implemented
|
## RFC's implemented
|
||||||
|
|
||||||
@@ -42,6 +54,15 @@ option, and the server is not yet threaded.
|
|||||||
### Update operations
|
### Update operations
|
||||||
- [RFC 2136](https://tools.ietf.org/html/rfc2136): Dynamic Update
|
- [RFC 2136](https://tools.ietf.org/html/rfc2136): Dynamic Update
|
||||||
|
|
||||||
|
### Secure DNS operations
|
||||||
|
- [RFC 3007](https://tools.ietf.org/html/rfc3007): Secure Dynamic Update
|
||||||
|
- [RFC 4034](https://tools.ietf.org/html/rfc4034): DNSSEC Resource Records
|
||||||
|
- [RFC 4035](https://tools.ietf.org/html/rfc4035): Protocol Modifications for DNSSEC
|
||||||
|
- [RFC 4509](https://tools.ietf.org/html/rfc4509): SHA-256 in DNSSEC Delegation Signer
|
||||||
|
- [RFC 5702](https://tools.ietf.org/html/rfc5702): SHA-2 Algorithms with RSA in DNSKEY and RRSIG for DNSSEC
|
||||||
|
- [RFC 6840](https://tools.ietf.org/html/rfc6840): Clarifications and Implementation Notes for DNSSEC
|
||||||
|
- [RFC 6944](https://tools.ietf.org/html/rfc6944): DNSKEY Algorithm Implementation Status
|
||||||
|
|
||||||
## RFC's in progress or not yet implemented
|
## RFC's in progress or not yet implemented
|
||||||
|
|
||||||
### Basic operations
|
### Basic operations
|
||||||
@@ -55,14 +76,7 @@ option, and the server is not yet threaded.
|
|||||||
- [Long-Lived Queries](http://tools.ietf.org/html/draft-sekar-dns-llq-01): Notify with bells
|
- [Long-Lived Queries](http://tools.ietf.org/html/draft-sekar-dns-llq-01): Notify with bells
|
||||||
|
|
||||||
### Secure DNS operations
|
### Secure DNS operations
|
||||||
- [RFC 3007](https://tools.ietf.org/html/rfc3007): Secure Dynamic Update
|
|
||||||
- [RFC 4034](https://tools.ietf.org/html/rfc4034): DNSSEC Resource Records
|
|
||||||
- [RFC 4035](https://tools.ietf.org/html/rfc4035): Protocol Modifications for DNSSEC
|
|
||||||
- [RFC 4509](https://tools.ietf.org/html/rfc4509): SHA-256 in DNSSEC Delegation Signer
|
|
||||||
- [RFC 5155](https://tools.ietf.org/html/rfc5155): DNSSEC Hashed Authenticated Denial of Existence
|
- [RFC 5155](https://tools.ietf.org/html/rfc5155): DNSSEC Hashed Authenticated Denial of Existence
|
||||||
- [RFC 5702](https://tools.ietf.org/html/rfc5702): SHA-2 Algorithms with RSA in DNSKEY and RRSIG for DNSSEC
|
|
||||||
- [RFC 6840](https://tools.ietf.org/html/rfc6840): Clarifications and Implementation Notes for DNSSEC
|
|
||||||
- [RFC 6944](https://tools.ietf.org/html/rfc6944): DNSKEY Algorithm Implementation Status
|
|
||||||
- [RFC 6975](https://tools.ietf.org/html/rfc6975): Signaling Cryptographic Algorithm Understanding
|
- [RFC 6975](https://tools.ietf.org/html/rfc6975): Signaling Cryptographic Algorithm Understanding
|
||||||
- [DNSCrypt](https://dnscrypt.org): Trusted DNS queries
|
- [DNSCrypt](https://dnscrypt.org): Trusted DNS queries
|
||||||
- [S/MIME](https://tools.ietf.org/html/draft-ietf-dane-smime-09): Domain Names For S/MIME
|
- [S/MIME](https://tools.ietf.org/html/draft-ietf-dane-smime-09): Domain Names For S/MIME
|
||||||
|
3
root_key.sh
Executable file
3
root_key.sh
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
openssl req -text -noout -verify -in Kjqmt7v.csr -inform DER -pubkey -out src/rr/dnssec/Kjqmt7v.pem
|
54
src/rr/dnssec/Kjqmt7v.pem
Normal file
54
src/rr/dnssec/Kjqmt7v.pem
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
-----BEGIN PUBLIC KEY-----
|
||||||
|
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqAAgqVVmukLohruATNqE
|
||||||
|
5H71bb167GEmFVUs7JBtIRbQ7yBwKMUVVBRN/q/nx8uPAF3RgjQTOsBxCoEYLOH9
|
||||||
|
FK0ig7yDQ1+d8vYxMlGTGhdt8NpR5U9C5gSGDfs1lYAlD1WcxUPE/9Ucvj3oz9Bn
|
||||||
|
GSN/n8R+5ynaBoNfpFLoJemhjrwuy89WNHRlLDPPVqkDO8312XMSF5fsgIkEG24D
|
||||||
|
obctCnNbmE4DaHMJMyMk8nwtuoXp2xXoOgFDOC6XSwYhwY5iXs7JB1d9nnut6VJB
|
||||||
|
qB676KkB1NMnbkCxFMCi5vw40ZwuaqsCZEsoE/V1/CFgHg3uSc2e6WpDED5STWKH
|
||||||
|
PQIDAQAB
|
||||||
|
-----END PUBLIC KEY-----
|
||||||
|
Certificate Request:
|
||||||
|
Data:
|
||||||
|
Version: 0 (0x0)
|
||||||
|
Subject: O=ICANN, OU=IANA, CN=Root Zone KSK 2010-06-16T21:19:24+00:00/1.3.6.1.4.1.1000.53=. IN DS 19036 8 2 49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5
|
||||||
|
Subject Public Key Info:
|
||||||
|
Public Key Algorithm: rsaEncryption
|
||||||
|
Public-Key: (2048 bit)
|
||||||
|
Modulus:
|
||||||
|
00:a8:00:20:a9:55:66:ba:42:e8:86:bb:80:4c:da:
|
||||||
|
84:e4:7e:f5:6d:bd:7a:ec:61:26:15:55:2c:ec:90:
|
||||||
|
6d:21:16:d0:ef:20:70:28:c5:15:54:14:4d:fe:af:
|
||||||
|
e7:c7:cb:8f:00:5d:d1:82:34:13:3a:c0:71:0a:81:
|
||||||
|
18:2c:e1:fd:14:ad:22:83:bc:83:43:5f:9d:f2:f6:
|
||||||
|
31:32:51:93:1a:17:6d:f0:da:51:e5:4f:42:e6:04:
|
||||||
|
86:0d:fb:35:95:80:25:0f:55:9c:c5:43:c4:ff:d5:
|
||||||
|
1c:be:3d:e8:cf:d0:67:19:23:7f:9f:c4:7e:e7:29:
|
||||||
|
da:06:83:5f:a4:52:e8:25:e9:a1:8e:bc:2e:cb:cf:
|
||||||
|
56:34:74:65:2c:33:cf:56:a9:03:3b:cd:f5:d9:73:
|
||||||
|
12:17:97:ec:80:89:04:1b:6e:03:a1:b7:2d:0a:73:
|
||||||
|
5b:98:4e:03:68:73:09:33:23:24:f2:7c:2d:ba:85:
|
||||||
|
e9:db:15:e8:3a:01:43:38:2e:97:4b:06:21:c1:8e:
|
||||||
|
62:5e:ce:c9:07:57:7d:9e:7b:ad:e9:52:41:a8:1e:
|
||||||
|
bb:e8:a9:01:d4:d3:27:6e:40:b1:14:c0:a2:e6:fc:
|
||||||
|
38:d1:9c:2e:6a:ab:02:64:4b:28:13:f5:75:fc:21:
|
||||||
|
60:1e:0d:ee:49:cd:9e:e9:6a:43:10:3e:52:4d:62:
|
||||||
|
87:3d
|
||||||
|
Exponent: 65537 (0x10001)
|
||||||
|
Attributes:
|
||||||
|
a0:00
|
||||||
|
Signature Algorithm: sha256WithRSAEncryption
|
||||||
|
10:92:6a:79:8f:e9:e4:90:86:8c:d0:51:ac:2d:c9:9f:53:d3:
|
||||||
|
3a:79:e9:15:e8:ca:26:de:08:bd:d2:cd:83:da:ac:d3:e6:bc:
|
||||||
|
54:8b:f9:09:d9:27:b1:6a:ec:fa:b4:7a:4a:f6:97:80:a4:25:
|
||||||
|
80:b6:55:b2:1c:6a:a7:8f:5d:21:a8:57:ad:2e:bd:c9:37:50:
|
||||||
|
70:b7:8b:e0:1b:60:ed:a4:83:0d:d4:d6:13:0f:c9:cb:0a:8f:
|
||||||
|
76:80:eb:23:6f:01:0f:ba:09:20:2b:79:57:e1:18:8f:9a:dc:
|
||||||
|
72:18:6d:76:84:e7:71:72:f1:49:d7:ac:15:2a:51:27:e9:b4:
|
||||||
|
cd:47:ae:18:36:21:fc:88:d6:78:1e:3d:95:eb:81:d4:ad:24:
|
||||||
|
f7:cc:87:d0:73:91:41:f2:44:cd:a3:35:20:0a:07:a4:f0:de:
|
||||||
|
10:04:de:24:b7:9e:1d:1c:24:0a:ee:ca:71:da:ff:2c:f6:4f:
|
||||||
|
c3:f8:0f:57:6d:33:cb:8b:c1:45:73:8f:bb:f9:4c:71:0f:80:
|
||||||
|
c9:b8:15:51:51:17:03:fb:9b:b2:ea:ec:ae:31:a3:ce:0e:7b:
|
||||||
|
c9:d6:ac:65:b9:ec:8e:90:c8:94:e3:37:30:eb:fc:7f:cf:3a:
|
||||||
|
fd:59:7a:d7:7c:9e:0e:01:79:4e:52:0b:78:00:6f:fd:08:eb:
|
||||||
|
8c:56:1c:8f
|
@@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
use openssl::crypto::pkey::{PKey, Role};
|
use openssl::crypto::pkey::{PKey, Role};
|
||||||
use openssl::crypto::rsa::RSA;
|
use openssl::crypto::rsa::RSA;
|
||||||
use openssl::crypto::hash;
|
|
||||||
use openssl::bn::BigNum;
|
use openssl::bn::BigNum;
|
||||||
|
|
||||||
use ::rr::dnssec::DigestType;
|
use ::rr::dnssec::DigestType;
|
||||||
|
@@ -18,9 +18,11 @@ mod digest_type;
|
|||||||
mod nsec3;
|
mod nsec3;
|
||||||
mod signer;
|
mod signer;
|
||||||
mod supported_algorithm;
|
mod supported_algorithm;
|
||||||
|
mod trust_anchor;
|
||||||
|
|
||||||
pub use self::algorithm::Algorithm;
|
pub use self::algorithm::Algorithm;
|
||||||
pub use self::digest_type::DigestType;
|
pub use self::digest_type::DigestType;
|
||||||
pub use self::nsec3::Nsec3HashAlgorithm;
|
pub use self::nsec3::Nsec3HashAlgorithm;
|
||||||
pub use self::signer::Signer;
|
pub use self::signer::Signer;
|
||||||
pub use self::supported_algorithm::SupportedAlgorithms;
|
pub use self::supported_algorithm::SupportedAlgorithms;
|
||||||
|
pub use self::trust_anchor::TrustAnchor;
|
||||||
|
40
src/rr/dnssec/trust_anchor.rs
Normal file
40
src/rr/dnssec/trust_anchor.rs
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Benjamin Fry <benjaminfry@me.com>
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
use openssl::crypto::pkey::{PKey, Role};
|
||||||
|
|
||||||
|
use ::rr::dnssec::Algorithm;
|
||||||
|
|
||||||
|
const ROOT_ANCHOR: &'static str = include_str!("Kjqmt7v.pem");
|
||||||
|
|
||||||
|
pub struct TrustAnchor {
|
||||||
|
pkey: Vec<u8>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TrustAnchor {
|
||||||
|
pub fn new() -> TrustAnchor {
|
||||||
|
let mut cursor = Cursor::new(ROOT_ANCHOR);
|
||||||
|
let pkey = PKey::public_key_from_pem(&mut cursor).expect("Error parsing Kjqmt7v.pem");
|
||||||
|
let alg = Algorithm::RSASHA256;
|
||||||
|
|
||||||
|
TrustAnchor{ pkey: alg.public_key_to_vec(&pkey) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn contains(&self, other_key: &[u8]) -> bool {
|
||||||
|
self.pkey == other_key
|
||||||
|
}
|
||||||
|
}
|
@@ -26,7 +26,7 @@ use openssl::crypto::pkey::Role;
|
|||||||
use ::error::*;
|
use ::error::*;
|
||||||
use ::rr::{DNSClass, RecordType, Record, RData};
|
use ::rr::{DNSClass, RecordType, Record, RData};
|
||||||
use ::rr::domain;
|
use ::rr::domain;
|
||||||
use ::rr::dnssec::Signer;
|
use ::rr::dnssec::{Signer, TrustAnchor};
|
||||||
use ::op::{ Message, MessageType, OpCode, Query, Edns, ResponseCode };
|
use ::op::{ Message, MessageType, OpCode, Query, Edns, ResponseCode };
|
||||||
use ::serialize::binary::*;
|
use ::serialize::binary::*;
|
||||||
|
|
||||||
@@ -72,6 +72,7 @@ impl<A: ToSocketAddrs + Copy> Client<A> {
|
|||||||
// the RRSIG is signed by the DNSKEY, the DNSKEY is signed by the DS record in the Parent
|
// the RRSIG is signed by the DNSKEY, the DNSKEY is signed by the DS record in the Parent
|
||||||
// zone. The key_tag is the DS record is assigned to the DNSKEY.
|
// zone. The key_tag is the DS record is assigned to the DNSKEY.
|
||||||
let record_response = try!(self.inner_query(name, query_class, query_type, true));
|
let record_response = try!(self.inner_query(name, query_class, query_type, true));
|
||||||
|
{
|
||||||
let rrsigs: Vec<&Record> = record_response.get_answers().iter().filter(|rr| rr.get_rr_type() == RecordType::RRSIG).collect();
|
let rrsigs: Vec<&Record> = record_response.get_answers().iter().filter(|rr| rr.get_rr_type() == RecordType::RRSIG).collect();
|
||||||
|
|
||||||
if rrsigs.is_empty() {
|
if rrsigs.is_empty() {
|
||||||
@@ -95,18 +96,20 @@ impl<A: ToSocketAddrs + Copy> Client<A> {
|
|||||||
// the '.' DNSKEY is signed by the well known root certificate.
|
// the '.' DNSKEY is signed by the well known root certificate.
|
||||||
// TODO fix rrsigs clone()
|
// TODO fix rrsigs clone()
|
||||||
let proof = try!(self.recursive_query_verify(&name, rrset, rrsigs.clone(), query_type, query_class));
|
let proof = try!(self.recursive_query_verify(&name, rrset, rrsigs.clone(), query_type, query_class));
|
||||||
|
|
||||||
|
// TODO return this, also make a prettier print
|
||||||
debug!("proved existance through: {:?}", proof);
|
debug!("proved existance through: {:?}", proof);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// verify each RRSIG...
|
// getting here means that we looped through all records with validation
|
||||||
unimplemented!()
|
Ok(record_response)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Verifies a record set against the supplied signatures, looking up the DNSKey chain.
|
/// Verifies a record set against the supplied signatures, looking up the DNSKey chain.
|
||||||
/// returns the chain of proof or an error if there is none.
|
/// returns the chain of proof or an error if there is none.
|
||||||
fn recursive_query_verify(&self, name: &domain::Name, rrset: Vec<&Record>, rrsigs: Vec<&Record>,
|
fn recursive_query_verify(&self, name: &domain::Name, rrset: Vec<&Record>, rrsigs: Vec<&Record>,
|
||||||
query_type: RecordType, query_class: DNSClass) -> ClientResult<Vec<Record>> {
|
query_type: RecordType, query_class: DNSClass) -> ClientResult<Vec<Record>> {
|
||||||
debug!("verifying: {} type: {:?}", name, query_type);
|
|
||||||
|
|
||||||
// TODO: this is ugly, what reference do I want?
|
// TODO: this is ugly, what reference do I want?
|
||||||
let rrset: Vec<Record> = rrset.iter().map(|rr|rr.clone()).cloned().collect();
|
let rrset: Vec<Record> = rrset.iter().map(|rr|rr.clone()).cloned().collect();
|
||||||
@@ -119,6 +122,7 @@ impl<A: ToSocketAddrs + Copy> Client<A> {
|
|||||||
// but how do you know which needs to be validated with the DS in the parent zone?
|
// but how do you know which needs to be validated with the DS in the parent zone?
|
||||||
if zone_key && secure_entry_point {
|
if zone_key && secure_entry_point {
|
||||||
let mut proof = try!(self.verify_dnskey(record));
|
let mut proof = try!(self.verify_dnskey(record));
|
||||||
|
// TODO: this is verified, it can be cached
|
||||||
proof.push(record.clone());
|
proof.push(record.clone());
|
||||||
return Ok(proof);
|
return Ok(proof);
|
||||||
}
|
}
|
||||||
@@ -138,26 +142,26 @@ impl<A: ToSocketAddrs + Copy> Client<A> {
|
|||||||
|
|
||||||
for dnskey in key_rrset.iter() {
|
for dnskey in key_rrset.iter() {
|
||||||
if let &RData::DNSKEY{zone_key, algorithm, revoke, ref public_key, ..} = dnskey.get_rdata() {
|
if let &RData::DNSKEY{zone_key, algorithm, revoke, ref public_key, ..} = dnskey.get_rdata() {
|
||||||
if revoke { debug!("revoked"); continue } // TODO: does this need to be validated? RFC 5011
|
if revoke { debug!("revoked: {}", dnskey.get_name()); continue } // TODO: does this need to be validated? RFC 5011
|
||||||
if !zone_key { debug!("not a zone_key, can't use"); continue }
|
if !zone_key { continue }
|
||||||
if algorithm != sig_alg { debug!("algorithms don't match"); continue }
|
if algorithm != sig_alg { continue }
|
||||||
|
|
||||||
let pkey = try!(algorithm.public_key_from_vec(public_key));
|
let pkey = try!(algorithm.public_key_from_vec(public_key));
|
||||||
if !pkey.can(Role::Verify) { debug!("pkey can't verify"); continue }
|
if !pkey.can(Role::Verify) { debug!("pkey can't verify, {:?}", dnskey.get_name()); continue }
|
||||||
|
|
||||||
let signer: Signer = Signer::new(algorithm, pkey, signer_name.clone());
|
let signer: Signer = Signer::new(algorithm, pkey, signer_name.clone());
|
||||||
let rrset_hash: Vec<u8> = signer.hash_rrset(rrsig, &rrset);
|
let rrset_hash: Vec<u8> = signer.hash_rrset(rrsig, &rrset);
|
||||||
|
|
||||||
if signer.verify(&rrset_hash, sig) {
|
if signer.verify(&rrset_hash, sig) {
|
||||||
debug!("verified: {} with: {}", name, dnskey.get_name());
|
|
||||||
|
|
||||||
if signer_name == name && query_type == RecordType::DNSKEY {
|
if signer_name == name && query_type == RecordType::DNSKEY {
|
||||||
// this is self signed... let's skip to DS validation
|
// this is self signed... let's skip to DS validation
|
||||||
let mut proof: Vec<Record> = try!(self.verify_dnskey(dnskey));
|
let mut proof: Vec<Record> = try!(self.verify_dnskey(dnskey));
|
||||||
|
// TODO: this is verified, cache it
|
||||||
proof.push((*dnskey).clone());
|
proof.push((*dnskey).clone());
|
||||||
return Ok(proof);
|
return Ok(proof);
|
||||||
} else {
|
} else {
|
||||||
let mut proof = try!(self.recursive_query_verify(&signer_name, key_rrset.clone(), key_rrsigs, RecordType::DNSKEY, query_class));
|
let mut proof = try!(self.recursive_query_verify(&signer_name, key_rrset.clone(), key_rrsigs, RecordType::DNSKEY, query_class));
|
||||||
|
// TODO: this is verified, cache it
|
||||||
proof.push((*dnskey).clone());
|
proof.push((*dnskey).clone());
|
||||||
return Ok(proof);
|
return Ok(proof);
|
||||||
}
|
}
|
||||||
@@ -179,9 +183,16 @@ impl<A: ToSocketAddrs + Copy> Client<A> {
|
|||||||
/// attempts to verify the DNSKey against the DS of the parent.
|
/// attempts to verify the DNSKey against the DS of the parent.
|
||||||
/// returns the chain of proof or an error if there is none.
|
/// returns the chain of proof or an error if there is none.
|
||||||
fn verify_dnskey(&self, dnskey: &Record) -> ClientResult<Vec<Record>> {
|
fn verify_dnskey(&self, dnskey: &Record) -> ClientResult<Vec<Record>> {
|
||||||
debug!("verifying dnskey");
|
|
||||||
let name: &domain::Name = dnskey.get_name();
|
let name: &domain::Name = dnskey.get_name();
|
||||||
|
|
||||||
|
if dnskey.get_name().is_root() {
|
||||||
|
if let &RData::DNSKEY{ ref public_key, .. } = dnskey.get_rdata() {
|
||||||
|
if TrustAnchor::new().contains(public_key) {
|
||||||
|
return Ok(vec![dnskey.clone()])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let ds_response = try!(self.inner_query(&name, dnskey.get_dns_class(), RecordType::DS, true));
|
let ds_response = try!(self.inner_query(&name, dnskey.get_dns_class(), RecordType::DS, true));
|
||||||
let ds_rrset: Vec<&Record> = ds_response.get_answers().iter().filter(|rr| rr.get_rr_type() == RecordType::DS).collect();
|
let ds_rrset: Vec<&Record> = ds_response.get_answers().iter().filter(|rr| rr.get_rr_type() == RecordType::DS).collect();
|
||||||
let ds_rrsigs: Vec<&Record> = ds_response.get_answers().iter().filter(|rr| rr.get_rr_type() == RecordType::RRSIG).collect();
|
let ds_rrsigs: Vec<&Record> = ds_response.get_answers().iter().filter(|rr| rr.get_rr_type() == RecordType::RRSIG).collect();
|
||||||
@@ -217,7 +228,9 @@ impl<A: ToSocketAddrs + Copy> Client<A> {
|
|||||||
let hash: Vec<u8> = digest_type.hash(&buf);
|
let hash: Vec<u8> = digest_type.hash(&buf);
|
||||||
if &hash == digest {
|
if &hash == digest {
|
||||||
// continue to verify the chain...
|
// continue to verify the chain...
|
||||||
return self.recursive_query_verify(&name, ds_rrset.clone(), ds_rrsigs, RecordType::DNSKEY, dnskey.get_dns_class());
|
let mut proof: Vec<Record> = try!(self.recursive_query_verify(&name, ds_rrset.clone(), ds_rrsigs, RecordType::DNSKEY, dnskey.get_dns_class()));
|
||||||
|
proof.push(dnskey.clone());
|
||||||
|
return Ok(proof)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
panic!("expected DS: {:?}", ds.get_rr_type());
|
panic!("expected DS: {:?}", ds.get_rr_type());
|
||||||
@@ -488,36 +501,36 @@ fn test_secure_query_example() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: use this site for verifying nsec3
|
// // TODO: use this site for verifying nsec3
|
||||||
#[test]
|
// #[test]
|
||||||
#[cfg(feature = "ftest")]
|
// #[cfg(feature = "ftest")]
|
||||||
fn test_secure_query_sdsmt() {
|
// fn test_secure_query_sdsmt() {
|
||||||
use std::net::*;
|
// use std::net::*;
|
||||||
|
//
|
||||||
use ::rr::dns_class::DNSClass;
|
// use ::rr::dns_class::DNSClass;
|
||||||
use ::rr::record_type::RecordType;
|
// use ::rr::record_type::RecordType;
|
||||||
use ::rr::domain;
|
// use ::rr::domain;
|
||||||
use ::rr::record_data::RData;
|
// use ::rr::record_data::RData;
|
||||||
use ::udp::Client;
|
// use ::udp::Client;
|
||||||
|
//
|
||||||
let name = domain::Name::with_labels(vec!["www".to_string(), "sdsmt".to_string(), "edu".to_string()]);
|
// let name = domain::Name::with_labels(vec!["www".to_string(), "sdsmt".to_string(), "edu".to_string()]);
|
||||||
let client = Client::new(("8.8.8.8").parse().unwrap()).unwrap();
|
// let client = Client::new(("8.8.8.8").parse().unwrap()).unwrap();
|
||||||
|
//
|
||||||
let response = client.secure_query(&name, DNSClass::IN, RecordType::A);
|
// let response = client.secure_query(&name, DNSClass::IN, RecordType::A);
|
||||||
assert!(response.is_ok(), "query failed: {}", response.unwrap_err());
|
// assert!(response.is_ok(), "query failed: {}", response.unwrap_err());
|
||||||
|
//
|
||||||
let response = response.unwrap();
|
// let response = response.unwrap();
|
||||||
|
//
|
||||||
println!("response records: {:?}", response);
|
// println!("response records: {:?}", response);
|
||||||
|
//
|
||||||
let record = &response.get_answers()[0];
|
// let record = &response.get_answers()[0];
|
||||||
assert_eq!(record.get_name(), &name);
|
// assert_eq!(record.get_name(), &name);
|
||||||
assert_eq!(record.get_rr_type(), RecordType::A);
|
// assert_eq!(record.get_rr_type(), RecordType::A);
|
||||||
assert_eq!(record.get_dns_class(), DNSClass::IN);
|
// assert_eq!(record.get_dns_class(), DNSClass::IN);
|
||||||
|
//
|
||||||
if let &RData::A{ ref address } = record.get_rdata() {
|
// if let &RData::A{ ref address } = record.get_rdata() {
|
||||||
assert_eq!(address, &Ipv4Addr::new(93,184,216,34))
|
// assert_eq!(address, &Ipv4Addr::new(93,184,216,34))
|
||||||
} else {
|
// } else {
|
||||||
assert!(false);
|
// assert!(false);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
Reference in New Issue
Block a user