feature matrix for tests (#95)

* feature matrix for tests

* make tls optional in client

* fix matrix default options

* fix coverage

* fix path references for coverage reports

* remove min version, not passing

* add Changelog messages
This commit is contained in:
Benjamin Fry 2017-02-27 23:08:16 -08:00 committed by GitHub
parent 1a19072744
commit 74a001f89c
16 changed files with 419 additions and 341 deletions

View File

@ -1,19 +1,43 @@
sudo: required
dist: trusty
language: rust
rust: stable
cache: cargo
matrix:
include:
- os: osx
rust: stable
# optional feature variations
# we want full coverage, include all features...
- rust: stable
env: RUN_KCOV=1
OPTIONS="--all-features"
# no features
- rust: stable
env: MODULES="client"
CLIENT_OPTIONS="--no-default-features"
# default features...
- rust: stable
env: MODULES="client"
# just openssl
- rust: stable
env: MODULES="client"
CLIENT_OPTIONS="--no-default-features --features=openssl"
# just ring
- rust: stable
env: MODULES="client"
CLIENT_OPTIONS="--no-default-features --features=ring"
# min rust version
- rust: 1.13.0
# - rust: 1.14.0
- rust: beta
- rust: nightly
- os: osx
rust: stable
allow_failure:
- rust: nightly

View File

@ -14,6 +14,7 @@ are both synchronous implementations of the old Client function interfaces.
Please read those docs on those new types and the Client trait.
- When EDNS option is present, return only the digest understood matching RRSETs
- All code reformatted with rustfmt
- *Important* breaking change, all `Record` and associated types have been migrated to [RFC#344](https://github.com/aturon/rfcs/blob/conventions-galore/active/0000-conventions-galore.md#gettersetter-apis) style. `get_field()` -> `field()`; `field()` -> `set_field()`
### Removed
- *Important* The original Server implementation was removed entirely. Please
@ -26,6 +27,7 @@ and there is no easy way to migrate the original Server to use ServerFuture.
- additional config options for keys to named, see `tests/named_test_configs/example.toml`
- Added DNS over TLS support, RFC 7858, #38
- Added native-tls with support for macOS and Linux (DNS over TLS)
- matrixed tests for all features to Travis
## 0.9.3
### Changed

View File

@ -37,7 +37,8 @@ license = "MIT/Apache-2.0"
build = "build.rs"
[features]
default = ["openssl"]
default = ["openssl", "tls"]
tls = ["native-tls", "tokio-tls", "security-framework"]
[lib]
name = "trust_dns"
@ -51,15 +52,22 @@ error-chain = "0.1.12"
futures = "^0.1.6"
lazy_static = "^0.2.1"
log = "^0.3.5"
native-tls = "^0.1"
native-tls = { version = "^0.1", optional = true }
openssl = { version = "^0.9.7", features = ["v102", "v110"], optional = true }
rand = "^0.3"
ring = { version = "^0.6", optional = true }
rustc-serialize = "^0.3.18"
time = "^0.1"
tokio-core = "^0.1"
tokio-tls = "^0.1"
tokio-tls = { version = "^0.1", optional = true }
untrusted = "^0.3"
[dev-dependencies]
openssl = "^0.9.7"
native-tls = "^0.1"
[target.'cfg(target_os = "macos")'.dependencies]
security-framework = { version = "^0.1.10", optional = true }
[target.'cfg(target_os = "macos")'.dev-dependencies]
security-framework = "^0.1.10"

View File

@ -22,7 +22,7 @@ use client::{ClientHandle, BasicClientHandle, ClientConnection, ClientFuture, Se
use ::error::*;
use rr::{domain, DNSClass, IntoRecordSet, RecordType, Record};
use rr::dnssec::Signer;
#[cfg(feature = "openssl")]
#[cfg(any(feature = "openssl", feature = "ring"))]
use rr::dnssec::TrustAnchor;
use op::Message;
@ -390,13 +390,13 @@ impl Client<BasicClientHandle> for SyncClient {
}
}
#[cfg(feature = "openssl")]
#[cfg(any(feature = "openssl", feature = "ring"))]
pub struct SecureSyncClient {
client_handle: RefCell<SecureClientHandle<BasicClientHandle>>,
io_loop: RefCell<Core>,
}
#[cfg(feature = "openssl")]
#[cfg(any(feature = "openssl", feature = "ring"))]
impl SecureSyncClient {
/// Creates a new DNS client with the specified connection type
///
@ -433,8 +433,7 @@ impl SecureSyncClient {
/// * `query_name` - the label to lookup
/// * `query_class` - most likely this should always be DNSClass::IN
/// * `query_type` - record type to lookup
#[cfg(feature = "openssl")]
#[deprecated = "just use query from `Client`"]
#[deprecated = "just use query(...) from `Client`"]
pub fn secure_query(&self,
query_name: &domain::Name,
query_class: DNSClass,
@ -445,7 +444,7 @@ impl SecureSyncClient {
}
}
#[cfg(feature = "openssl")]
#[cfg(any(feature = "openssl", feature = "ring"))]
impl Client<SecureClientHandle<BasicClientHandle>> for SecureSyncClient {
fn get_io_loop(&self) -> RefMut<Core> {
self.io_loop.borrow_mut()
@ -456,6 +455,7 @@ impl Client<SecureClientHandle<BasicClientHandle>> for SecureSyncClient {
}
}
#[cfg(any(feature = "openssl", feature = "ring"))]
pub struct SecureSyncClientBuilder<CC>
where CC: ClientConnection,
<CC as ClientConnection>::MessageStream: Stream<Item=Vec<u8>, Error=io::Error> + 'static {
@ -464,6 +464,7 @@ where CC: ClientConnection,
signer: Option<Signer>,
}
#[cfg(any(feature = "openssl", feature = "ring"))]
impl<CC> SecureSyncClientBuilder<CC>
where CC: ClientConnection,
<CC as ClientConnection>::MessageStream: Stream<Item=Vec<u8>, Error=io::Error> + 'static {

View File

@ -25,7 +25,9 @@ mod retry_client_handle;
mod secure_client_handle;
#[allow(deprecated)]
pub use self::client::{Client, SecureSyncClient, SyncClient};
pub use self::client::{Client, SyncClient};
#[cfg(any(feature = "openssl", feature = "ring"))]
pub use self::client::SecureSyncClient;
pub use self::client_connection::ClientConnection;
pub use self::client_future::{ClientFuture, BasicClientHandle, ClientHandle, StreamHandle,
ClientStreamHandle};

View File

@ -37,18 +37,20 @@ extern crate futures;
extern crate lazy_static;
#[macro_use]
extern crate log;
#[cfg(feature = "native-tls")]
extern crate native_tls;
#[cfg(feature = "openssl")]
#[cfg(any(feature = "openssl", all(target_os = "linux", feature = "tls")))]
extern crate openssl;
extern crate rand;
#[cfg(feature = "ring")]
extern crate ring;
extern crate rustc_serialize;
#[cfg(target_os = "macos")]
#[cfg(all(target_os = "macos", feature = "security-framework"))]
extern crate security_framework;
extern crate time;
#[macro_use]
extern crate tokio_core;
#[cfg(feature = "tokio-tls")]
extern crate tokio_tls;
#[cfg(feature = "ring")]
extern crate untrusted;
@ -59,6 +61,7 @@ pub mod logger;
pub mod op;
pub mod rr;
pub mod tcp;
#[cfg(feature = "tls")]
pub mod tls;
pub mod udp;
pub mod serialize;

View File

@ -1,5 +1,8 @@
#[cfg(feature = "openssl")]
use openssl::ec::EcKey;
#[cfg(feature = "openssl")]
use openssl::rsa::Rsa;
#[cfg(feature = "openssl")]
use openssl::symm::Cipher;
use ::error::*;
@ -47,6 +50,7 @@ impl KeyFormat {
let password = password.as_bytes();
match algorithm {
#[cfg(feature = "openssl")]
Algorithm::RSASHA1 |
Algorithm::RSASHA1NSEC3SHA1 |
Algorithm::RSASHA256 |
@ -78,6 +82,7 @@ impl KeyFormat {
return Ok(try!(KeyPair::from_rsa(key)
.map_err(|e| format!("could not tranlate RSA to KeyPair: {}", e))));
}
#[cfg(feature = "openssl")]
Algorithm::ECDSAP256SHA256 |
Algorithm::ECDSAP384SHA384 => {
let key = match self {
@ -120,6 +125,10 @@ impl KeyFormat {
}
}
}
#[cfg(not(feature = "openssl"))]
e @ _ => {
return Err(format!("unsupported Algorith, enable openssl feature: {:?}", e).into())
}
}
}
@ -129,6 +138,7 @@ impl KeyFormat {
let password = password.iter().filter(|s| !s.is_empty()).map(|s| s.as_bytes()).next();
match *key_pair {
#[cfg(feature = "openssl")]
KeyPair::EC(ref pkey) |
KeyPair::RSA(ref pkey) => {
match self {
@ -157,8 +167,7 @@ impl KeyFormat {
}
}
}
#[cfg(feature = "ring")]
KeyPair::ED25519(..) => {
#[cfg(feature = "ring")] KeyPair::ED25519(..) => {
match self {
KeyFormat::Raw => {
// to avoid accientally storing a key where there was an expectation that it was password protected
@ -179,121 +188,132 @@ impl KeyFormat {
}
}
#[test]
fn test_rsa_encode_decode_der() {
let algorithm = Algorithm::RSASHA256;
encode_decode_with_format(KeyFormat::Der, algorithm, false, true);
}
#[test]
fn test_rsa_encode_decode_pem() {
let algorithm = Algorithm::RSASHA256;
encode_decode_with_format(KeyFormat::Pem, algorithm, true, true);
}
#[test]
fn test_rsa_encode_decode_raw() {
let algorithm = Algorithm::RSASHA256;
encode_decode_with_format(KeyFormat::Raw, algorithm, false, false);
}
#[test]
fn test_ec_encode_decode_der() {
let algorithm = Algorithm::ECDSAP256SHA256;
encode_decode_with_format(KeyFormat::Der, algorithm, false, true);
}
#[test]
fn test_ec_encode_decode_pem() {
let algorithm = Algorithm::ECDSAP256SHA256;
encode_decode_with_format(KeyFormat::Pem, algorithm, true, true);
}
#[test]
fn test_ec_encode_decode_raw() {
let algorithm = Algorithm::ECDSAP256SHA256;
encode_decode_with_format(KeyFormat::Raw, algorithm, false, false);
}
#[test]
#[cfg(feature = "ring")]
fn test_ed25519_encode_decode() {
let algorithm = Algorithm::ED25519;
encode_decode_with_format(KeyFormat::Der, algorithm, false, false);
encode_decode_with_format(KeyFormat::Pem, algorithm, false, false);
encode_decode_with_format(KeyFormat::Raw, algorithm, false, true);
}
#[cfg(test)]
fn encode_decode_with_format(key_format: KeyFormat,
algorithm: Algorithm,
ok_pass: bool,
ok_empty_pass: bool) {
let keypair = KeyPair::generate(algorithm).unwrap();
let password = Some("test password");
let empty_password = Some("");
let no_password = None::<&str>;
mod tests {
pub use super::*;
encode_decode_with_password(key_format,
&keypair,
password,
password,
algorithm,
ok_pass,
true);
encode_decode_with_password(key_format,
&keypair,
empty_password,
empty_password,
algorithm,
ok_empty_pass,
true);
encode_decode_with_password(key_format,
&keypair,
no_password,
no_password,
algorithm,
ok_empty_pass,
true);
encode_decode_with_password(key_format,
&keypair,
no_password,
empty_password,
algorithm,
ok_empty_pass,
true);
encode_decode_with_password(key_format,
&keypair,
empty_password,
no_password,
algorithm,
ok_empty_pass,
true);
encode_decode_with_password(key_format,
&keypair,
password,
no_password,
algorithm,
ok_pass,
false);
}
#[cfg(test)]
fn encode_decode_with_password(key_format: KeyFormat,
keypair: &KeyPair,
en_pass: Option<&str>,
de_pass: Option<&str>,
algorithm: Algorithm,
encode: bool,
decode: bool) {
let encoded = key_format.encode_key(&keypair, en_pass);
if encode {
assert!(encoded.is_ok(), format!("{}", encoded.unwrap_err()));
let decoded = key_format.decode_key(&encoded.unwrap(), de_pass, algorithm);
assert_eq!(decoded.is_ok(), decode);
} else {
assert!(encoded.is_err());
#[test]
#[cfg(feature = "openssl")]
fn test_rsa_encode_decode_der() {
let algorithm = Algorithm::RSASHA256;
encode_decode_with_format(KeyFormat::Der, algorithm, false, true);
}
}
#[test]
#[cfg(feature = "openssl")]
fn test_rsa_encode_decode_pem() {
let algorithm = Algorithm::RSASHA256;
encode_decode_with_format(KeyFormat::Pem, algorithm, true, true);
}
#[test]
#[cfg(feature = "openssl")]
fn test_rsa_encode_decode_raw() {
let algorithm = Algorithm::RSASHA256;
encode_decode_with_format(KeyFormat::Raw, algorithm, false, false);
}
#[test]
#[cfg(feature = "openssl")]
fn test_ec_encode_decode_der() {
let algorithm = Algorithm::ECDSAP256SHA256;
encode_decode_with_format(KeyFormat::Der, algorithm, false, true);
}
#[test]
#[cfg(feature = "openssl")]
fn test_ec_encode_decode_pem() {
let algorithm = Algorithm::ECDSAP256SHA256;
encode_decode_with_format(KeyFormat::Pem, algorithm, true, true);
}
#[test]
#[cfg(feature = "openssl")]
fn test_ec_encode_decode_raw() {
let algorithm = Algorithm::ECDSAP256SHA256;
encode_decode_with_format(KeyFormat::Raw, algorithm, false, false);
}
#[test]
#[cfg(feature = "ring")]
fn test_ed25519_encode_decode() {
let algorithm = Algorithm::ED25519;
encode_decode_with_format(KeyFormat::Der, algorithm, false, false);
encode_decode_with_format(KeyFormat::Pem, algorithm, false, false);
encode_decode_with_format(KeyFormat::Raw, algorithm, false, true);
}
#[cfg(test)]
fn encode_decode_with_format(key_format: KeyFormat,
algorithm: Algorithm,
ok_pass: bool,
ok_empty_pass: bool) {
let keypair = KeyPair::generate(algorithm).unwrap();
let password = Some("test password");
let empty_password = Some("");
let no_password = None::<&str>;
encode_decode_with_password(key_format,
&keypair,
password,
password,
algorithm,
ok_pass,
true);
encode_decode_with_password(key_format,
&keypair,
empty_password,
empty_password,
algorithm,
ok_empty_pass,
true);
encode_decode_with_password(key_format,
&keypair,
no_password,
no_password,
algorithm,
ok_empty_pass,
true);
encode_decode_with_password(key_format,
&keypair,
no_password,
empty_password,
algorithm,
ok_empty_pass,
true);
encode_decode_with_password(key_format,
&keypair,
empty_password,
no_password,
algorithm,
ok_empty_pass,
true);
encode_decode_with_password(key_format,
&keypair,
password,
no_password,
algorithm,
ok_pass,
false);
}
#[cfg(test)]
fn encode_decode_with_password(key_format: KeyFormat,
keypair: &KeyPair,
en_pass: Option<&str>,
de_pass: Option<&str>,
algorithm: Algorithm,
encode: bool,
decode: bool) {
let encoded = key_format.encode_key(&keypair, en_pass);
if encode {
assert!(encoded.is_ok(), format!("{}", encoded.unwrap_err()));
let decoded = key_format.decode_key(&encoded.unwrap(), de_pass, algorithm);
assert_eq!(decoded.is_ok(), decode);
} else {
assert!(encoded.is_err());
}
}
}

View File

@ -18,6 +18,7 @@
mod algorithm;
mod digest_type;
#[cfg(any(feature = "openssl", feature = "ring"))]
mod key_format;
mod keypair;
mod nsec3;
@ -27,6 +28,7 @@ mod trust_anchor;
pub use self::algorithm::Algorithm;
pub use self::digest_type::DigestType;
#[cfg(any(feature = "openssl", feature = "ring"))]
pub use self::key_format::KeyFormat;
pub use self::keypair::KeyPair;
pub use self::nsec3::Nsec3HashAlgorithm;

View File

@ -15,19 +15,19 @@
*/
//! signer is a structure for performing many of the signing processes of the DNSSec specification
#[cfg(feature = "openssl")]
#[cfg(any(feature = "openssl", feature = "ring"))]
use chrono::Duration;
#[cfg(feature = "openssl")]
#[cfg(any(feature = "openssl", feature = "ring"))]
use op::Message;
#[cfg(feature = "openssl")]
#[cfg(any(feature = "openssl", feature = "ring"))]
use rr::{DNSClass, Name, Record, RecordType, RData};
#[cfg(feature = "openssl")]
#[cfg(any(feature = "openssl", feature = "ring"))]
use rr::dnssec::{Algorithm, DigestType, DnsSecErrorKind, DnsSecResult};
use rr::dnssec::KeyPair;
#[cfg(feature = "openssl")]
#[cfg(any(feature = "openssl", feature = "ring"))]
use rr::rdata::{sig, SIG};
#[cfg(feature = "openssl")]
#[cfg(any(feature = "openssl", feature = "ring"))]
use serialize::binary::{BinEncoder, BinSerializable, EncodeMode};
/// Use for performing signing and validation of DNSSec based components.
@ -229,7 +229,7 @@ use serialize::binary::{BinEncoder, BinSerializable, EncodeMode};
/// Note that the response received by the resolver should include all
/// NSEC RRs needed to authenticate the response (see Section 3.1.3).
/// ```
#[cfg(feature = "openssl")]
#[cfg(any(feature = "openssl", feature = "ring"))]
pub struct Signer {
key: KeyPair,
algorithm: Algorithm,
@ -239,10 +239,10 @@ pub struct Signer {
is_zone_update_auth: bool,
}
#[cfg(not(feature = "openssl"))]
#[cfg(not(any(feature = "openssl", feature = "ring")))]
pub struct Signer;
#[cfg(feature = "openssl")]
#[cfg(any(feature = "openssl", feature = "ring"))]
impl Signer {
/// Version of Signer for verifying RRSIGs and SIG0 records.
pub fn new_verifier(algorithm: Algorithm,
@ -690,208 +690,206 @@ impl Signer {
}
}
#[test]
#[cfg(test)]
#[cfg(feature = "openssl")]
fn test_sign_and_verify_message_sig0() {
use openssl::rsa::Rsa;
use rr::Name;
use op::{Message, Query, UpdateMessage};
mod tests {
extern crate openssl;
use self::openssl::rsa::Rsa;
let origin: Name = Name::parse("example.com.", None).unwrap();
let mut question: Message = Message::new();
let mut query: Query = Query::new();
query.set_name(origin.clone());
question.add_query(query);
let rsa = Rsa::generate(512).unwrap();
let key = KeyPair::from_rsa(rsa).unwrap();
let signer = Signer::new(Algorithm::RSASHA256,
key,
Name::root(),
Duration::max_value(),
true,
true);
let sig = signer.sign_message(&question).unwrap();
println!("sig: {:?}", sig);
assert!(!sig.is_empty());
assert!(signer.verify_message(&question, &sig).is_ok());
// now test that the sig0 record works correctly.
assert!(question.sig0().is_empty());
question.sign(&signer, 0).expect("should have signed");
assert!(!question.sig0().is_empty());
let sig = signer.sign_message(&question);
println!("sig after sign: {:?}", sig);
if let &RData::SIG(ref sig) = question.sig0()[0].rdata() {
assert!(signer.verify_message(&question, sig.sig()).is_ok());
}
}
#[test]
#[cfg(feature = "openssl")]
fn test_hash_rrset() {
use openssl::rsa::Rsa;
use rr::{Name, RecordType};
use rr::rdata::SIG;
use op::{Message, Query, UpdateMessage};
let rsa = Rsa::generate(512).unwrap();
let key = KeyPair::from_rsa(rsa).unwrap();
let signer = Signer::new(Algorithm::RSASHA256,
key,
Name::root(),
Duration::max_value(),
true,
true);
pub use super::*;
let origin: Name = Name::parse("example.com.", None).unwrap();
let rrsig = Record::new()
.set_name(origin.clone())
.set_ttl(86400)
.set_rr_type(RecordType::NS)
.set_dns_class(DNSClass::IN)
.set_rdata(RData::SIG(SIG::new(RecordType::NS,
Algorithm::RSASHA256,
origin.num_labels(),
86400,
5,
0,
signer.calculate_key_tag().unwrap(),
origin.clone(),
vec![])))
.clone();
let rrset = vec![Record::new()
.set_name(origin.clone())
.set_ttl(86400)
.set_rr_type(RecordType::NS)
.set_dns_class(DNSClass::IN)
.set_rdata(RData::NS(Name::parse("a.iana-servers.net.", None).unwrap()))
.clone(),
Record::new()
.set_name(origin.clone())
.set_ttl(86400)
.set_rr_type(RecordType::NS)
.set_dns_class(DNSClass::IN)
.set_rdata(RData::NS(Name::parse("b.iana-servers.net.", None).unwrap()))
.clone()];
#[test]
fn test_sign_and_verify_message_sig0() {
let origin: Name = Name::parse("example.com.", None).unwrap();
let mut question: Message = Message::new();
let mut query: Query = Query::new();
query.set_name(origin.clone());
question.add_query(query);
let hash = signer.hash_rrset_with_rrsig(&rrsig, &rrset).unwrap();
assert!(!hash.is_empty());
let rsa = Rsa::generate(512).unwrap();
let key = KeyPair::from_rsa(rsa).unwrap();
let signer = Signer::new(Algorithm::RSASHA256,
key,
Name::root(),
Duration::max_value(),
true,
true);
let rrset = vec![Record::new()
.set_name(origin.clone())
.set_ttl(86400)
.set_rr_type(RecordType::CNAME)
.set_dns_class(DNSClass::IN)
.set_rdata(RData::CNAME(Name::parse("a.iana-servers.net.", None).unwrap()))
.clone(), // different type
Record::new()
.set_name(Name::parse("www.example.com.", None).unwrap())
.set_ttl(86400)
.set_rr_type(RecordType::NS)
.set_dns_class(DNSClass::IN)
.set_rdata(RData::NS(Name::parse("a.iana-servers.net.", None).unwrap()))
.clone(), // different name
Record::new()
.set_name(origin.clone())
.set_ttl(86400)
.set_rr_type(RecordType::NS)
.set_dns_class(DNSClass::CH)
.set_rdata(RData::NS(Name::parse("a.iana-servers.net.", None).unwrap()))
.clone(), // different class
Record::new()
.set_name(origin.clone())
.set_ttl(86400)
.set_rr_type(RecordType::NS)
.set_dns_class(DNSClass::IN)
.set_rdata(RData::NS(Name::parse("a.iana-servers.net.", None).unwrap()))
.clone(),
Record::new()
.set_name(origin.clone())
.set_ttl(86400)
.set_rr_type(RecordType::NS)
.set_dns_class(DNSClass::IN)
.set_rdata(RData::NS(Name::parse("b.iana-servers.net.", None).unwrap()))
.clone()];
let sig = signer.sign_message(&question).unwrap();
println!("sig: {:?}", sig);
let filtered_hash = signer.hash_rrset_with_rrsig(&rrsig, &rrset).unwrap();
assert!(!filtered_hash.is_empty());
assert_eq!(hash, filtered_hash);
}
assert!(!sig.is_empty());
assert!(signer.verify_message(&question, &sig).is_ok());
#[test]
#[cfg(feature = "openssl")]
fn test_sign_and_verify_rrset() {
use openssl::rsa::Rsa;
use rr::RecordType;
use rr::Name;
use rr::rdata::SIG;
// now test that the sig0 record works correctly.
assert!(question.sig0().is_empty());
question.sign(&signer, 0).expect("should have signed");
assert!(!question.sig0().is_empty());
let rsa = Rsa::generate(512).unwrap();
let key = KeyPair::from_rsa(rsa).unwrap();
let signer = Signer::new(Algorithm::RSASHA256,
key,
Name::root(),
Duration::max_value(),
true,
true);
let sig = signer.sign_message(&question);
println!("sig after sign: {:?}", sig);
let origin: Name = Name::parse("example.com.", None).unwrap();
let rrsig = Record::new()
.set_name(origin.clone())
.set_ttl(86400)
.set_rr_type(RecordType::NS)
.set_dns_class(DNSClass::IN)
.set_rdata(RData::SIG(SIG::new(RecordType::NS,
Algorithm::RSASHA256,
origin.num_labels(),
86400,
5,
0,
signer.calculate_key_tag().unwrap(),
origin.clone(),
vec![])))
.clone();
let rrset = vec![Record::new()
.set_name(origin.clone())
.set_ttl(86400)
.set_rr_type(RecordType::NS)
.set_dns_class(DNSClass::IN)
.set_rdata(RData::NS(Name::parse("a.iana-servers.net.", None).unwrap()))
.clone(),
Record::new()
.set_name(origin.clone())
.set_ttl(86400)
.set_rr_type(RecordType::NS)
.set_dns_class(DNSClass::IN)
.set_rdata(RData::NS(Name::parse("b.iana-servers.net.", None).unwrap()))
.clone()];
if let &RData::SIG(ref sig) = question.sig0()[0].rdata() {
assert!(signer.verify_message(&question, sig.sig()).is_ok());
}
}
let hash = signer.hash_rrset_with_rrsig(&rrsig, &rrset).unwrap();
let sig = signer.sign(&hash).unwrap();
#[test]
fn test_hash_rrset() {
let rsa = Rsa::generate(512).unwrap();
let key = KeyPair::from_rsa(rsa).unwrap();
let signer = Signer::new(Algorithm::RSASHA256,
key,
Name::root(),
Duration::max_value(),
true,
true);
assert!(signer.verify(&hash, &sig).is_ok());
}
let origin: Name = Name::parse("example.com.", None).unwrap();
let rrsig = Record::new()
.set_name(origin.clone())
.set_ttl(86400)
.set_rr_type(RecordType::NS)
.set_dns_class(DNSClass::IN)
.set_rdata(RData::SIG(SIG::new(RecordType::NS,
Algorithm::RSASHA256,
origin.num_labels(),
86400,
5,
0,
signer.calculate_key_tag().unwrap(),
origin.clone(),
vec![])))
.clone();
let rrset =
vec![Record::new()
.set_name(origin.clone())
.set_ttl(86400)
.set_rr_type(RecordType::NS)
.set_dns_class(DNSClass::IN)
.set_rdata(RData::NS(Name::parse("a.iana-servers.net.", None).unwrap()))
.clone(),
Record::new()
.set_name(origin.clone())
.set_ttl(86400)
.set_rr_type(RecordType::NS)
.set_dns_class(DNSClass::IN)
.set_rdata(RData::NS(Name::parse("b.iana-servers.net.", None).unwrap()))
.clone()];
#[test]
#[cfg(feature = "openssl")]
fn test_calculate_key_tag() {
use openssl::rsa::Rsa;
let rsa = Rsa::generate(512).unwrap();
println!("pkey: {:?}", rsa.public_key_to_pem().unwrap());
let hash = signer.hash_rrset_with_rrsig(&rrsig, &rrset).unwrap();
assert!(!hash.is_empty());
let key = KeyPair::from_rsa(rsa).unwrap();
let signer = Signer::new(Algorithm::RSASHA256,
key,
Name::root(),
Duration::max_value(),
true,
true);
let key_tag = signer.calculate_key_tag().unwrap();
let rrset =
vec![Record::new()
.set_name(origin.clone())
.set_ttl(86400)
.set_rr_type(RecordType::CNAME)
.set_dns_class(DNSClass::IN)
.set_rdata(RData::CNAME(Name::parse("a.iana-servers.net.", None).unwrap()))
.clone(), // different type
Record::new()
.set_name(Name::parse("www.example.com.", None).unwrap())
.set_ttl(86400)
.set_rr_type(RecordType::NS)
.set_dns_class(DNSClass::IN)
.set_rdata(RData::NS(Name::parse("a.iana-servers.net.", None).unwrap()))
.clone(), // different name
Record::new()
.set_name(origin.clone())
.set_ttl(86400)
.set_rr_type(RecordType::NS)
.set_dns_class(DNSClass::CH)
.set_rdata(RData::NS(Name::parse("a.iana-servers.net.", None).unwrap()))
.clone(), // different class
Record::new()
.set_name(origin.clone())
.set_ttl(86400)
.set_rr_type(RecordType::NS)
.set_dns_class(DNSClass::IN)
.set_rdata(RData::NS(Name::parse("a.iana-servers.net.", None).unwrap()))
.clone(),
Record::new()
.set_name(origin.clone())
.set_ttl(86400)
.set_rr_type(RecordType::NS)
.set_dns_class(DNSClass::IN)
.set_rdata(RData::NS(Name::parse("b.iana-servers.net.", None).unwrap()))
.clone()];
println!("key_tag: {}", key_tag);
assert!(key_tag > 0);
}
let filtered_hash = signer.hash_rrset_with_rrsig(&rrsig, &rrset).unwrap();
assert!(!filtered_hash.is_empty());
assert_eq!(hash, filtered_hash);
}
#[test]
fn test_sign_and_verify_rrset() {
let rsa = Rsa::generate(512).unwrap();
let key = KeyPair::from_rsa(rsa).unwrap();
let signer = Signer::new(Algorithm::RSASHA256,
key,
Name::root(),
Duration::max_value(),
true,
true);
let origin: Name = Name::parse("example.com.", None).unwrap();
let rrsig = Record::new()
.set_name(origin.clone())
.set_ttl(86400)
.set_rr_type(RecordType::NS)
.set_dns_class(DNSClass::IN)
.set_rdata(RData::SIG(SIG::new(RecordType::NS,
Algorithm::RSASHA256,
origin.num_labels(),
86400,
5,
0,
signer.calculate_key_tag().unwrap(),
origin.clone(),
vec![])))
.clone();
let rrset =
vec![Record::new()
.set_name(origin.clone())
.set_ttl(86400)
.set_rr_type(RecordType::NS)
.set_dns_class(DNSClass::IN)
.set_rdata(RData::NS(Name::parse("a.iana-servers.net.", None).unwrap()))
.clone(),
Record::new()
.set_name(origin.clone())
.set_ttl(86400)
.set_rr_type(RecordType::NS)
.set_dns_class(DNSClass::IN)
.set_rdata(RData::NS(Name::parse("b.iana-servers.net.", None).unwrap()))
.clone()];
let hash = signer.hash_rrset_with_rrsig(&rrsig, &rrset).unwrap();
let sig = signer.sign(&hash).unwrap();
assert!(signer.verify(&hash, &sig).is_ok());
}
#[test]
fn test_calculate_key_tag() {
let rsa = Rsa::generate(512).unwrap();
println!("pkey: {:?}", rsa.public_key_to_pem().unwrap());
let key = KeyPair::from_rsa(rsa).unwrap();
let signer = Signer::new(Algorithm::RSASHA256,
key,
Name::root(),
Duration::max_value(),
true,
true);
let key_tag = signer.calculate_key_tag().unwrap();
println!("key_tag: {}", key_tag);
assert!(key_tag > 0);
}
}

View File

@ -11,6 +11,7 @@ extern crate openssl;
#[cfg(target_os = "macos")]
extern crate security_framework;
extern crate tokio_core;
#[cfg(feature = "tokio-tls")]
extern crate tokio_tls;
extern crate trust_dns;
@ -42,6 +43,7 @@ use openssl::x509::store::X509StoreBuilder;
use security_framework::certificate::SecCertificate;
use tokio_core::reactor::Core;
#[cfg(feature = "tls")]
use trust_dns::tls::TlsStream;
// this fails on linux for some reason. It appears that a buffer somewhere is dirty
@ -49,6 +51,7 @@ use trust_dns::tls::TlsStream;
// but not 3?
// #[cfg(not(target_os = "linux"))]
#[test]
#[cfg(feature = "tls")]
fn test_tls_client_stream_ipv4() {
tls_client_stream_test(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), false)
}
@ -56,12 +59,14 @@ fn test_tls_client_stream_ipv4() {
// FIXME: mtls is disabled at the moment, it causes a hang on Linux, and is currently not supported on macOS
#[cfg(feature = "mtls_disabled")]
#[test]
#[cfg(feature = "tls")]
#[cfg(not(target_os = "macos"))] // ignored until Travis-CI fixes IPv6
fn test_tls_client_stream_ipv4_mtls() {
tls_client_stream_test(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), true)
}
#[test]
#[cfg(feature = "tls")]
#[cfg(not(target_os = "linux"))] // ignored until Travis-CI fixes IPv6
fn test_tls_client_stream_ipv6() {
tls_client_stream_test(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), false)
@ -148,6 +153,7 @@ fn cert(subject_name: &str, ca_pkey: &PKey, ca_name: &X509Name, _: &X509) -> (PK
#[allow(unused_mut)]
#[cfg(feature = "tls")]
fn tls_client_stream_test(server_addr: IpAddr, mtls: bool) {
let succeeded = Arc::new(std::sync::atomic::AtomicBool::new(false));
let succeeded_clone = succeeded.clone();

View File

@ -11,6 +11,7 @@ esac
# don't run on nightly or beta
rustc --version | grep beta && exit 0;
rustc --version | grep nightly && exit 0;
if [ -z ${RUN_KCOV} ] ; then exit 0; fi
rm -rf kcov-master master.tar.gz*
@ -36,7 +37,7 @@ export COVERALLS_PARALLEL=true
SRC_PATHS=client/src,server/src
EXCLUDE_PATHS=client/src/error,server/src/error
for i in target/debug/trust_dns*-* target/debug/*_tests-* ; do
for i in target/debug/deps/trust_dns*-* target/debug/deps/*_tests-* ; do
if [ -f $i ] && [ -x $i ]; then
# submit the report... what's the executable since there are many?
echo "executing kcov on $i"

View File

@ -1,12 +1,18 @@
#!/bin/bash -e
MODULES=${MODULES:-"client server"}
CLIENT_OPTIONS=${CLIENT_OPTIONS} # add in all features
OPTIONS=${OPTIONS}
trust_dns_dir=$(dirname $0)/..
cd ${trust_dns_dir:?}
for i in client server; do
for i in ${MODULES:?}; do
pushd $i
opts=${OPTIONS}
if [ $i == "client" ] ; then opts="${OPTIONS} ${CLIENT_OPTIONS}" ; fi
echo "executing cargo on $i"
cargo build
cargo test
cargo test ${opts}
popd
done

View File

@ -38,6 +38,8 @@ license = "MIT/Apache-2.0"
build = "build.rs"
[features]
default = ["trust-dns/tls"]
ring = ["trust-dns/ring"]
[lib]
name = "trust_dns_server"

View File

@ -288,14 +288,14 @@ fn read_cert(path: &Path, password: Option<&str>) -> Result<native_tls::Pkcs12,
.map_err(|e| format!("badly formated pkcs12 key from: {:?}: {}", path, e))
}
fn load_cert(tls_cert_config: &TlsCertConfig) -> Result<native_tls::Pkcs12, String> {
let path = tls_cert_config.get_path();
fn load_cert(zone_dir: &Path, tls_cert_config: &TlsCertConfig) -> Result<native_tls::Pkcs12, String> {
let path = zone_dir.to_owned().join(tls_cert_config.get_path());
let password = tls_cert_config.get_password();
let subject_name = tls_cert_config.get_subject_name();
if path.exists() {
info!("reading TLS certificate from: {:?}", path);
read_cert(path, password)
read_cert(&path, password)
} else if tls_cert_config.create_if_absent() {
info!("generating RSA certificate: {:?}", path);
let key_pair = try!(KeyPair::generate(Algorithm::RSASHA256)
@ -366,7 +366,7 @@ fn load_cert(tls_cert_config: &TlsCertConfig) -> Result<native_tls::Pkcs12, Stri
panic!("the interior key was not an EC, something changed")
}
read_cert(path, password)
read_cert(&path, password)
} else {
Err(format!("TLS certificate not found: {:?}", path))
}
@ -469,7 +469,7 @@ pub fn main() {
info!("loading cert for DNS over TLS: {:?}",
tls_cert_config.get_path());
// TODO: see about modifying native_tls to impl Clone for Pkcs12
let tls_cert = load_cert(tls_cert_config).expect("error loading tls certificate file");
let tls_cert = load_cert(zone_dir, tls_cert_config).expect("error loading tls certificate file");
info!("listening for TLS on {:?}", tls_listener);
server.register_tls_listener(tls_listener, tcp_request_timeout, tls_cert)

View File

@ -1,6 +1,6 @@
listen_addrs_ipv4 = ["0.0.0.0"]
tls_cert = { path = "tests/named_test_configs/sec/example.p12", subject_name = "ns.example.com", password = "testpass", create_if_absent = true }
tls_cert = { path = "sec/example.p12", subject_name = "ns.example.com", password = "testpass", create_if_absent = true }
[[zones]]
zone = "example.com"

View File

@ -256,7 +256,10 @@ fn test_ipv4_and_ipv6_toml_startup() {
fn test_example_tls_toml_startup() {
named_test_harness("dns_over_tls.toml", move |_, tls_port| {
let mut cert_der = vec![];
File::open("tests/named_test_configs/sec/example.cert")
let server_path = env::var("TDNS_SERVER_SRC_ROOT").unwrap_or(".".to_owned());
println!("using server src path: {}", server_path);
File::open(&format!("{}/tests/named_test_configs/sec/example.cert", server_path))
.unwrap()
.read_to_end(&mut cert_der)
.unwrap();