refactored authority and configuration to support new key formats

This commit is contained in:
Benjamin Fry 2017-01-08 15:16:42 -08:00
parent 413a95ab7f
commit 4c0318ec95
27 changed files with 616 additions and 283 deletions

View File

@ -2,6 +2,11 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## 0.9.4 (in progress)
### Added
- support for ECDSAP256SHA256, ECDSAP384SHA384 and ED25519 (client and server)
- additional config options for keys to named, see `tests/named_test_configs/example.toml`
## 0.9.3
### Changed
- updated to rust-openssl 0.9.x series

18
Cargo.lock generated
View File

@ -10,7 +10,7 @@ dependencies = [
"lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl 0.9.4 (git+https://github.com/bluejekyll/rust-openssl.git)",
"openssl 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"rusqlite 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
@ -320,19 +320,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "openssl"
version = "0.9.4"
source = "git+https://github.com/bluejekyll/rust-openssl.git#444c00955a5622ff694eaefd75f047e7eabbad2a"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-sys 0.9.4 (git+https://github.com/bluejekyll/rust-openssl.git)",
"openssl-sys 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "openssl-sys"
version = "0.9.4"
source = "git+https://github.com/bluejekyll/rust-openssl.git#444c00955a5622ff694eaefd75f047e7eabbad2a"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
@ -498,7 +498,7 @@ dependencies = [
"lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl 0.9.4 (git+https://github.com/bluejekyll/rust-openssl.git)",
"openssl 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"ring 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
@ -587,8 +587,8 @@ dependencies = [
"checksum num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "fb24d9bfb3f222010df27995441ded1e954f8f69cd35021f6bef02ca9552fb92"
"checksum num-iter 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "287a1c9969a847055e1122ec0ea7a5c5d6f72aad97934e131c83d5c08ab4e45c"
"checksum num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "a16a42856a256b39c6d3484f097f6713e14feacd9bfb02290917904fae46c81c"
"checksum openssl 0.9.4 (git+https://github.com/bluejekyll/rust-openssl.git)" = "<none>"
"checksum openssl-sys 0.9.4 (git+https://github.com/bluejekyll/rust-openssl.git)" = "<none>"
"checksum openssl 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6a324049c1cf6496421e033daf0a460bc17cc1de11b421568492e2b1fd57a710"
"checksum openssl-sys 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4e38c5a9261a179e63757eee43a1ee63f9033a2e99b8147aa4c245857a995af7"
"checksum pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8cee804ecc7eaf201a4a207241472cc870e825206f6c031e3ee2a72fa425f2fa"
"checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d"
"checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f"

View File

@ -53,7 +53,7 @@ futures = "^0.1"
lazy_static = "^0.2.1"
log = "^0.3.5"
mio = { version = "^0.5.1", optional = true }
openssl = { version = "0.9.4", git = "https://github.com/bluejekyll/rust-openssl.git", optional = true }
openssl = { version = "^0.9.5", optional = true }
rand = "^0.3"
# ring = { version = "^0.6", optional = true, features = ["rsa_signing"] }
ring = { version = "^0.6", optional = true }

View File

@ -39,7 +39,7 @@ use ::serialize::binary::*;
use ::client::ClientConnection;
/// The Client is abstracted over either trust_dns::tcp::TcpClientConnection or
/// trust_dns::udp::UdpClientConnection
/// trust_dns::udp::UdpClientConnection.
///
/// Usage of TCP or UDP is up to the user. Some DNS servers
/// disallow TCP in some cases, so if TCP double check if UDP works.
@ -226,11 +226,11 @@ impl<C: ClientConnection> Client<C> {
if !rdata.is_zone_key() { continue }
if *rdata.get_algorithm() != sig.get_algorithm() { continue }
let pkey = KeyPair::from_vec(rdata.get_public_key(), *rdata.get_algorithm());
let pkey = KeyPair::from_public_bytes(rdata.get_public_key(), *rdata.get_algorithm());
if pkey.is_err() { debug!("could not translate public_key_from_vec: {}", pkey.err().unwrap()); continue }
let pkey = pkey.unwrap();
let signer: Signer = Signer::new_verifier(*rdata.get_algorithm(), pkey, sig.get_signer_name().clone());
let signer: Signer = Signer::new_verifier(*rdata.get_algorithm(), pkey, sig.get_signer_name().clone(), rdata.is_zone_key(), false);
let rrset_hash = signer.hash_rrset_with_rrsig(rrsig, &rrset);
if rrset_hash.is_err() { debug!("could not hash_rrset_with_rrsig: {}, {}", name, rrset_hash.unwrap_err()); continue }
let rrset_hash: Vec<u8> = rrset_hash.unwrap();

View File

@ -14,8 +14,7 @@
* limitations under the License.
*/
//! Use `Client` along with `trust_dns::udp::UdpClientConnection` or
//! `trust_dns::tcp::TcpClientConnection`.
//! DNS Client associated classes for performing queries and other operations.
#[cfg(feature = "mio_client")]
mod client;

View File

@ -69,7 +69,7 @@ impl<H> SecureClientHandle<H> where H: ClientHandle + 'static {
trust_anchor: Rc::new(trust_anchor),
request_depth: 0,
minimum_key_len: 0,
minimum_algorithm: Algorithm::RSASHA1,
minimum_algorithm: Algorithm::RSASHA256,
}
}
@ -101,6 +101,7 @@ impl<H> ClientHandle for SecureClientHandle<H> where H: ClientHandle + 'static {
let query = message.get_queries().first().cloned().unwrap();
let client: SecureClientHandle<H> = self.clone_with_context();
// TODO: cache response of the server about understood algorithms
#[cfg(any(feature = "openssl", feature = "ring"))]
{
let edns = message.get_edns_mut();
@ -631,11 +632,11 @@ fn verify_rrset_with_dnskey(dnskey: &DNSKEY,
if !dnskey.is_zone_key() { return Err(ClientErrorKind::Message("is not a zone key").into()) }
if *dnskey.get_algorithm() != sig.get_algorithm() { return Err(ClientErrorKind::Message("mismatched algorithm").into()) }
let pkey = KeyPair::from_vec(dnskey.get_public_key(), *dnskey.get_algorithm());
let pkey = KeyPair::from_public_bytes(dnskey.get_public_key(), *dnskey.get_algorithm());
if let Err(e) = pkey { debug!("error getting key from vec: {}", e); return Err(ClientErrorKind::Message("error getting key from vec").into()) }
let pkey = pkey.unwrap();
let signer: Signer = Signer::new_verifier(*dnskey.get_algorithm(), pkey, sig.get_signer_name().clone());
let signer: Signer = Signer::new_verifier(*dnskey.get_algorithm(), pkey, sig.get_signer_name().clone(), dnskey.is_zone_key(), false);
signer.hash_rrset_with_sig(&rrset.name, rrset.record_class, sig, &rrset.records)
.map_err(|e| e.into())

View File

@ -99,7 +99,7 @@ use ::error::*;
/// This document cannot be updated, only made obsolete and replaced by a
/// successor document.
/// ```
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, RustcDecodable)]
pub enum Algorithm {
/// DO NOT USE, SHA1 is a compromised hashing function, it is here for backward compatability
RSASHA1,
@ -139,6 +139,18 @@ impl Algorithm {
Algorithm::RSASHA512 => 64, // 512 bites
}
}
pub fn to_str(&self) -> &'static str {
match *self {
Algorithm::RSASHA1 => "RSASHA1",
Algorithm::RSASHA256 => "RSASHA256",
Algorithm::RSASHA1NSEC3SHA1 => "RSASHA1-NSEC3-SHA1",
Algorithm::RSASHA512 => "RSASHA512",
Algorithm::ECDSAP256SHA256 => "ECDSAP256SHA256",
Algorithm::ECDSAP384SHA384 => "ECDSAP384SHA384",
Algorithm::ED25519 => "ED25519",
}
}
}
impl BinSerializable<Algorithm> for Algorithm {
@ -172,15 +184,7 @@ impl FromStr for Algorithm {
impl From<Algorithm> for &'static str {
fn from(a: Algorithm) -> &'static str {
match a {
Algorithm::RSASHA1 => "RSASHA1",
Algorithm::RSASHA256 => "RSASHA256",
Algorithm::RSASHA1NSEC3SHA1 => "RSASHA1-NSEC3-SHA1",
Algorithm::RSASHA512 => "RSASHA512",
Algorithm::ECDSAP256SHA256 => "ECDSAP256SHA256",
Algorithm::ECDSAP384SHA384 => "ECDSAP384SHA384",
Algorithm::ED25519 => "ED25519",
}
a.to_str()
}
}

View File

@ -12,6 +12,7 @@
#[cfg(feature = "openssl")] use openssl::ec::{EcGroup, EcKey, EcPoint, POINT_CONVERSION_UNCOMPRESSED};
#[cfg(feature = "openssl")] use openssl::nid;
#[cfg(feature = "ring")] use ring::rand;
#[cfg(feature = "ring")] use ring::signature::{Ed25519KeyPair, Ed25519KeyPairBytes, EdDSAParameters, VerificationAlgorithm};
#[cfg(feature = "ring")] use untrusted::Input;
@ -63,7 +64,7 @@ impl KeyPair {
///
/// * `public_key` - the public key bytes formatted in BigEndian/NetworkByteOrder
/// * `algorithm` - the Algorithm which is used to interpret the key
pub fn from_vec(public_key: &[u8], algorithm: Algorithm) -> DnsSecResult<Self> {
pub fn from_public_bytes(public_key: &[u8], algorithm: Algorithm) -> DnsSecResult<Self> {
match algorithm {
#[cfg(feature = "openssl")]
Algorithm::RSASHA1 |
@ -202,7 +203,7 @@ impl KeyPair {
///
/// If there is a private key associated with this keypair, it will not be included in this
/// format. Only the public key material will be included.
pub fn to_vec(&self) -> DnsSecResult<Vec<u8>> {
pub fn to_public_bytes(&self) -> DnsSecResult<Vec<u8>> {
match *self {
// see from_vec() RSA sections for reference
#[cfg(feature = "openssl")]
@ -311,7 +312,7 @@ impl KeyPair {
pub fn key_tag(&self) -> DnsSecResult<u16> {
let mut ac: usize = 0;
for (i,k) in try!(self.to_vec()).iter().enumerate() {
for (i,k) in try!(self.to_public_bytes()).iter().enumerate() {
ac += if i & 0x0001 == 0x0001 { *k as usize } else { (*k as usize) << 8 };
}
@ -331,13 +332,8 @@ impl KeyPair {
/// the DNSKEY record data
// pub fn to_dnskey(&self, name: Name, ttl: u32, algorithm: Algorithm) -> DnsSecResult<DNSKEY> {
pub fn to_dnskey(&self, algorithm: Algorithm) -> DnsSecResult<DNSKEY> {
self.to_vec()
self.to_public_bytes()
.map(|bytes| DNSKEY::new(true, true, false, algorithm, bytes) )
// {
// //let mut record = Record::with(name.clone(), RecordType::DNSKEY, ttl);
// DNSKEY::new(true, true, false, algorithm, bytes)
// })
}
/// Creates a DS record for this KeyPair associated to the given name
@ -420,146 +416,198 @@ impl KeyPair {
_ => Err(DnsSecErrorKind::Message("openssl nor ring feature(s) not enabled").into()),
}
}
}
#[cfg(feature = "openssl")]
#[test]
fn test_rsa_hashing() {
use openssl::rsa;
/// The KeyPair, with private key, converted to binary form.
///
/// Generally the format is will be in PEM, with the exception of ED25519, which is
/// currently little endian `32 private key bytes | 32 public key bytes`.
pub fn to_private_bytes(&self) -> DnsSecResult<Vec<u8>> {
match *self {
#[cfg(feature = "openssl")]
KeyPair::RSA(ref pkey) | KeyPair::EC(ref pkey) => {
pkey.private_key_to_pem().map_err(|e| e.into())
},
#[cfg(feature = "ring")]
KeyPair::ED25519(ref ed_key) => {
let mut vec = Vec::with_capacity(ed_key.private_key.len() + ed_key.public_key.len());
let bytes = b"www.example.com";
let key = rsa::Rsa::generate(2048)
.map_err(|e| e.into())
.and_then(|rsa| KeyPair::from_rsa(rsa))
.unwrap();
let neg = rsa::Rsa::generate(2048)
.map_err(|e| e.into())
.and_then(|rsa| KeyPair::from_rsa(rsa))
.unwrap();
vec.extend_from_slice(&ed_key.private_key);
vec.extend_from_slice(&ed_key.public_key);
Ok(vec)
}
#[cfg(not(any(feature = "openssl", feature = "ring")))]
_ => Err(DnsSecErrorKind::Message("openssl nor ring feature(s) not enabled").into()),
}
}
for algorithm in &[Algorithm::RSASHA1,
Algorithm::RSASHA256,
Algorithm::RSASHA1NSEC3SHA1,
Algorithm::RSASHA512] {
let sig = key.sign(*algorithm, bytes).unwrap();
assert!(key.verify(*algorithm, bytes, &sig).is_ok(), "algorithm: {:?}", algorithm);
assert!(!neg.verify(*algorithm, bytes, &sig).is_ok(), "algorithm: {:?}", algorithm);
/// Creates a KeyPair for the specified algorithm with the associated bytes
///
/// Generally the format is expected to be in PEM, with the exception of ED25519, which is
/// currently little endian `32 private key bytes | 32 public key bytes`.
pub fn from_private_bytes(algorithm: Algorithm, bytes: &[u8]) -> DnsSecResult<Self> {
match algorithm {
#[cfg(feature = "openssl")]
Algorithm::RSASHA1 |
Algorithm::RSASHA1NSEC3SHA1 |
Algorithm::RSASHA256 |
Algorithm::RSASHA512 => {
let rsa = try!(OpenSslRsa::private_key_from_pem(bytes));
KeyPair::from_rsa(rsa)
},
#[cfg(feature = "openssl")]
Algorithm::ECDSAP256SHA256 |
Algorithm::ECDSAP384SHA384 => {
let ec = try!(EcKey::private_key_from_pem(bytes));
KeyPair::from_ec_key(ec)
},
#[cfg(feature = "ring")]
Algorithm::ED25519 => {
let mut private_key = [0u8;32];
let mut public_key = [0u8;32];
if bytes.len() != 64 { return Err(DnsSecErrorKind::Msg(format!("expected 64 bytes: {}", bytes.len())).into()) }
private_key.copy_from_slice(&bytes[..32]);
public_key.copy_from_slice(&bytes[32..]);
Ok(KeyPair::from_ed25519(Ed25519KeyPairBytes{private_key: private_key, public_key: public_key}))
},
#[cfg(not(any(feature = "openssl", feature = "ring")))]
_ => Err(DnsSecErrorKind::Message("openssl nor ring feature(s) not enabled").into()),
}
}
/// Generates a new private and public key pair for the specified algorithm.
///
/// RSA keys are hardcoded to 2048bits at the moment. Other keys have predefined sizes.
pub fn generate(algorithm: Algorithm) -> DnsSecResult<Self> {
match algorithm {
#[cfg(feature = "openssl")]
Algorithm::RSASHA1 |
Algorithm::RSASHA1NSEC3SHA1 |
Algorithm::RSASHA256 |
Algorithm::RSASHA512 => {
// TODO: the only keysize right now, would be better for people to use other algorithms...
OpenSslRsa::generate(2048)
.map_err(|e| e.into())
.and_then(|rsa| KeyPair::from_rsa(rsa))
},
#[cfg(feature = "openssl")]
Algorithm::ECDSAP256SHA256 => {
EcGroup::from_curve_name(nid::SECP256K1)
.and_then(|group| EcKey::generate(&group))
.map_err(|e| e.into())
.and_then(|ec_key| KeyPair::from_ec_key(ec_key))
},
#[cfg(feature = "openssl")]
Algorithm::ECDSAP384SHA384 => {
EcGroup::from_curve_name(nid::SECP384R1)
.and_then(|group| EcKey::generate(&group))
.map_err(|e| e.into())
.and_then(|ec_key| KeyPair::from_ec_key(ec_key))
},
#[cfg(feature = "ring")]
Algorithm::ED25519 => {
let rng = rand::SystemRandom::new();
Ed25519KeyPair::generate_serializable(&rng)
.map_err(|e| e.into())
.map(|(_, key)| KeyPair::from_ed25519(key))
},
#[cfg(not(any(feature = "openssl", feature = "ring")))]
_ => Err(DnsSecErrorKind::Message("openssl nor ring feature(s) not enabled").into()),
}
}
}
#[cfg(feature = "openssl")]
#[test]
fn test_ec_hashing_p256() {
use openssl::ec;
let algorithm = Algorithm::ECDSAP256SHA256;
let bytes = b"www.example.com";
let key = EcGroup::from_curve_name(nid::SECP256K1)
.and_then(|group| ec::EcKey::generate(&group))
.map_err(|e| e.into())
.and_then(|ec_key| KeyPair::from_ec_key(ec_key))
.unwrap();
let neg = EcGroup::from_curve_name(nid::SECP256K1)
.and_then(|group| ec::EcKey::generate(&group))
.map_err(|e| e.into())
.and_then(|ec_key| KeyPair::from_ec_key(ec_key))
.unwrap();
fn test_rsa_hashing() {
hash_test(Algorithm::RSASHA256);
}
let sig = key.sign(algorithm, bytes).unwrap();
assert!(key.verify(algorithm, bytes, &sig).is_ok(), "algorithm: {:?}", algorithm);
assert!(!neg.verify(algorithm, bytes, &sig).is_ok(), "algorithm: {:?}", algorithm);
#[cfg(feature = "openssl")]
#[test]
fn test_ec_hashing_p256() {
hash_test(Algorithm::ECDSAP256SHA256);
}
#[cfg(feature = "openssl")]
#[test]
fn test_ec_hashing_p384() {
use openssl::ec;
let algorithm = Algorithm::ECDSAP384SHA384;
let bytes = b"www.example.com";
let key = EcGroup::from_curve_name(nid::SECP384R1)
.and_then(|group| ec::EcKey::generate(&group))
.map_err(|e| e.into())
.and_then(|ec_key| KeyPair::from_ec_key(ec_key))
.unwrap();
let neg = EcGroup::from_curve_name(nid::SECP384R1)
.and_then(|group| ec::EcKey::generate(&group))
.map_err(|e| e.into())
.and_then(|ec_key| KeyPair::from_ec_key(ec_key))
.unwrap();
let sig = key.sign(algorithm, bytes).unwrap();
assert!(key.verify(algorithm, bytes, &sig).is_ok(), "algorithm: {:?}", algorithm);
assert!(!neg.verify(algorithm, bytes, &sig).is_ok(), "algorithm: {:?}", algorithm);
hash_test(Algorithm::ECDSAP384SHA384);
}
#[cfg(feature = "ring")]
#[test]
fn test_ed25519() {
use ring::rand;
hash_test(Algorithm::ED25519);
}
let algorithm = Algorithm::ED25519;
#[cfg(test)]
fn hash_test(algorithm: Algorithm) {
let bytes = b"www.example.com";
let rng = rand::SystemRandom::new();
let key = Ed25519KeyPair::generate_serializable(&rng).map(|(_, key)| KeyPair::from_ed25519(key)).expect("no ring");
let neg = Ed25519KeyPair::generate_serializable(&rng).map(|(_, key)| KeyPair::from_ed25519(key)).expect("no ring");
let key = KeyPair::generate(algorithm).unwrap();
let neg = KeyPair::generate(algorithm).unwrap();
let sig = key.sign(algorithm, bytes).unwrap();
assert!(key.verify(algorithm, bytes, &sig).is_ok(), "algorithm: {:?}", algorithm);
assert!(!neg.verify(algorithm, bytes, &sig).is_ok(), "algorithm: {:?}", algorithm);
}
#[cfg(feature = "openssl")]
#[test]
fn test_to_from_vec_rsa() {
use openssl::rsa;
let key = rsa::Rsa::generate(2048)
.map_err(|e| e.into())
.and_then(|rsa| KeyPair::from_rsa(rsa))
.unwrap();
assert!(key.to_vec().and_then(|bytes| KeyPair::from_vec(&bytes, Algorithm::RSASHA256)).is_ok());
fn test_to_from_public_key_rsa() {
to_from_public_key_test(Algorithm::RSASHA256);
}
#[cfg(feature = "openssl")]
#[test]
fn test_to_from_vec_ec_p256() {
use openssl::ec;
let algorithm = Algorithm::ECDSAP256SHA256;
let key = EcGroup::from_curve_name(nid::SECP256K1)
.and_then(|group| ec::EcKey::generate(&group))
.map_err(|e| e.into())
.and_then(|ec_key| KeyPair::from_ec_key(ec_key))
.unwrap();
assert!(key.to_vec().and_then(|bytes| KeyPair::from_vec(&bytes, algorithm)).is_ok());
fn test_to_from_public_key_ec_p256() {
to_from_public_key_test(Algorithm::ECDSAP256SHA256);
}
#[cfg(feature = "openssl")]
#[test]
fn test_to_from_vec_ec_p384() {
use openssl::ec;
let algorithm = Algorithm::ECDSAP384SHA384;
let key = EcGroup::from_curve_name(nid::SECP384R1)
.and_then(|group| ec::EcKey::generate(&group))
.map_err(|e| e.into())
.and_then(|ec_key| KeyPair::from_ec_key(ec_key))
.unwrap();
assert!(key.to_vec().and_then(|bytes| KeyPair::from_vec(&bytes, algorithm)).is_ok());
fn test_to_from_public_key_ec_p384() {
to_from_public_key_test(Algorithm::ECDSAP384SHA384);
}
#[cfg(feature = "ring")]
#[test]
fn test_to_from_vec_ed25519() {
use ring::rand;
let algorithm = Algorithm::ED25519;
let rng = rand::SystemRandom::new();
let key = Ed25519KeyPair::generate_serializable(&rng).map(|(_,key)| KeyPair::from_ed25519(key)).expect("no ring");
key.to_vec().and_then(|bytes| KeyPair::from_vec(&bytes, algorithm)).expect("failed");
fn test_to_from_public_key_ed25519() {
to_from_public_key_test(Algorithm::ED25519);
}
#[cfg(test)]
fn to_from_public_key_test(algorithm: Algorithm) {
let key = KeyPair::generate(algorithm).unwrap();
assert!(key.to_public_bytes().and_then(|bytes| KeyPair::from_public_bytes(&bytes, algorithm)).is_ok());
}
#[cfg(feature = "openssl")]
#[test]
fn test_serialization_ec() {
test_serialization(Algorithm::ECDSAP256SHA256);
}
#[cfg(feature = "ring")]
#[test]
fn test_serialization_ed25519() {
test_serialization(Algorithm::ED25519);
}
#[cfg(feature = "openssl")]
#[test]
fn test_serialization_rsa() {
test_serialization(Algorithm::RSASHA256);
}
#[cfg(test)]
fn test_serialization(algorithm: Algorithm) {
let key = KeyPair::generate(algorithm).unwrap();
assert!(KeyPair::from_private_bytes(algorithm, &key.to_private_bytes().unwrap()).is_ok());
}

View File

@ -235,6 +235,8 @@ pub struct Signer {
algorithm: Algorithm,
signer_name: Name,
sig_duration: Duration,
is_zone_signing_key: bool,
is_zone_update_auth: bool,
}
#[cfg(not(feature = "openssl"))]
@ -243,19 +245,26 @@ pub struct Signer;
#[cfg(feature = "openssl")]
impl Signer {
/// Version of Signer for verifying RRSIGs and SIG0 records.
pub fn new_verifier(algorithm: Algorithm, key: KeyPair, signer_name: Name) -> Self {
Signer{ key: key, algorithm: algorithm, signer_name: signer_name, sig_duration: Duration::zero() }
pub fn new_verifier(algorithm: Algorithm, key: KeyPair, signer_name: Name,
is_zone_signing_key: bool, is_zone_update_auth: bool) -> Self {
Signer{ key: key, algorithm: algorithm, signer_name: signer_name,
sig_duration: Duration::zero(), is_zone_signing_key: is_zone_signing_key,
is_zone_update_auth: is_zone_update_auth }
}
/// Version of Signer for signing RRSIGs and SIG0 records.
pub fn new(algorithm: Algorithm, key: KeyPair, signer_name: Name, sig_duration: Duration) -> Self {
Signer{ key: key, algorithm: algorithm, signer_name: signer_name, sig_duration: sig_duration }
pub fn new(algorithm: Algorithm, key: KeyPair, signer_name: Name, sig_duration: Duration,
is_zone_signing_key: bool, is_zone_update_auth: bool) -> Self {
Signer{ key: key, algorithm: algorithm, signer_name: signer_name, sig_duration: sig_duration,
is_zone_signing_key: is_zone_signing_key, is_zone_update_auth: is_zone_update_auth }
}
pub fn get_algorithm(&self) -> Algorithm { self.algorithm }
pub fn get_key(&self) -> &KeyPair { &self.key }
pub fn get_sig_duration(&self) -> Duration { self.sig_duration }
pub fn get_signer_name(&self) -> &Name { &self.signer_name }
pub fn is_zone_signing_key(&self) -> bool { self.is_zone_signing_key }
pub fn is_zone_update_auth(&self) -> bool { self.is_zone_update_auth }
/// The key tag is calculated as a hash to more quickly lookup a DNSKEY.
///
@ -313,7 +322,7 @@ impl Signer {
pub fn calculate_key_tag(&self) -> DnsSecResult<u16> {
let mut ac: usize = 0;
for (i,k) in try!(self.key.to_vec()).iter().enumerate() {
for (i,k) in try!(self.key.to_public_bytes()).iter().enumerate() {
ac += if i & 0x0001 == 0x0001 { *k as usize } else { (*k as usize) << 8 };
}
@ -627,7 +636,7 @@ fn test_sign_and_verify_message_sig0() {
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());
let signer = Signer::new(Algorithm::RSASHA256, key, Name::root(), Duration::max_value(), true, true);
let sig = signer.sign_message(&question).unwrap();
println!("sig: {:?}", sig);
@ -657,7 +666,7 @@ 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());
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().name(origin.clone()).ttl(86400).rr_type(RecordType::NS).dns_class(DNSClass::IN).rdata(RData::SIG(SIG::new(RecordType::NS, Algorithm::RSASHA256, origin.num_labels(), 86400,
@ -689,7 +698,7 @@ 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());
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().name(origin.clone()).ttl(86400).rr_type(RecordType::NS).dns_class(DNSClass::IN).rdata(RData::SIG(SIG::new(RecordType::NS, Algorithm::RSASHA256, origin.num_labels(), 86400,
@ -711,7 +720,7 @@ fn test_calculate_key_tag() {
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());
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);

View File

@ -32,7 +32,17 @@ impl SupportedAlgorithms {
}
pub fn all() -> Self {
SupportedAlgorithms{ bit_map: 0b00001111 }
SupportedAlgorithms{ bit_map: 0b00111111 }
}
pub fn from_vec(algorithms: &[Algorithm]) -> Self {
let mut supported = SupportedAlgorithms::new();
for a in algorithms {
supported.set(*a);
}
supported
}
fn pos(algorithm: Algorithm) -> u8 {
@ -92,10 +102,10 @@ impl SupportedAlgorithms {
// }
impl<'a> From<&'a [u8]> for SupportedAlgorithms {
fn from(value: &'a [u8]) -> Self {
fn from(values: &'a [u8]) -> Self {
let mut supported = SupportedAlgorithms::new();
for a in value.iter().map(|i|Algorithm::from_u8(*i)) {
for a in values.iter().map(|i|Algorithm::from_u8(*i)) {
if a.is_ok() {
supported.set(a.unwrap());
} else {
@ -103,7 +113,6 @@ impl<'a> From<&'a [u8]> for SupportedAlgorithms {
}
}
supported
}
}
@ -156,8 +165,10 @@ fn test_has() {
assert!(supported.has(Algorithm::RSASHA1));
assert!(!supported.has(Algorithm::RSASHA1NSEC3SHA1));
let mut supported = SupportedAlgorithms::new();
supported.set(Algorithm::RSASHA256);
assert!(supported.has(Algorithm::RSASHA1));
assert!(!supported.has(Algorithm::RSASHA1));
assert!(!supported.has(Algorithm::RSASHA1NSEC3SHA1));
assert!(supported.has(Algorithm::RSASHA256));
}
@ -165,7 +176,7 @@ fn test_has() {
#[test]
fn test_iterator() {
let supported = SupportedAlgorithms::all();
assert_eq!(supported.iter().count(), 4);
assert_eq!(supported.iter().count(), 6);
// it just so happens that the iterator has a fixed order...
let supported = SupportedAlgorithms::all();

View File

@ -38,7 +38,7 @@ impl Default for TrustAnchor {
let rsa = Rsa::public_key_from_pem(ROOT_ANCHOR.as_bytes()).expect("Error parsing Kjqmt7v.pem");
let key = KeyPair::from_rsa(rsa).expect("Error creating KeyPair from RSA key");
TrustAnchor{ pkeys: vec![key.to_vec().expect("could not convert key to bytes")] }
TrustAnchor{ pkeys: vec![key.to_public_bytes().expect("could not convert key to bytes")] }
}
#[cfg(not(feature = "openssl"))]

View File

@ -44,6 +44,18 @@ impl Name {
Self::new()
}
/// Returns true if there are no labels, i.e. it's empty.
///
/// In DNS the root is represented by `.`
///
/// # Examples
///
/// ```
/// use trust_dns::rr::domain::Name;
///
/// let root = Name::root();
/// assert_eq!(&root.to_string(), ".");
/// ```
pub fn is_root(&self) -> bool {
self.labels.is_empty()
}
@ -98,6 +110,8 @@ impl Name {
/// Creates a new Name with all labels lowercased
///
/// # Examples
///
/// ```
/// use trust_dns::rr::domain::Name;
/// use std::cmp::Ordering;
@ -116,6 +130,8 @@ impl Name {
/// Trims off the first part of the name, to help with searching for the domain piece
///
/// # Examples
///
/// ```
/// use trust_dns::rr::domain::Name;
///
@ -135,6 +151,8 @@ impl Name {
/// Trims to the number of labels specified
///
/// # Examples
///
/// ```
/// use trust_dns::rr::domain::Name;
///
@ -169,6 +187,22 @@ impl Name {
return true;
}
/// Returns the number of labels in the name, discounting `*`.
///
/// # Examples
///
/// ```
/// use trust_dns::rr::domain::Name;
///
/// let root = Name::root();
/// assert_eq!(root.num_labels(), 0);
///
/// let example_com = Name::new().label("example").label("com");
/// assert_eq!(example_com.num_labels(), 2);
///
/// let star_example_com = Name::new().label("*").label("example").label("com");
/// assert_eq!(star_example_com.num_labels(), 2);
/// ```
pub fn num_labels(&self) -> u8 {
// it is illegal to have more than 256 labels.
let num = self.labels.len() as u8;
@ -180,6 +214,9 @@ impl Name {
}
/// returns the length in bytes of the labels. '.' counts as 1
///
/// This can be used as an estimate, when serializing labels, they will often be compressed
/// and/or escaped causing the exact length to be different.
pub fn len(&self) -> usize {
let dots = if self.labels.len() > 0 { self.labels.len() } else { 1 };
self.labels.iter().fold(dots, |acc, item| acc + item.len())
@ -256,6 +293,9 @@ impl Name {
Ok(name)
}
/// Emits the canonical version of the name to the encoder.
///
/// In canonical form, there will be no pointers written to the encoder (i.e. no compression).
pub fn emit_as_canonical(&self, encoder: &mut BinEncoder, canonical: bool) -> EncodeResult {
let buf_len = encoder.len(); // lazily assert the size is less than 255...
// lookup the label in the BinEncoder
@ -337,6 +377,15 @@ impl Name {
self.labels.len().cmp(&other.labels.len())
}
/// Converts the Name labels to the String form.
///
/// This converts the name to an unescaped format, that could be used with parse. The name is
/// is followed by the final `.`, e.g. as in `www.example.com.`, which represents a fully
/// qualified Name.
pub fn to_string(&self) -> String {
format!("{}", self)
}
}
impl Hash for Name {
@ -441,6 +490,7 @@ impl BinSerializable<Name> for Name {
}
}
/// FIXME: this needs to escape characters in the labels.
impl fmt::Display for Name {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for label in &*self.labels {

View File

@ -104,6 +104,24 @@ impl Record {
}
}
/// Create a record with the specified initial values.
///
/// # Arguments
///
/// * `name` - name of the resource records
/// * `rr_type` - the record type
/// * `ttl` - time-to-live is the amount of time this record should be cached before refreshing
/// * `rdata` - record data to associate with the Record
pub fn from_rdata(name: domain::Name, ttl: u32, record_type: RecordType, rdata: RData) -> Record {
Record {
name_labels: name,
rr_type: record_type,
dns_class: DNSClass::IN,
ttl: ttl,
rdata: rdata,
}
}
/// ```text
/// NAME a domain name to which this resource record pertains.
/// ```

View File

@ -56,7 +56,7 @@ futures = "^0.1"
lazy_static = "^0.2.1"
log = "^0.3.5"
mio = "^0.5.1"
openssl = { version = "0.9.4", git = "https://github.com/bluejekyll/rust-openssl.git" }
openssl = "^0.9.5"
rand = "^0.3"
rustc-serialize = "^0.3.18"
rusqlite = "^0.7.3"

View File

@ -38,6 +38,7 @@ pub struct Authority {
records: BTreeMap<RrKey, RecordSet>,
zone_type: ZoneType,
allow_update: bool,
is_dnssec_enabled: bool,
// Private key mapped to the Record of the DNSKey
// TODO: these private_keys should be stored securely. Ideally, we have keys only stored per
// server instance, but that requires requesting updates from the parent zone, which may or
@ -56,13 +57,15 @@ impl Authority {
/// * `records` - The map of the initial set of records in the zone.
/// * `zone_type` - The type of zone, i.e. is this authoritative?
/// * `allow_update` - If true, then this zone accepts dynamic updates.
/// * `is_dnssec_enabled` - If true, then the zone will sign the zone with all registered keys,
/// (see `add_secure_key()`)
///
/// # Return value
///
/// The new `Authority`.
pub fn new(origin: Name, records: BTreeMap<RrKey, RecordSet>, zone_type: ZoneType, allow_update: bool) -> Authority {
pub fn new(origin: Name, records: BTreeMap<RrKey, RecordSet>, zone_type: ZoneType, allow_update: bool, is_dnssec_enabled: bool) -> Authority {
Authority{ origin: origin, class: DNSClass::IN, journal: None, records: records, zone_type: zone_type,
allow_update: allow_update, secure_keys: Vec::new() }
allow_update: allow_update, is_dnssec_enabled: is_dnssec_enabled, secure_keys: Vec::new() }
}
/// By adding a secure key, this will implicitly enable dnssec for the zone.
@ -73,8 +76,8 @@ impl Authority {
pub fn add_secure_key(&mut self, signer: Signer) -> DnsSecResult<()> {
// also add the key to the zone
let zone_ttl = self.get_minimum_ttl();
let dnskey = try!(signer.get_key()
.to_dnskey(self.origin.clone(), zone_ttl, signer.get_algorithm()));
let dnskey = try!(signer.get_key().to_dnskey(signer.get_algorithm()));
let dnskey = Record::from_rdata(self.origin.clone(), zone_ttl, RecordType::DNSKEY, RData::DNSKEY(dnskey));
// TODO: also generate the CDS and CDNSKEY
let serial = self.get_serial();
@ -107,7 +110,11 @@ impl Authority {
}
// zone signing was off during load, now sign the zone.
self.sign_zone().map_err(|e| e.into())
if self.is_dnssec_enabled {
self.sign_zone().map_err(|e| e.into())
} else {
Ok(())
}
}
/// Persist the state of the current zone to the journal, does nothing if there is no associated
@ -440,14 +447,14 @@ impl Authority {
keys.iter()
.filter_map(|rr_set| if let &RData::KEY(ref key) = rr_set.get_rdata() { Some(key) } else { None })
.any(|key| {
let pkey = KeyPair::from_vec(key.get_public_key(), *key.get_algorithm());
let pkey = KeyPair::from_public_bytes(key.get_public_key(), *key.get_algorithm());
if let Err(error) = pkey {
warn!("public key {:?} of {} could not be used: {}", key, name, error);
return false
}
let pkey = pkey.unwrap();
let signer: Signer = Signer::new_verifier(*key.get_algorithm(), pkey, sig.get_signer_name().clone());
let signer: Signer = Signer::new_verifier(*key.get_algorithm(), pkey, sig.get_signer_name().clone(), false, true);
signer.verify_message(update_message, sig.get_sig())
.map(|_| {
@ -570,9 +577,9 @@ impl Authority {
/// # Arguments
///
/// * `records` - set of record instructions for update following above rules
/// * `auto_sign` - if true, the zone will auto_sign (assuming there are signers present), this
/// should be disabled during recovery.
pub fn update_records(&mut self, records: &[Record], auto_sign: bool) -> UpdateResult<bool> {
/// * `auto_signing_and_increment` - if true, the zone will sign and increment the SOA, this
/// should be disabled during recovery.
pub fn update_records(&mut self, records: &[Record], auto_signing_and_increment: bool) -> UpdateResult<bool> {
let mut updated = false;
let serial: u32 = self.get_serial();
@ -706,11 +713,17 @@ impl Authority {
}
// update the serial...
if auto_sign && updated {
try!(self.secure_zone().map_err(|e| {
error!("failure securing zone: {}", e);
ResponseCode::ServFail
}))
if updated && auto_signing_and_increment {
if self.is_dnssec_enabled {
try!(self.secure_zone().map_err(|e| {
error!("failure securing zone: {}", e);
ResponseCode::ServFail
}))
} else {
// the secure_zone() function increments the SOA during it's operation, if we're not
// dnssec, then we need to do it here...
self.increment_soa_serial();
}
}
Ok(updated)
@ -974,6 +987,11 @@ impl Authority {
let inception = UTC::now();
let zone_ttl = self.get_minimum_ttl();
// TODO: should this be an error?
if self.secure_keys.is_empty() {
warn!("attempt to sign_zone for dnssec, but no keys available!")
}
for rr_set in self.records.iter_mut().filter_map(|(_, rr_set)| {
// do not sign zone DNSKEY's that's the job of the parent zone
if rr_set.get_record_type() == RecordType::DNSKEY { return None }

View File

@ -21,6 +21,8 @@ use std::sync::RwLock;
use trust_dns::op::{Edns, Message, MessageType, OpCode, Query, UpdateMessage, RequestHandler, ResponseCode};
use trust_dns::rr::{Name, RecordType};
use trust_dns::rr::dnssec::{Algorithm, SupportedAlgorithms};
use trust_dns::rr::rdata::opt::EdnsOption;
use ::authority::{Authority, ZoneType};
@ -98,16 +100,13 @@ impl RequestHandler for Catalog {
},
};
if let Some(resp_edns) = resp_edns_opt {
if let Some(mut resp_edns) = resp_edns_opt {
// set edns DAU and DHU
// send along the algorithms which are supported by this authority
let mut algorithms = SupportedAlgorithms::new();
#[cfg(feature = "openssl")] {
algorithms.set(Algorithm::RSASHA256);
algorithms.set(Algorithm::ECDSAP256SHA256);
algorithms.set(Algorithm::ECDSAP384SHA384);
}
#[cfg(feature = "ring")]
algorithms.set(Algorithm::RSASHA256);
algorithms.set(Algorithm::ECDSAP256SHA256);
algorithms.set(Algorithm::ECDSAP384SHA384);
algorithms.set(Algorithm::ED25519);
let dau = EdnsOption::DAU(algorithms);
@ -116,7 +115,6 @@ impl RequestHandler for Catalog {
resp_edns.set_option(dau);
resp_edns.set_option(dhu);
response.set_edns(resp_edns);
// TODO: if DNSSec supported, sign the package with SIG0
// get this servers private key ideally use pkcs11
@ -236,10 +234,8 @@ impl Catalog {
/// # Arguments
///
/// * `request` - the query message.
/// * `request_algorithms` - algorithms which this authority supports
pub fn lookup(&self,
request: &Message,
request_algorithms: SupportedAlgorithms) -> (Message, SupportedAlgorithms) {
request: &Message) -> Message {
let mut response: Message = Message::new();
response.id(request.get_id());
response.op_code(OpCode::Query);

View File

@ -27,8 +27,9 @@ use log::LogLevel;
use rustc_serialize::Decodable;
use toml::{Decoder, Value};
use trust_dns::error::ParseResult;
use trust_dns::error::*;
use trust_dns::rr::Name;
use trust_dns::rr::dnssec::Algorithm;
use ::authority::ZoneType;
use ::error::{ConfigErrorKind, ConfigResult, ConfigError};
@ -57,10 +58,17 @@ impl Config {
toml.parse()
}
/// set of listening ipv4 addresses (for TCP and UDP)
pub fn get_listen_addrs_ipv4(&self) -> Vec<Ipv4Addr> { self.listen_addrs_ipv4.iter().map(|s| s.parse().unwrap()).collect() }
/// set of listening ipv6 addresses (for TCP and UDP)
pub fn get_listen_addrs_ipv6(&self) -> Vec<Ipv6Addr> { self.listen_addrs_ipv6.iter().map(|s| s.parse().unwrap()).collect() }
/// port on which to listen for connections on specified addresses
pub fn get_listen_port(&self) -> u16 { self.listen_port.unwrap_or(DEFAULT_PORT) }
/// default timeout for all TCP connections before forceably shutdown
pub fn get_tcp_request_timeout(&self) -> Duration { Duration::from_secs(self.tcp_request_timeout.unwrap_or(DEFAULT_TCP_REQUEST_TIMEOUT)) }
// TODO: also support env_logger
/// specify the log level which should be used, ["Trace", "Debug", "Info", "Warn", "Error"]
pub fn get_log_level(&self) -> LogLevel {
if let Some(ref level_str) = self.log_level {
match level_str as &str {
@ -75,7 +83,9 @@ impl Config {
LogLevel::Info
}
}
/// the path for all zone configurations, defaults to `/var/named`
pub fn get_directory(&self) -> &Path { self.directory.as_ref().map_or(Path::new(DEFAULT_PATH), |s|Path::new(s)) }
/// the set of zones which should be loaded
pub fn get_zones(&self) -> &[ZoneConfig] { &self.zones }
}
@ -96,17 +106,88 @@ pub struct ZoneConfig {
file: String,
allow_update: Option<bool>,
enable_dnssec: Option<bool>,
keys: Vec<KeyConfig>,
}
impl ZoneConfig {
pub fn new(zone: String, zone_type: ZoneType, file: String, allow_update: Option<bool>, enable_dnssec: Option<bool>) -> Self {
ZoneConfig{zone: zone, zone_type: zone_type, file: file, allow_update: allow_update, enable_dnssec: enable_dnssec }
pub fn new(zone: String, zone_type: ZoneType, file: String, allow_update: Option<bool>,
enable_dnssec: Option<bool>, keys: Vec<KeyConfig>) -> Self {
ZoneConfig{zone: zone, zone_type: zone_type, file: file, allow_update: allow_update,
enable_dnssec: enable_dnssec, keys: keys}
}
// TODO this is a little ugly for the parse, b/c there is no terminal char
/// retuns the name of the Zone, i.e. the `example.com` of `www.example.com.`
pub fn get_zone(&self) -> ParseResult<Name> { Name::parse(&self.zone, Some(&Name::new())) }
/// the type of the zone
pub fn get_zone_type(&self) -> ZoneType { self.zone_type }
/// path to the zone file, i.e. the base set of original records in the zone
///
/// this is ony used on first load, if dynamic update is enabled for the zone, then the journal
/// file is the actual source of truth for the zone.
pub fn get_file(&self) -> PathBuf { PathBuf::from(&self.file) }
/// enable dynamic updates for the zone (see SIG0 and the registered keys)
pub fn is_update_allowed(&self) -> bool { self.allow_update.unwrap_or(false) }
/// declare that this zone should be signed, see keys for configuration of the keys for signing
pub fn is_dnssec_enabled(&self) -> bool { self.enable_dnssec.unwrap_or(false) }
/// the configuration for the keys used for auth and/or dnssec zone signing.
pub fn get_keys(&self) -> &[KeyConfig] {
&self.keys
}
}
#[derive(RustcDecodable, PartialEq, Debug)]
pub struct KeyConfig {
key_path: String,
algorithm: String,
signer_name: Option<String>,
is_zone_signing_key: Option<bool>,
is_zone_update_auth: Option<bool>,
do_auto_generate: Option<bool>,
}
impl KeyConfig {
pub fn new(key_path: String, algorithm: Algorithm, signer_name: String,
is_zone_signing_key: bool, is_zone_update_auth: bool, do_auto_generate: bool) -> Self {
KeyConfig{ key_path: key_path, algorithm: algorithm.to_str().to_string(), signer_name: Some(signer_name),
is_zone_signing_key: Some(is_zone_signing_key), is_zone_update_auth: Some(is_zone_update_auth),
do_auto_generate: Some(do_auto_generate)
}
}
/// path to the key file, either relative to the zone file, or a explicit from the root.
pub fn get_key_path(&self) -> &Path { Path::new(&self.key_path) }
/// algorithm for for the key, see `Algorithm` for supported algorithms.
pub fn get_algorithm(&self) -> ParseResult<Algorithm> { Algorithm::from_str(&self.algorithm).map_err(|e|e.into()) }
/// the signer name for the key, this defaults to the $ORIGIN aka zone name.
pub fn get_signer_name(&self) -> ParseResult<Option<Name>> {
if let Some(ref signer_name) = self.signer_name.as_ref() {
let name = try!(Name::parse(signer_name, None));
return Ok(Some(name))
}
Ok(None)
}
/// specifies that this key should be used to sign the zone
///
/// The public key for this must be trusted by a resolver to work. The key must have a private
/// portion associated with it. It will be registered as a DNSKEY in the zone.
pub fn is_zone_signing_key(&self) -> bool { self.is_zone_signing_key.unwrap_or(false) }
/// this is at least a public_key, and can be used for SIG0 dynamic updates.
///
/// it will be registered as a KEY record in the zone.
pub fn is_zone_update_auth(&self) -> bool { self.is_zone_update_auth.unwrap_or(false) }
/// auto generate/create the key if it doesn't already exist (the public portion can be
/// retrieved by a DNS query to the zone for DNSKEY and KEY records).
pub fn do_auto_generate(&self) -> bool { self.do_auto_generate.unwrap_or(false) }
}

View File

@ -48,7 +48,6 @@ use std::io::{Read, Write};
use chrono::{Duration};
use docopt::Docopt;
use log::LogLevel;
use openssl::rsa::Rsa;
use trust_dns::error::ParseResult;
use trust_dns::logger;
@ -58,7 +57,7 @@ use trust_dns::rr::Name;
use trust_dns::rr::dnssec::{Algorithm, KeyPair, Signer};
use trust_dns_server::authority::{Authority, Catalog, Journal, ZoneType};
use trust_dns_server::config::{Config, ZoneConfig};
use trust_dns_server::config::{Config, KeyConfig, ZoneConfig};
use trust_dns_server::server::ServerFuture;
// the Docopt usage string.
@ -89,7 +88,7 @@ struct Args {
pub flag_port: Option<u16>,
}
fn parse_file(file: File, origin: Option<Name>, zone_type: ZoneType, allow_update: bool) -> ParseResult<Authority> {
fn parse_file(file: File, origin: Option<Name>, zone_type: ZoneType, allow_update: bool, is_dnssec_enabled: bool) -> ParseResult<Authority> {
let mut file = file;
let mut buf = String::new();
@ -99,27 +98,22 @@ fn parse_file(file: File, origin: Option<Name>, zone_type: ZoneType, allow_updat
let lexer = Lexer::new(&buf);
let (origin, records) = try!(Parser::new().parse(lexer, origin));
Ok(Authority::new(origin, records, zone_type, allow_update))
Ok(Authority::new(origin, records, zone_type, allow_update, is_dnssec_enabled))
}
fn load_zone(zone_dir: &Path, zone: &ZoneConfig) -> Result<Authority, String> {
let zone_name: Name = zone.get_zone().expect("bad zone name");
let zone_path: PathBuf = zone_dir.to_owned().join(zone.get_file());
fn load_zone(zone_dir: &Path, zone_config: &ZoneConfig) -> Result<Authority, String> {
let zone_name: Name = zone_config.get_zone().expect("bad zone name");
let zone_path: PathBuf = zone_dir.to_owned().join(zone_config.get_file());
let journal_path: PathBuf = zone_path.with_extension("jrnl");
let key_path: PathBuf = zone_path.with_extension("key");
let original_key_path: PathBuf = zone_path.with_extension("key");
// load the zone
let mut authority = if zone.is_update_allowed() && journal_path.exists() {
let mut authority = if zone_config.is_update_allowed() && journal_path.exists() {
info!("recovering zone from journal: {:?}", journal_path);
let journal = match Journal::from_file(&journal_path) {
Ok(j) => j,
Err(e) => return Err(format!("error opening journal: {:?}: {}", journal_path, e)),
};
let journal = try!(Journal::from_file(&journal_path).map_err(|e| format!("error opening journal: {:?}: {}", journal_path, e)));
let mut authority = Authority::new(zone_name.clone(), BTreeMap::new(), zone.get_zone_type(), zone.is_update_allowed());
if let Err(e) = authority.recover_with_journal(&journal) {
return Err(format!("error recovering from journal: {}", e))
}
let mut authority = Authority::new(zone_name.clone(), BTreeMap::new(), zone_config.get_zone_type(), zone_config.is_update_allowed(), zone_config.is_dnssec_enabled());
try!(authority.recover_with_journal(&journal).map_err(|e| format!("error recovering from journal: {}", e)));
authority.journal(journal);
info!("recovered zone: {}", zone_name);
@ -128,30 +122,24 @@ fn load_zone(zone_dir: &Path, zone: &ZoneConfig) -> Result<Authority, String> {
} else if zone_path.exists() {
info!("loading zone file: {:?}", zone_path);
let zone_file = match File::open(&zone_path) {
Ok(f) => f,
Err(e) => return Err(format!("error opening zone file: {:?}: {}", zone_path, e)),
};
let zone_file = try!(File::open(&zone_path).map_err(|e| format!("error opening zone file: {:?}: {}", zone_path, e)));
let mut authority: Authority = match parse_file(zone_file, Some(zone_name.clone()), zone.get_zone_type(), zone.is_update_allowed()) {
Ok(a) => a,
Err(e) => return Err(format!("error reading zone: {:?}: {}", zone_path, e)),
};
let mut authority = try!(parse_file(zone_file,
Some(zone_name.clone()),
zone_config.get_zone_type(),
zone_config.is_update_allowed(),
zone_config.is_dnssec_enabled())
.map_err(|e| format!("error reading zone: {:?}: {}", zone_path, e)));
// if dynamic update is enabled, enable the journal
if zone.is_update_allowed() {
if zone_config.is_update_allowed() {
info!("enabling journal: {:?}", journal_path);
let journal = match Journal::from_file(&journal_path) {
Ok(j) => j,
Err(e) => return Err(format!("error creating journal {:?}: {}", journal_path, e)),
};
let journal = try!(Journal::from_file(&journal_path).map_err(|e| format!("error creating journal {:?}: {}", journal_path, e)));
authority.journal(journal);
// preserve to the new journal, i.e. we just loaded the zone from disk, start the journal
if let Err(e) = authority.persist_to_journal() {
return Err(format!("error persisting to journal {:?}: {}", journal_path, e))
}
try!(authority.persist_to_journal().map_err(|e| format!("error persisting to journal {:?}: {}", journal_path, e)));
}
info!("loaded zone: {}", zone_name);
@ -161,55 +149,85 @@ fn load_zone(zone_dir: &Path, zone: &ZoneConfig) -> Result<Authority, String> {
};
// load any keys for the Zone, if it is a dynamic update zone, then keys are required
if zone.is_dnssec_enabled() {
let rsa = if key_path.exists() {
info!("reading key: {:?}", key_path);
// TODO: validate owndership
let mut file = match File::open(&key_path) {
Ok(f) => f,
Err(e) => return Err(format!("error opening private key file: {:?}: {}", key_path, e)),
};
let mut rsa_bytes = Vec::with_capacity(256);
try!(file.read_to_end(&mut rsa_bytes).map_err(|e| format!("could not read rsa key from: {:?}: {}", key_path, e)));
match Rsa::private_key_from_pem(&rsa_bytes) {
Ok(rsa) => rsa,
Err(e) => return Err(format!("error reading private key file: {:?}: {}", key_path, e)),
}
if zone_config.is_dnssec_enabled() {
// old backward compatible logic, TODO: deprecated
if zone_config.get_keys().is_empty() {
// original RSA key construction
let key_config = KeyConfig::new(original_key_path.to_string_lossy().to_string(),
Algorithm::RSASHA256,
zone_name.clone().to_string(),
true,
true,
true);
let signer = try!(load_key(zone_name, &key_config).map_err(|e| format!("failed to load key: {:?} msg: {}", key_config.get_key_path(), e)));
info!("adding key to zone: {:?}, is_zsk: {}, is_auth: {}", key_config.get_key_path(), key_config.is_zone_signing_key(), key_config.is_zone_update_auth());
authority.add_secure_key(signer).expect("failed to add key to authority");
} else {
info!("creating key: {:?}", key_path);
// TODO: establish proper ownership
let mut file = match File::create(&key_path) {
Ok(f) => f,
Err(e) => return Err(format!("error creating private key file: {:?}: {}", key_path, e))
};
let rsa: Rsa = try!(Rsa::generate(2048).map_err(|e| format!("could not generate rsa key: {}", e)));
let rsa_bytes = try!(rsa.private_key_to_pem().map_err(|e| format!("could not get rsa pem bytes: {}", e)));
if let Err(e) = file.write_all(&rsa_bytes) {
fs::remove_file(&key_path).ok(); // ignored
return Err(format!("error writing private key file: {:?}: {}", key_path, e))
for key_config in zone_config.get_keys() {
let signer = try!(load_key(zone_name.clone(), &key_config).map_err(|e| format!("failed to load key: {:?} msg: {}", key_config.get_key_path(), e)));
info!("adding key to zone: {:?}, is_zsk: {}, is_auth: {}", key_config.get_key_path(), key_config.is_zone_signing_key(), key_config.is_zone_update_auth());
authority.add_secure_key(signer).expect("failed to add key to authority");
}
rsa
};
let pkey = KeyPair::from_rsa(rsa).expect("error converting RSA to KeyPair");
// add the key to the zone
// TODO: allow the duration of signatutes to be customized
let signer = Signer::new(Algorithm::RSASHA256, pkey, authority.get_origin().clone(), Duration::weeks(52));
authority.add_secure_key(signer).expect("failed to add key to authority");
}
}
Ok(authority)
}
/// set of DNSSEC algorithms to use to sign the zone. enable_dnssec must be true.
/// these will be lookedup by $file.{key_name}.pem, for backward compatability
/// with previous versions of TRust-DNS, if enable_dnssec is enabled but
/// supported_algorithms is not specified, it will default to "RSASHA256" and
/// look for the $file.pem for the key. To control key length, or other options
/// keys of the specified formats can be generated in PEM format. Instructions
/// for custom keys can be found elsewhere.
///
/// the currently supported set of supported_algorithms are
/// ["RSASHA256", "RSASHA512", "ECDSAP256SHA256", "ECDSAP384SHA384", "ED25519"]
///
/// keys are listed in pairs of key_name and algorithm, the search path is the
/// same directory has the zone $file:
/// keys = [ "my_rsa_2048|RSASHA256", "/path/to/my_ed25519|ED25519" ]
fn load_key(zone_name: Name, key_config: &KeyConfig) -> Result<Signer, String> {
let key_path = key_config.get_key_path();
let algorithm = try!(key_config.get_algorithm().map_err(|e| format!("bad algorithm: {}", e)));
let key: KeyPair = if key_path.exists() {
info!("reading key: {:?}", key_path);
// TODO: validate owndership
let mut file = try!(File::open(&key_path).map_err(|e| format!("error opening private key file: {:?}: {}", key_path, e)));
let mut key_bytes = Vec::with_capacity(256);
try!(file.read_to_end(&mut key_bytes).map_err(|e| format!("could not read rsa key from: {:?}: {}", key_path, e)));
try!(KeyPair::from_private_bytes(algorithm, &key_bytes).map_err(|e| format!("error reading private key file: {:?}: {}", key_path, e)))
} else if key_config.do_auto_generate() {
info!("creating key: {:?}", key_path);
// TODO: establish proper ownership
let mut file = try!(File::create(&key_path).map_err(|e| format!("error creating private key file: {:?}: {}", key_path, e)));
let key = try!(KeyPair::generate(algorithm).map_err(|e| format!("could not generate key: {}", e)));
let key_bytes: Vec<u8> = try!(key.to_private_bytes().map_err(|e| format!("could not get key bytes: {}", e)));
try!(file.write_all(&key_bytes)
.or_else(|_| fs::remove_file(&key_path))
.map_err(|e| format!("error writing private key file: {:?}: {}", key_path, e)));
key
} else {
return Err(format!("file not found: {:?}", key_path))
};
let name = try!(key_config.get_signer_name().map_err(|e| format!("error reading name: {}", e)))
.unwrap_or(zone_name);
// add the key to the zone
// TODO: allow the duration of signatutes to be customized
Ok(Signer::new(Algorithm::RSASHA256, key, name, Duration::weeks(52), true, true))
}
/// Main method for running the named server.
///
/// `Note`: Tries to avoid panics, in favor of always starting.

View File

@ -322,9 +322,10 @@ fn test_journal() {
// that record should have been recorded... let's reload the journal and see if we get it.
let mut recovered_authority = Authority::new(authority.get_origin().clone(),
BTreeMap::new(),
ZoneType::Master,
false);
BTreeMap::new(),
ZoneType::Master,
false,
false);
recovered_authority.recover_with_journal(authority.get_journal().expect("journal not Some")).expect("recovery");
// assert that the correct set of records is there.
@ -348,9 +349,10 @@ fn test_recovery() {
let journal = authority.get_journal().unwrap();
let mut recovered_authority = Authority::new(authority.get_origin().clone(),
BTreeMap::new(),
ZoneType::Master,
false);
BTreeMap::new(),
ZoneType::Master,
false,
false);
recovered_authority.recover_with_journal(journal).expect("recovery");

View File

@ -18,7 +18,7 @@ use common::authority::create_example;
pub fn create_test() -> Authority {
let origin: Name = Name::parse("test.com.", None).unwrap();
let mut records: Authority = Authority::new(origin.clone(), BTreeMap::new(), ZoneType::Master, false);
let mut records: Authority = Authority::new(origin.clone(), BTreeMap::new(), ZoneType::Master, false, false);
records.upsert(Record::new().name(origin.clone()).ttl(3600).rr_type(RecordType::SOA).dns_class(DNSClass::IN).rdata(RData::SOA(SOA::new(Name::parse("sns.dns.icann.org.", None).unwrap(), Name::parse("noc.dns.icann.org.", None).unwrap(), 2015082403, 7200, 3600, 1209600, 3600 ))).clone(), 0);
records.upsert(Record::new().name(origin.clone()).ttl(86400).rr_type(RecordType::NS).dns_class(DNSClass::IN).rdata(RData::NS(Name::parse("a.iana-servers.net.", None).unwrap()) ).clone(), 0);

View File

@ -172,13 +172,15 @@ fn create_sig0_ready_client(io_loop: &Core) -> (BasicClientHandle, domain::Name)
let signer = Signer::new(Algorithm::RSASHA256,
key,
domain::Name::with_labels(vec!["trusted".to_string(), "example".to_string(), "com".to_string()]),
Duration::max_value());
Duration::max_value(),
true,
true);
// insert the KEY for the trusted.example.com
let mut auth_key = Record::with(domain::Name::with_labels(vec!["trusted".to_string(), "example".to_string(), "com".to_string()]),
RecordType::KEY,
Duration::minutes(5).num_seconds() as u32);
auth_key.rdata(RData::KEY(DNSKEY::new(false, false, false, signer.get_algorithm(), signer.get_key().to_vec().expect("to_vec failed"))));
auth_key.rdata(RData::KEY(DNSKEY::new(false, false, false, signer.get_algorithm(), signer.get_key().to_public_bytes().expect("to_vec failed"))));
authority.upsert(auth_key, 0);
// setup the catalog

View File

@ -128,7 +128,7 @@ fn test_secure_query_example_nonet() {
let public_key = signers.first().expect("expected a key in the authority").get_key();
let mut trust_anchor = TrustAnchor::new();
trust_anchor.insert_trust_anchor(public_key.to_vec().expect("to_vec failed"));
trust_anchor.insert_trust_anchor(public_key.to_public_bytes().expect("to_vec failed"));
trust_anchor
};
@ -233,7 +233,7 @@ fn test_nsec_query_example_nonet() {
let public_key = signers.first().expect("expected a key in the authority").get_key();
let mut trust_anchor = TrustAnchor::new();
trust_anchor.insert_trust_anchor(public_key.to_vec().expect("to_vec failed"));
trust_anchor.insert_trust_anchor(public_key.to_public_bytes().expect("to_vec failed"));
trust_anchor
};
@ -343,13 +343,13 @@ fn create_sig0_ready_client<'a>(catalog: &'a mut Catalog) -> (Client<TestClientC
let signer = Signer::new(Algorithm::RSASHA256, key,
domain::Name::with_labels(vec!["trusted".to_string(), "example".to_string(), "com".to_string()]),
Duration::max_value());
Duration::max_value(), true, true);
// insert the KEY for the trusted.example.com
let mut auth_key = Record::with(domain::Name::with_labels(vec!["trusted".to_string(), "example".to_string(), "com".to_string()]),
RecordType::KEY,
Duration::minutes(5).num_seconds() as u32);
auth_key.rdata(RData::KEY(DNSKEY::new(false, false, false, signer.get_algorithm(), signer.get_key().to_vec().expect("to_vec failed"))));
auth_key.rdata(RData::KEY(DNSKEY::new(false, false, false, signer.get_algorithm(), signer.get_key().to_public_bytes().expect("to_vec failed"))));
authority.upsert(auth_key, 0);
catalog.upsert(authority.get_origin().clone(), authority);

View File

@ -11,7 +11,7 @@ pub fn create_example() -> Authority {
use trust_dns::rr::rdata::*;
let origin: Name = Name::parse("example.com.", None,).unwrap();
let mut records: Authority = Authority::new(origin.clone(), BTreeMap::new(), ZoneType::Master, false);
let mut records: Authority = Authority::new(origin.clone(), BTreeMap::new(), ZoneType::Master, false, false);
// example.com. 3600 IN SOA sns.dns.icann.org. noc.dns.icann.org. 2015082403 7200 3600 1209600 3600
records.upsert(Record::new().name(origin.clone()).ttl(3600).rr_type(RecordType::SOA).dns_class(DNSClass::IN).rdata(RData::SOA(SOA::new(Name::parse("sns.dns.icann.org.", None).unwrap(), Name::parse("noc.dns.icann.org.", None).unwrap(), 2015082403, 7200, 3600, 1209600, 3600 ))).clone(), 0);
@ -73,7 +73,7 @@ pub fn create_secure_example() -> Authority {
let mut authority: Authority = create_example();
let rsa = Rsa::generate(2048).unwrap();
let key = KeyPair::from_rsa(rsa).unwrap();
let signer = Signer::new(Algorithm::RSASHA256, key, authority.get_origin().clone(), Duration::weeks(1));
let signer = Signer::new(Algorithm::RSASHA256, key, authority.get_origin().clone(), Duration::weeks(1), true, true);
authority.add_secure_key(signer);
authority.secure_zone();

View File

@ -14,6 +14,7 @@
* limitations under the License.
*/
extern crate log;
extern crate trust_dns;
extern crate trust_dns_server;
use std::env;
@ -23,6 +24,9 @@ use std::time::Duration;
use log::LogLevel;
use trust_dns::rr::Name;
use trust_dns::rr::dnssec::Algorithm;
use trust_dns_server::authority::ZoneType;
use trust_dns_server::config::*;
@ -45,12 +49,12 @@ fn test_read_config() {
assert_eq!(config.get_log_level(), LogLevel::Info);
assert_eq!(config.get_directory(), Path::new("/var/named"));
assert_eq!(config.get_zones(), [
ZoneConfig::new("localhost".into(), ZoneType::Master, "default/localhost.zone".into(), None, None),
ZoneConfig::new("0.0.127.in-addr.arpa".into(), ZoneType::Master, "default/127.0.0.1.zone".into(), None, None),
ZoneConfig::new("0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa".into(), ZoneType::Master, "default/ipv6_1.zone".into(), None, None),
ZoneConfig::new("255.in-addr.arpa".into(), ZoneType::Master, "default/255.zone".into(), None, None),
ZoneConfig::new("0.in-addr.arpa".into(), ZoneType::Master, "default/0.zone".into(), None, None),
ZoneConfig::new("example.com".into(), ZoneType::Master, "example.com.zone".into(), None, None),
ZoneConfig::new("localhost".into(), ZoneType::Master, "default/localhost.zone".into(), None, None, vec![]),
ZoneConfig::new("0.0.127.in-addr.arpa".into(), ZoneType::Master, "default/127.0.0.1.zone".into(), None, None, vec![]),
ZoneConfig::new("0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa".into(), ZoneType::Master, "default/ipv6_1.zone".into(), None, None, vec![]),
ZoneConfig::new("255.in-addr.arpa".into(), ZoneType::Master, "default/255.zone".into(), None, None, vec![]),
ZoneConfig::new("0.in-addr.arpa".into(), ZoneType::Master, "default/0.zone".into(), None, None, vec![]),
ZoneConfig::new("example.com".into(), ZoneType::Master, "example.com.zone".into(), None, None, vec![]),
]);
}
@ -79,4 +83,38 @@ fn test_parse_toml() {
let config: Config = "directory = \"/dev/null\"".parse().unwrap();
assert_eq!(config.get_directory(), Path::new("/dev/null"));
let config: Config = "
[[zones]]
zone = \"example.com\"
zone_type = \"Master\"
file = \"example.com.zone\"
[[zones.keys]]
key_path = \"/path/to/my_ed25519.pem\"
algorithm = \"ED25519\"
signer_name = \"ns.example.com.\"
is_zone_signing_key = false
is_zone_update_auth = true
do_auto_generate = true
[[zones.keys]]
key_path = \"/path/to/my_rsa.pem\"
algorithm = \"RSASHA256\"
signer_name = \"ns.example.com.\"
".parse().unwrap();
assert_eq!(config.get_zones()[0].get_keys()[0].get_key_path(), Path::new("/path/to/my_ed25519.pem"));
assert_eq!(config.get_zones()[0].get_keys()[0].get_algorithm().unwrap(), Algorithm::ED25519);
assert_eq!(config.get_zones()[0].get_keys()[0].get_signer_name().unwrap().unwrap(), Name::parse("ns.example.com.", None).unwrap());
assert_eq!(config.get_zones()[0].get_keys()[0].is_zone_signing_key(), false);
assert_eq!(config.get_zones()[0].get_keys()[0].is_zone_update_auth(), true);
assert_eq!(config.get_zones()[0].get_keys()[0].do_auto_generate(), true);
assert_eq!(config.get_zones()[0].get_keys()[1].get_key_path(), Path::new("/path/to/my_rsa.pem"));
assert_eq!(config.get_zones()[0].get_keys()[1].get_algorithm().unwrap(), Algorithm::RSASHA256);
assert_eq!(config.get_zones()[0].get_keys()[1].get_signer_name().unwrap().unwrap(), Name::parse("ns.example.com.", None).unwrap());
assert_eq!(config.get_zones()[0].get_keys()[1].is_zone_signing_key(), false);
assert_eq!(config.get_zones()[0].get_keys()[1].is_zone_update_auth(), false);
assert_eq!(config.get_zones()[0].get_keys()[1].do_auto_generate(), false);
}

View File

@ -78,8 +78,41 @@ file = "example.com.zone"
## if false, updates will not be allowed, default false
# allow_update = false
## if true, looks to see if a chained pem file exists at $file.pem
## if true, looks to see if a chained pem file exists at $file.pem (see
## supported_algorithms below).
## these keys will also be registered as authorities for update,
## meaning that SIG(0) updates can be established by initially using these
## keys.
## keys. the zone will be signed with all specified keys, it may be desirable
## to limit this set for performance reasons.
# enable_dnssec = false
## set of DNSSEC algorithms to use to sign the zone. enable_dnssec must be true.
## these will be lookedup by $file.{key_name}.pem, for backward compatability
## with previous versions of TRust-DNS, if enable_dnssec is enabled but
## supported_algorithms is not specified, it will default to "RSASHA256" and
## look for the $file.pem for the key. To control key length, or other options
## keys of the specified formats can be generated in PEM format. Instructions
## for custom keys can be found elsewhere.
##
## the currently supported set of supported_algorithms are
## ["RSASHA256", "RSASHA512", "ECDSAP256SHA256", "ECDSAP384SHA384", "ED25519"]
##
## keys are listed in pairs of key_name and algorithm, the search path is the
## same directory has the zone $file (this section would be relative to the
## example.com zone):
# [[zones.keys]]
## relative to the zone $file
# key = "my_rsa_2048.pem"
## specify the algorithm
# algorithm = "RSASHA256"
## this key should be used to sign the zone
# is_zone_signing_key = true
## this key is authorized for dynamic update access to the zone via SIG0
# is_zone_update_auth = true
#
# [[zones.keys]]
# key = "/path/to/my_ed25519.pem
# algorithm = "ED25519"
## for keys that are not zone signing, the pem need only include the pubic_key
# is_zone_signing_key = false
# is_zone_update_auth = true

View File

@ -176,7 +176,7 @@ fn with_nonet<F>(test: F) where F: Fn(SecureClientHandle<MemoizeClientHandle<Bas
let public_key = signers.first().expect("expected a key in the authority").get_key();
let mut trust_anchor = TrustAnchor::new();
trust_anchor.insert_trust_anchor(public_key.to_vec().expect("to_vec failed"));
trust_anchor.insert_trust_anchor(public_key.to_public_bytes().expect("to_vec failed"));
trust_anchor
};

View File

@ -45,7 +45,7 @@ venera A 10.1.0.52
if records.is_err() { panic!("failed to parse: {:?}", records.err()) }
let (origin, records) = records.unwrap();
let authority = Authority::new(origin, records, ZoneType::Master, false);
let authority = Authority::new(origin, records, ZoneType::Master, false, false);
// not validating everything, just one of each...