Openssl 09 (#80)

* refactor to allow multiple key implementations

* add byte format test for trust_keys

* upgrade to OpenSSL 0.9

* bump versions for release

* fix build for optional components

* add publish script
This commit is contained in:
Benjamin Fry 2016-12-31 13:24:17 -08:00 committed by GitHub
parent 0f696950d9
commit bd618862f6
27 changed files with 893 additions and 649 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.3
### Changed
- updated to rust-openssl 0.9.x series
- restructured dnssec code to better support alternate key formats
## 0.9.2
### Changed
- mio_client is now an optional feature in favor of the futures-rs ClientFuture

61
Cargo.lock generated
View File

@ -1,6 +1,6 @@
[root]
name = "trust-dns-server"
version = "0.9.0"
version = "0.9.3"
dependencies = [
"backtrace 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)",
@ -10,14 +10,14 @@ 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.8.3 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl 0.9.4 (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)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-core 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)",
"trust-dns 0.9.2",
"trust-dns 0.9.3",
]
[[package]]
@ -47,7 +47,7 @@ name = "backtrace-sys"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gcc 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.41 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -123,7 +123,7 @@ dependencies = [
[[package]]
name = "gcc"
version = "0.3.40"
version = "0.3.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -159,14 +159,6 @@ name = "libc"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libressl-pnacl-sys"
version = "2.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"pnacl-build-helper 1.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "libsqlite3-sys"
version = "0.5.0"
@ -313,23 +305,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "openssl"
version = "0.8.3"
version = "0.9.4"
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.7.17 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-sys 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "openssl-sys"
version = "0.7.17"
version = "0.9.4"
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)",
"libressl-pnacl-sys 2.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -339,14 +330,6 @@ name = "pkg-config"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "pnacl-build-helper"
version = "1.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand"
version = "0.3.15"
@ -427,14 +410,6 @@ name = "strsim"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "tempdir"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "thread-id"
version = "2.0.0"
@ -484,7 +459,7 @@ dependencies = [
[[package]]
name = "trust-dns"
version = "0.9.2"
version = "0.9.3"
dependencies = [
"backtrace 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)",
@ -494,13 +469,19 @@ 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.8.3 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-core 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"untrusted 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "untrusted"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "user32-sys"
version = "0.2.0"
@ -553,13 +534,12 @@ dependencies = [
"checksum docopt 0.6.86 (registry+https://github.com/rust-lang/crates.io-index)" = "4a7ef30445607f6fc8720f0a0a2c7442284b629cf0d049286860fae23e71c4d9"
"checksum error-chain 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faa976b4fd2e4c2b2f3f486874b19e61944d3de3de8b61c9fcf835d583871bcc"
"checksum futures 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "177a82a61dd7e528022ce97f24e54b499dd2fee4d4646a0f283c5fb500dbfe20"
"checksum gcc 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)" = "872db9e59486ef2b14f8e8c10e9ef02de2bccef6363d7f34835dedb386b3d950"
"checksum gcc 0.3.41 (registry+https://github.com/rust-lang/crates.io-index)" = "3689e1982a563af74960ae3a4758aa632bb8fd984cfc3cc3b60ee6109477ab6e"
"checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6abe0ee2e758cd6bc8a2cd56726359007748fbf4128da998b65d0b70f881e19b"
"checksum lazycell 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce12306c4739d86ee97c23139f3a34ddf0387bbf181bc7929d287025a8c3ef6b"
"checksum libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "a51822fc847e7a8101514d1d44e354ba2ffa7d4c194dcab48870740e327cac70"
"checksum libressl-pnacl-sys 2.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "cbc058951ab6a3ef35ca16462d7642c4867e6403520811f28537a4e2f2db3e71"
"checksum libsqlite3-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "663508cb9c1e23363aea1a8b1f7d6340394ebc3bc3a6daebfb9cc99b8feaf2ec"
"checksum linked-hash-map 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "83f7ff3baae999fdf921cccf54b61842bb3b26868d50d02dff48052ebec8dd79"
"checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054"
@ -575,10 +555,9 @@ 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.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b11754cb6c81bb9e62faaf0eb6d94dde2aab0928c04db5078b74242880f35eb1"
"checksum openssl-sys 0.7.17 (registry+https://github.com/rust-lang/crates.io-index)" = "89c47ee94c352eea9ddaf8e364be7f978a3bb6d66d73176572484238dd5a5c3f"
"checksum openssl 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6574ee213eef2c839252c5d2ca11090516287085bec625d3bbaca654757eb655"
"checksum openssl-sys 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5e23374cdaca202b655937ff6d1ad6887edc391d9ff371f3f48350c3e9fad001"
"checksum pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8cee804ecc7eaf201a4a207241472cc870e825206f6c031e3ee2a72fa425f2fa"
"checksum pnacl-build-helper 1.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "61c9231d31aea845007443d62fcbb58bb6949ab9c18081ee1e09920e0cf1118b"
"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"
"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957"
@ -591,12 +570,12 @@ dependencies = [
"checksum slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d807fd58c4181bbabed77cb3b891ba9748241a552bcc5be698faaebefc54f46e"
"checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23"
"checksum strsim 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "67f84c44fbb2f91db7fef94554e6b2ac05909c9c0b0bc23bb98d3a1aebfe7f7c"
"checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6"
"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03"
"checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5"
"checksum time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "3c7ec6d62a20df54e07ab3b78b9a3932972f4b7981de295563686849eb3989af"
"checksum tokio-core 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "52416b3e937abac22a543a7f1c66bd37feb60137ff1ab42390fa02df85347e58"
"checksum toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "0590d72182e50e879c4da3b11c6488dae18fccb1ae0c7a3eda18e16795844796"
"checksum untrusted 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "193df64312e3515fd983ded55ad5bcaa7647a035804828ed757e832ce6029ef3"
"checksum user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ef4711d107b21b410a3a974b1204d9accc8b10dad75d8324b5d755de1617d47"
"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f"
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"

View File

@ -1,6 +1,6 @@
[package]
name = "trust-dns"
version = "0.9.2"
version = "0.9.3"
authors = ["Benjamin Fry <benjaminfry@me.com>"]
# A short blurb about the package. This is not rendered in any format when
@ -53,8 +53,10 @@ futures = "^0.1"
lazy_static = "^0.2.1"
log = "^0.3.5"
mio = { version = "^0.5.1", optional = true }
openssl = { version = "^0.8.3", optional = true }
openssl = { version = "^0.9", optional = true }
rand = "^0.3"
# ring = { version = "^0.6", optional = true, features = ["rsa_signing"] }
rustc-serialize = "^0.3.18"
time = "^0.1"
tokio-core = "^0.1"
untrusted = "^0.3"

View File

@ -29,7 +29,7 @@ use ::error::*;
use ::rr::{DNSClass, RecordType, Record, RData};
use ::rr::rdata::NULL;
use ::rr::domain;
use ::rr::dnssec::Signer;
use ::rr::dnssec::{KeyPair, Signer};
#[cfg(feature = "openssl")]
use ::rr::dnssec::TrustAnchor;
use ::op::{Message, MessageType, OpCode, Query, UpdateMessage};
@ -226,8 +226,8 @@ impl<C: ClientConnection> Client<C> {
if !rdata.is_zone_key() { continue }
if *rdata.get_algorithm() != sig.get_algorithm() { continue }
let pkey = rdata.get_algorithm().public_key_from_vec(rdata.get_public_key());
if pkey.is_err() { debug!("could not translate public_key_from_vec: {}", pkey.unwrap_err()); continue }
let pkey = KeyPair::from_vec(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());

View File

@ -16,9 +16,9 @@ use ::client::ClientHandle;
use ::error::*;
use ::op::{Message, OpCode, Query};
use ::rr::{domain, DNSClass, RData, Record, RecordType};
use ::rr::dnssec::{KeyPair, TrustAnchor};
#[cfg(feature = "openssl")]
use ::rr::dnssec::Signer;
use ::rr::dnssec::TrustAnchor;
use ::rr::rdata::{dnskey, DNSKEY, DS, SIG};
use ::serialize::binary::{BinEncoder, BinSerializable};
@ -657,7 +657,7 @@ 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 = dnskey.get_algorithm().public_key_from_vec(dnskey.get_public_key());
let pkey = KeyPair::from_vec(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();

View File

@ -15,89 +15,85 @@
*/
use std::str::FromStr;
#[cfg(feature = "openssl")]
use openssl::crypto::rsa::RSA;
#[cfg(feature = "openssl")]
use openssl::bn::BigNum;
#[cfg(feature = "openssl")]
use ::rr::dnssec::DigestType;
use ::serialize::binary::*;
use ::error::*;
// RFC 6944 DNSSEC DNSKEY Algorithm Status April 2013
//
// 2.2. Algorithm Implementation Status Assignment Rationale
//
// RSASHA1 has an implementation status of Must Implement, consistent
// with [RFC4034]. RSAMD5 has an implementation status of Must Not
// Implement because of known weaknesses in MD5.
//
// The status of RSASHA1-NSEC3-SHA1 is set to Recommended to Implement
// as many deployments use NSEC3. The status of RSA/SHA-256 and RSA/
// SHA-512 are also set to Recommended to Implement as major deployments
// (such as the root zone) use these algorithms [ROOTDPS]. It is
// believed that RSA/SHA-256 or RSA/SHA-512 algorithms will replace
// older algorithms (e.g., RSA/SHA-1) that have a perceived weakness.
//
// Likewise, ECDSA with the two identified curves (ECDSAP256SHA256 and
// ECDSAP384SHA384) is an algorithm that may see widespread use due to
// the perceived similar level of security offered with smaller key size
// compared to the key sizes of algorithms such as RSA. Therefore,
// ECDSAP256SHA256 and ECDSAP384SHA384 are Recommended to Implement.
//
// All other algorithms used in DNSSEC specified without an
// implementation status are currently set to Optional.
//
// 2.3. DNSSEC Implementation Status Table
//
// The DNSSEC algorithm implementation status table is listed below.
// Only the algorithms already specified for use with DNSSEC at the time
// of writing are listed.
//
// +------------+------------+-------------------+-------------------+
// | Must | Must Not | Recommended | Optional |
// | Implement | Implement | to Implement | |
// +------------+------------+-------------------+-------------------+
// | | | | |
// | RSASHA1 | RSAMD5 | RSASHA256 | Any |
// | | | RSASHA1-NSEC3 | registered |
// | | | -SHA1 | algorithm |
// | | | RSASHA512 | not listed in |
// | | | ECDSAP256SHA256 | this table |
// | | | ECDSAP384SHA384 | |
// +------------+------------+-------------------+-------------------+
//
// This table does not list the Reserved values in the IANA registry
// table or the values for INDIRECT (252), PRIVATE (253), and PRIVATEOID
// (254). These values may relate to more than one algorithm and are
// therefore up to the implementer's discretion. As noted, any
// algorithm not listed in the table is Optional. As of this writing,
// the Optional algorithms are DSASHA1, DH, DSA-NSEC3-SHA1, and GOST-
// ECC, but in general, anything not explicitly listed is Optional.
//
// 2.4. Specifying New Algorithms and Updating the Status of Existing
// Entries
//
// [RFC6014] establishes a parallel procedure for adding a registry
// entry for a new algorithm other than a standards track document.
// Because any algorithm not listed in the foregoing table is Optional,
// algorithms entered into the registry using the [RFC6014] procedure
// are automatically Optional.
//
// It has turned out to be useful for implementations to refer to a
// single document that specifies the implementation status of every
// algorithm. Accordingly, when a new algorithm is to be registered
// with a status other than Optional, this document shall be made
// obsolete by a new document that adds the new algorithm to the table
// in Section 2.3. Similarly, if the status of any algorithm in the
// table in Section 2.3 changes, a new document shall make this document
// obsolete; that document shall include a replacement of the table in
// Section 2.3. This way, the goal of having one authoritative document
// to specify all the status values is achieved.
//
// This document cannot be updated, only made obsolete and replaced by a
// successor document.
/// [RFC 6944](https://tools.ietf.org/html/rfc6944), DNSSEC DNSKEY Algorithm Status, April 2013
///
/// ```text
///
/// 2.2. Algorithm Implementation Status Assignment Rationale
///
/// RSASHA1 has an implementation status of Must Implement, consistent
/// with [RFC4034]. RSAMD5 has an implementation status of Must Not
/// Implement because of known weaknesses in MD5.
///
/// The status of RSASHA1-NSEC3-SHA1 is set to Recommended to Implement
/// as many deployments use NSEC3. The status of RSA/SHA-256 and RSA/
/// SHA-512 are also set to Recommended to Implement as major deployments
/// (such as the root zone) use these algorithms [ROOTDPS]. It is
/// believed that RSA/SHA-256 or RSA/SHA-512 algorithms will replace
/// older algorithms (e.g., RSA/SHA-1) that have a perceived weakness.
///
/// Likewise, ECDSA with the two identified curves (ECDSAP256SHA256 and
/// ECDSAP384SHA384) is an algorithm that may see widespread use due to
/// the perceived similar level of security offered with smaller key size
/// compared to the key sizes of algorithms such as RSA. Therefore,
/// ECDSAP256SHA256 and ECDSAP384SHA384 are Recommended to Implement.
///
/// All other algorithms used in DNSSEC specified without an
/// implementation status are currently set to Optional.
///
/// 2.3. DNSSEC Implementation Status Table
///
/// The DNSSEC algorithm implementation status table is listed below.
/// Only the algorithms already specified for use with DNSSEC at the time
/// of writing are listed.
///
/// +------------+------------+-------------------+-------------------+
/// | Must | Must Not | Recommended | Optional |
/// | Implement | Implement | to Implement | |
/// +------------+------------+-------------------+-------------------+
/// | | | | |
/// | RSASHA1 | RSAMD5 | RSASHA256 | Any |
/// | | | RSASHA1-NSEC3 | registered |
/// | | | -SHA1 | algorithm |
/// | | | RSASHA512 | not listed in |
/// | | | ECDSAP256SHA256 | this table |
/// | | | ECDSAP384SHA384 | |
/// +------------+------------+-------------------+-------------------+
///
/// This table does not list the Reserved values in the IANA registry
/// table or the values for INDIRECT (252), PRIVATE (253), and PRIVATEOID
/// (254). These values may relate to more than one algorithm and are
/// therefore up to the implementer's discretion. As noted, any
/// algorithm not listed in the table is Optional. As of this writing,
/// the Optional algorithms are DSASHA1, DH, DSA-NSEC3-SHA1, and GOST-
/// ECC, but in general, anything not explicitly listed is Optional.
///
/// 2.4. Specifying New Algorithms and Updating the Status of Existing
/// Entries
///
/// [RFC6014] establishes a parallel procedure for adding a registry
/// entry for a new algorithm other than a standards track document.
/// Because any algorithm not listed in the foregoing table is Optional,
/// algorithms entered into the registry using the [RFC6014] procedure
/// are automatically Optional.
///
/// It has turned out to be useful for implementations to refer to a
/// single document that specifies the implementation status of every
/// algorithm. Accordingly, when a new algorithm is to be registered
/// with a status other than Optional, this document shall be made
/// obsolete by a new document that adds the new algorithm to the table
/// in Section 2.3. Similarly, if the status of any algorithm in the
/// table in Section 2.3 changes, a new document shall make this document
/// obsolete; that document shall include a replacement of the table in
/// Section 2.3. This way, the goal of having one authoritative document
/// to specify all the status values is achieved.
///
/// This document cannot be updated, only made obsolete and replaced by a
/// successor document.
/// ```
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
pub enum Algorithm {
/// DO NOT USE, SHA1 is a compromised hashing function, it is here for backward compatability
@ -106,33 +102,13 @@ pub enum Algorithm {
/// DO NOT USE, SHA1 is a compromised hashing function, it is here for backward compatability
RSASHA1NSEC3SHA1,
RSASHA512,
// ECDSAP256SHA256, // not yet supported
// ECDSAP384SHA384,
/// [rfc6605](https://tools.ietf.org/html/rfc6605)
ECDSAP256SHA256,
/// [rfc6605](https://tools.ietf.org/html/rfc6605)
ECDSAP384SHA384,
}
impl Algorithm {
#[cfg(feature = "openssl")]
pub fn sign(&self, private_key: &RSA, data: &[u8]) -> DnsSecResult<Vec<u8>> {
let digest_type = DigestType::from(*self);
// calculate the hash...
digest_type.hash(data)
.and_then(|ref hash| private_key.sign(digest_type.to_hash(), hash)
.map_err(|e| e.into()))
}
#[cfg(feature = "openssl")]
pub fn verify(&self, public_key: &RSA, data: &[u8], signature: &[u8]) -> DnsSecResult<()> {
let digest_type = DigestType::from(*self);
// calculate the hash on the local data
digest_type.hash(data)
// verify the remotely sent signature
.and_then(|ref hash| public_key.verify(digest_type.to_hash(), hash, signature)
.map_err(|e| e.into()))
}
/// http://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml
pub fn from_u8(value: u8) -> DecodeResult<Self> {
match value {
@ -140,8 +116,8 @@ impl Algorithm {
7 => Ok(Algorithm::RSASHA1NSEC3SHA1),
8 => Ok(Algorithm::RSASHA256),
10 => Ok(Algorithm::RSASHA512),
// 13 => Algorithm::ECDSAP256SHA256,
// 14 => Algorithm::ECDSAP384SHA384,
13 => Ok(Algorithm::ECDSAP256SHA256),
14 => Ok(Algorithm::ECDSAP384SHA384),
_ => Err(DecodeErrorKind::UnknownAlgorithmTypeValue(value).into()),
}
}
@ -150,98 +126,11 @@ impl Algorithm {
pub fn hash_len(&self) -> usize {
match *self {
Algorithm::RSASHA1 | Algorithm::RSASHA1NSEC3SHA1 => 20, // 160 bits
Algorithm::RSASHA256 => 32, // 256 bits
Algorithm::RSASHA256 | Algorithm::ECDSAP256SHA256 => 32, // 256 bits
Algorithm::ECDSAP384SHA384 => 48,
Algorithm::RSASHA512 => 64, // 512 bites
}
}
#[cfg(feature = "openssl")]
pub fn public_key_from_vec(&self, public_key: &[u8]) -> DecodeResult<RSA> {
match *self {
Algorithm::RSASHA1 |
Algorithm::RSASHA1NSEC3SHA1 |
Algorithm::RSASHA256 |
Algorithm::RSASHA512 => {
// RFC 3110 RSA SIGs and KEYs in the DNS May 2001
//
// 2. RSA Public KEY Resource Records
//
// RSA public keys are stored in the DNS as KEY RRs using algorithm
// number 5 [RFC2535]. The structure of the algorithm specific portion
// of the RDATA part of such RRs is as shown below.
//
// Field Size
// ----- ----
// exponent length 1 or 3 octets (see text)
// exponent as specified by length field
// modulus remaining space
//
// For interoperability, the exponent and modulus are each limited to
// 4096 bits in length. The public key exponent is a variable length
// unsigned integer. Its length in octets is represented as one octet
// if it is in the range of 1 to 255 and by a zero octet followed by a
// two octet unsigned length if it is longer than 255 bytes. The public
// key modulus field is a multiprecision unsigned integer. The length
// of the modulus can be determined from the RDLENGTH and the preceding
// RDATA fields including the exponent. Leading zero octets are
// prohibited in the exponent and modulus.
//
// Note: KEY RRs for use with RSA/SHA1 DNS signatures MUST use this
// algorithm number (rather than the algorithm number specified in the
// obsoleted RFC 2537).
//
// Note: This changes the algorithm number for RSA KEY RRs to be the
// same as the new algorithm number for RSA/SHA1 SIGs.
if public_key.len() < 3 || public_key.len() > (4096 + 3) { return Err(DecodeErrorKind::Message("bad public key").into()) }
let mut num_exp_len_octs = 1;
let mut len: u16 = public_key[0] as u16;
if len == 0 {
num_exp_len_octs = 3;
len = ((public_key[1] as u16) << 8) | (public_key[2] as u16)
}
let len = len; // demut
let e = try!(BigNum::new_from_slice(&public_key[(num_exp_len_octs as usize)..(len as usize + num_exp_len_octs)]));
let n = try!(BigNum::new_from_slice(&public_key[(len as usize +num_exp_len_octs)..]));
RSA::from_public_components(n, e).map_err(|e| e.into())
}
}
}
#[cfg(not(feature = "openssl"))]
pub fn public_key_from_vec(&self, _: &[u8]) -> DecodeResult<()> {
Err(DecodeErrorKind::Message("openssl feature not enabled").into())
}
#[cfg(feature = "openssl")]
pub fn public_key_to_vec(&self, public_key: &RSA) -> Vec<u8> {
match *self {
Algorithm::RSASHA1 |
Algorithm::RSASHA1NSEC3SHA1 |
Algorithm::RSASHA256 |
Algorithm::RSASHA512 => {
let mut bytes: Vec<u8> = Vec::new();
// this is to get us access to the exponent and the modulus
let e: Vec<u8> = public_key.e().expect("RSA should have been initialized").to_vec();
let n: Vec<u8> = public_key.n().expect("RSA should have been initialized").to_vec();
if e.len() > 255 {
bytes.push(0);
bytes.push((e.len() >> 8) as u8);
bytes.push(e.len() as u8);
} else {
bytes.push(e.len() as u8);
}
bytes.extend_from_slice(&e);
bytes.extend_from_slice(&n);
bytes
}
}
}
}
impl BinSerializable<Algorithm> for Algorithm {
@ -265,8 +154,8 @@ impl FromStr for Algorithm {
"RSASHA256" => Ok(Algorithm::RSASHA256),
"RSASHA1-NSEC3-SHA1" => Ok(Algorithm::RSASHA1NSEC3SHA1),
"RSASHA512" => Ok(Algorithm::RSASHA512),
// "ECDSAP256SHA256" => Algorithm::ECDSAP256SHA256,
// "ECDSAP384SHA384" => Algorithm::ECDSAP384SHA384,
"ECDSAP256SHA256" => Ok(Algorithm::ECDSAP256SHA256),
"ECDSAP384SHA384" => Ok(Algorithm::ECDSAP384SHA384),
_ => Err(DecodeErrorKind::Msg(format!("unrecognized string {}", s)).into()),
}
}
@ -279,8 +168,8 @@ impl From<Algorithm> for &'static str {
Algorithm::RSASHA256 => "RSASHA256",
Algorithm::RSASHA1NSEC3SHA1 => "RSASHA1-NSEC3-SHA1",
Algorithm::RSASHA512 => "RSASHA512",
// ECDSAP256SHA256 => "ECDSAP256SHA256",
// ECDSAP384SHA384 => "ECDSAP384SHA384",
Algorithm::ECDSAP256SHA256 => "ECDSAP256SHA256",
Algorithm::ECDSAP384SHA384 => "ECDSAP384SHA384",
}
}
}
@ -292,30 +181,20 @@ impl From<Algorithm> for u8 {
Algorithm::RSASHA1NSEC3SHA1 => 7,
Algorithm::RSASHA256 => 8,
Algorithm::RSASHA512 => 10,
// ECDSAP256SHA256 => 13,
// ECDSAP384SHA384 => 14,
Algorithm::ECDSAP256SHA256 => 13,
Algorithm::ECDSAP384SHA384 => 14,
}
}
}
#[cfg(test)]
#[cfg(feature = "openssl")]
mod test {
use super::Algorithm;
#[cfg(feature = "openssl")]
use openssl::crypto::rsa;
#[test]
fn test_hashing() {
let bytes = b"www.example.com";
let rsa = rsa::RSA::generate(2048).unwrap();
for algorithm in &[Algorithm::RSASHA1,
Algorithm::RSASHA256,
Algorithm::RSASHA1NSEC3SHA1,
Algorithm::RSASHA512] {
let sig = algorithm.sign(&rsa, bytes).unwrap();
assert!(algorithm.verify(&rsa, bytes, &sig).is_ok());
}
#[test]
fn test_into() {
for algorithm in &[Algorithm::RSASHA1,
Algorithm::RSASHA256,
Algorithm::RSASHA1NSEC3SHA1,
Algorithm::RSASHA512,
Algorithm::ECDSAP256SHA256,
Algorithm::ECDSAP384SHA384] {
assert_eq!(*algorithm, Algorithm::from_u8(Into::<u8>::into(*algorithm)).unwrap())
}
}

View File

@ -14,17 +14,21 @@
* limitations under the License.
*/
#[cfg(feature = "openssl")]
use openssl::crypto::hash;
use openssl::hash;
#[cfg(feature = "openssl")]
use openssl::hash::MessageDigest;
use ::rr::dnssec::Algorithm;
use ::error::*;
// 0 Reserved - [RFC3658]
// 1 SHA-1 MANDATORY [RFC3658]
// 2 SHA-256 MANDATORY [RFC4509]
// 3 GOST R 34.11-94 OPTIONAL [RFC5933]
// 4 SHA-384 OPTIONAL [RFC6605]
// 5-255 Unassigned -
/// ```text
/// 0 Reserved - [RFC3658]
/// 1 SHA-1 MANDATORY [RFC3658]
/// 2 SHA-256 MANDATORY [RFC4509]
/// 3 GOST R 34.11-94 OPTIONAL [RFC5933]
/// 4 SHA-384 OPTIONAL [RFC6605]
/// 5-255 Unassigned -
/// ```
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
pub enum DigestType {
SHA1, // [RFC3658]
@ -47,12 +51,12 @@ impl DigestType {
}
#[cfg(feature = "openssl")]
pub fn to_hash(&self) -> hash::Type {
pub fn to_hash(&self) -> MessageDigest {
match *self {
DigestType::SHA1 => hash::Type::SHA1,
DigestType::SHA256 => hash::Type::SHA256,
DigestType::SHA384 => hash::Type::SHA384,
DigestType::SHA512 => hash::Type::SHA512,
DigestType::SHA1 => MessageDigest::sha1(),
DigestType::SHA256 => MessageDigest::sha256(),
DigestType::SHA384 => MessageDigest::sha384(),
DigestType::SHA512 => MessageDigest::sha512(),
}
}
@ -73,8 +77,8 @@ impl From<Algorithm> for DigestType {
Algorithm::RSASHA1 | Algorithm::RSASHA1NSEC3SHA1 => DigestType::SHA1,
Algorithm::RSASHA256 => DigestType::SHA256,
Algorithm::RSASHA512 => DigestType::SHA512,
// Algorithm::ECDSAP256SHA256 => hash::Type::SHA256,
// Algorithm::ECDSAP384SHA384 => hash::Type::SHA384,
Algorithm::ECDSAP256SHA256 => DigestType::SHA256,
Algorithm::ECDSAP384SHA384 => DigestType::SHA384,
}
}
}

View File

@ -0,0 +1,227 @@
// Copyright 2015-2016 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
#[cfg(feature = "openssl")]
use openssl::rsa::Rsa as OpenSslRsa;
#[cfg(feature = "openssl")]
use openssl::sign::{Signer, Verifier};
#[cfg(feature = "openssl")]
use openssl::pkey::PKey;
#[cfg(feature = "openssl")]
use openssl::bn::BigNum;
use ::error::*;
use ::rr::{Name, RData, Record, RecordType};
use ::rr::dnssec::{Algorithm, DigestType};
use ::rr::rdata::DNSKEY;
/// A public and private key pair.
pub enum KeyPair {
#[cfg(feature = "openssl")]
RSA { pkey: PKey },
#[cfg(feature = "openssl")]
ECDSA {},
}
impl KeyPair {
#[cfg(feature = "openssl")]
pub fn from_rsa(rsa: OpenSslRsa) -> DnsSecResult<Self> {
PKey::from_rsa(rsa).map(|pkey| KeyPair::RSA{pkey: pkey}).map_err(|e| e.into())
}
pub fn from_vec(public_key: &[u8], algorithm: Algorithm) -> DnsSecResult<Self> {
match algorithm {
#[cfg(feature = "openssl")]
Algorithm::RSASHA1 |
Algorithm::RSASHA1NSEC3SHA1 |
Algorithm::RSASHA256 |
Algorithm::RSASHA512 => {
// RFC 3110 RSA SIGs and KEYs in the DNS May 2001
//
// 2. RSA Public KEY Resource Records
//
// RSA public keys are stored in the DNS as KEY RRs using algorithm
// number 5 [RFC2535]. The structure of the algorithm specific portion
// of the RDATA part of such RRs is as shown below.
//
// Field Size
// ----- ----
// exponent length 1 or 3 octets (see text)
// exponent as specified by length field
// modulus remaining space
//
// For interoperability, the exponent and modulus are each limited to
// 4096 bits in length. The public key exponent is a variable length
// unsigned integer. Its length in octets is represented as one octet
// if it is in the range of 1 to 255 and by a zero octet followed by a
// two octet unsigned length if it is longer than 255 bytes. The public
// key modulus field is a multiprecision unsigned integer. The length
// of the modulus can be determined from the RDLENGTH and the preceding
// RDATA fields including the exponent. Leading zero octets are
// prohibited in the exponent and modulus.
//
// Note: KEY RRs for use with RSA/SHA1 DNS signatures MUST use this
// algorithm number (rather than the algorithm number specified in the
// obsoleted RFC 2537).
//
// Note: This changes the algorithm number for RSA KEY RRs to be the
// same as the new algorithm number for RSA/SHA1 SIGs.
if public_key.len() < 3 || public_key.len() > (4096 + 3) { return Err(DnsSecErrorKind::Message("bad public key").into()) }
let mut num_exp_len_octs = 1;
let mut len: u16 = public_key[0] as u16;
if len == 0 {
num_exp_len_octs = 3;
len = ((public_key[1] as u16) << 8) | (public_key[2] as u16)
}
let len = len; // demut
let e = try!(BigNum::from_slice(&public_key[(num_exp_len_octs as usize)..(len as usize + num_exp_len_octs)]));
let n = try!(BigNum::from_slice(&public_key[(len as usize +num_exp_len_octs)..]));
OpenSslRsa::from_public_components(n, e)
.map_err(|e| e.into())
.and_then(|rsa| Self::from_rsa(rsa))
},
#[cfg(feature = "openssl")]
Algorithm::ECDSAP256SHA256 | Algorithm::ECDSAP384SHA384 => {
Err(DnsSecErrorKind::Message("unimplemented").into())
}
#[cfg(not(feature = "openssl"))]
_ => Err(DnsSecErrorKind::Message("openssl feature not enabled").into()),
}
}
pub fn to_vec(&self) -> Vec<u8> {
match *self {
#[cfg(feature = "openssl")]
KeyPair::RSA{ref pkey} => {
let mut bytes: Vec<u8> = Vec::new();
let rsa: OpenSslRsa = pkey.rsa().expect("pkey should have been initialized with RSA");
// this is to get us access to the exponent and the modulus
let e: Vec<u8> = rsa.e().expect("RSA should have been initialized").to_vec();
let n: Vec<u8> = rsa.n().expect("RSA should have been initialized").to_vec();
if e.len() > 255 {
bytes.push(0);
bytes.push((e.len() >> 8) as u8);
bytes.push(e.len() as u8);
} else {
bytes.push(e.len() as u8);
}
bytes.extend_from_slice(&e);
bytes.extend_from_slice(&n);
bytes
},
#[cfg(feature = "openssl")]
KeyPair::ECDSA{} => {
Vec::new() // TODO: unimplemented
},
// _ => vec![],
}
}
/// Creates a Record that represents the public key for this Signer
///
/// # Arguments
///
/// * `name` - name of the entity associated with this DNSKEY
/// * `ttl` - the time to live for this DNSKEY
///
/// # Return
///
/// the DNSKEY record
pub fn to_dnskey(&self, name: Name, ttl: u32, algorithm: Algorithm) -> Record {
let mut record = Record::with(name.clone(), RecordType::DNSKEY, ttl);
#[cfg(feature = "openssl")]
{
let rsa_bytes = self.to_vec();
record.rdata(RData::DNSKEY(DNSKEY::new(true, true, false, algorithm, rsa_bytes)));
}
record
}
/// Signs a hash.
///
/// This will panic if the `key` is not a private key and can be used for signing.
///
/// # Arguments
///
/// * `hash` - the hashed resource record set, see `hash_rrset`.
///
/// # Return value
///
/// The signature, ready to be stored in an `RData::RRSIG`.
pub fn sign(&self, algorithm: Algorithm, hash: &[u8]) -> DnsSecResult<Vec<u8>> {
match *self {
#[cfg(feature = "openssl")]
KeyPair::RSA{ref pkey} => {
let mut signer = Signer::new(DigestType::from(algorithm).to_hash(), &pkey).unwrap();
try!(signer.update(&hash));
signer.finish().map_err(|e| e.into())
},
#[cfg(feature = "openssl")]
KeyPair::ECDSA{} => {
Err(DnsSecErrorKind::Message("unimplemented").into())
}
}
}
/// Verifies the hash matches the signature with the current `key`.
///
/// # Arguments
///
/// * `hash` - the hash to be validated, see `hash_rrset`
/// * `signature` - the signature to use to verify the hash, extracted from an `RData::RRSIG`
/// for example.
///
/// # Return value
///
/// True if and only if the signature is valid for the hash. This will always return
/// false if the `key`.
pub fn verify(&self, algorithm: Algorithm, hash: &[u8], signature: &[u8]) -> DnsSecResult<()> {
match *self {
#[cfg(feature = "openssl")]
KeyPair::RSA{ref pkey} => {
let mut verifier = Verifier::new(DigestType::from(algorithm).to_hash(), &pkey).unwrap();
try!(verifier.update(hash));
verifier.finish(signature)
.map_err(|e| e.into())
.and_then(|b| if b { Ok(()) }
else { Err(DnsSecErrorKind::Message("could not verify").into()) })
},
#[cfg(feature = "openssl")]
KeyPair::ECDSA{} => {
// FIXME
Err(DnsSecErrorKind::Message("not implemented").into())
}
}
}
}
#[cfg(feature = "openssl")]
#[test]
fn test_hashing() {
use ::rr::dnssec::Algorithm;
use openssl::rsa;
let bytes = b"www.example.com";
let rsa = rsa::Rsa::generate(2048).unwrap();
let key = KeyPair::from_rsa(rsa).unwrap();
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);
}
}

View File

@ -18,6 +18,7 @@
mod algorithm;
mod digest_type;
mod keypair;
mod nsec3;
mod signer;
mod supported_algorithm;
@ -25,6 +26,7 @@ mod trust_anchor;
pub use self::algorithm::Algorithm;
pub use self::digest_type::DigestType;
pub use self::keypair::KeyPair;
pub use self::nsec3::Nsec3HashAlgorithm;
pub use self::signer::Signer;
pub use self::supported_algorithm::SupportedAlgorithms;

View File

@ -16,7 +16,7 @@
#[cfg(feature = "openssl")]
use std::io::Write;
#[cfg(feature = "openssl")]
use openssl::crypto::hash;
use openssl::hash;
use ::error::*;
#[cfg(feature = "openssl")]

View File

@ -17,8 +17,6 @@
//! signer is a structure for performing many of the signing processes of the DNSSec specification
#[cfg(feature = "openssl")]
use chrono::Duration;
#[cfg(feature = "openssl")]
use openssl::crypto::rsa::RSA;
#[cfg(feature = "openssl")]
use ::op::Message;
@ -26,16 +24,215 @@ use ::op::Message;
use ::rr::{DNSClass, Name, Record, RecordType, RData};
#[cfg(feature = "openssl")]
use ::rr::dnssec::{Algorithm, DigestType, DnsSecErrorKind, DnsSecResult};
use ::rr::dnssec::KeyPair;
#[cfg(feature = "openssl")]
use ::rr::rdata::{DNSKEY, sig, SIG};
use ::rr::rdata::{sig, SIG};
#[cfg(feature = "openssl")]
use ::serialize::binary::{BinEncoder, BinSerializable, EncodeMode};
/// Use for performing signing and validation of DNSSec based components.
///
/// [RFC 4035](https://tools.ietf.org/html/rfc4035), DNSSEC Protocol Modifications, March 2005
///
/// ```text
/// 5.3. Authenticating an RRset with an RRSIG RR
///
/// A validator can use an RRSIG RR and its corresponding DNSKEY RR to
/// attempt to authenticate RRsets. The validator first checks the RRSIG
/// RR to verify that it covers the RRset, has a valid time interval, and
/// identifies a valid DNSKEY RR. The validator then constructs the
/// canonical form of the signed data by appending the RRSIG RDATA
/// (excluding the Signature Field) with the canonical form of the
/// covered RRset. Finally, the validator uses the public key and
/// signature to authenticate the signed data. Sections 5.3.1, 5.3.2,
/// and 5.3.3 describe each step in detail.
///
/// 5.3.1. Checking the RRSIG RR Validity
///
/// A security-aware resolver can use an RRSIG RR to authenticate an
/// RRset if all of the following conditions hold:
///
/// o The RRSIG RR and the RRset MUST have the same owner name and the
/// same class.
///
/// o The RRSIG RR's Signer's Name field MUST be the name of the zone
/// that contains the RRset.
///
/// o The RRSIG RR's Type Covered field MUST equal the RRset's type.
///
/// o The number of labels in the RRset owner name MUST be greater than
/// or equal to the value in the RRSIG RR's Labels field.
///
/// o The validator's notion of the current time MUST be less than or
/// equal to the time listed in the RRSIG RR's Expiration field.
///
/// o The validator's notion of the current time MUST be greater than or
/// equal to the time listed in the RRSIG RR's Inception field.
///
/// o The RRSIG RR's Signer's Name, Algorithm, and Key Tag fields MUST
/// match the owner name, algorithm, and key tag for some DNSKEY RR in
/// the zone's apex DNSKEY RRset.
///
/// o The matching DNSKEY RR MUST be present in the zone's apex DNSKEY
/// RRset, and MUST have the Zone Flag bit (DNSKEY RDATA Flag bit 7)
/// set.
///
/// It is possible for more than one DNSKEY RR to match the conditions
/// above. In this case, the validator cannot predetermine which DNSKEY
/// RR to use to authenticate the signature, and it MUST try each
/// matching DNSKEY RR until either the signature is validated or the
/// validator has run out of matching public keys to try.
///
/// Note that this authentication process is only meaningful if the
/// validator authenticates the DNSKEY RR before using it to validate
/// signatures. The matching DNSKEY RR is considered to be authentic if:
///
/// o the apex DNSKEY RRset containing the DNSKEY RR is considered
/// authentic; or
///
/// o the RRset covered by the RRSIG RR is the apex DNSKEY RRset itself,
/// and the DNSKEY RR either matches an authenticated DS RR from the
/// parent zone or matches a trust anchor.
///
/// 5.3.2. Reconstructing the Signed Data
///
/// Once the RRSIG RR has met the validity requirements described in
/// Section 5.3.1, the validator has to reconstruct the original signed
/// data. The original signed data includes RRSIG RDATA (excluding the
/// Signature field) and the canonical form of the RRset. Aside from
/// being ordered, the canonical form of the RRset might also differ from
/// the received RRset due to DNS name compression, decremented TTLs, or
/// wildcard expansion. The validator should use the following to
/// reconstruct the original signed data:
///
/// signed_data = RRSIG_RDATA | RR(1) | RR(2)... where
///
/// "|" denotes concatenation
///
/// RRSIG_RDATA is the wire format of the RRSIG RDATA fields
/// with the Signature field excluded and the Signer's Name
/// in canonical form.
///
/// RR(i) = name | type | class | OrigTTL | RDATA length | RDATA
///
/// name is calculated according to the function below
///
/// class is the RRset's class
///
/// type is the RRset type and all RRs in the class
///
/// OrigTTL is the value from the RRSIG Original TTL field
///
/// All names in the RDATA field are in canonical form
///
/// The set of all RR(i) is sorted into canonical order.
///
/// To calculate the name:
/// let rrsig_labels = the value of the RRSIG Labels field
///
/// let fqdn = RRset's fully qualified domain name in
/// canonical form
///
/// let fqdn_labels = Label count of the fqdn above.
///
/// if rrsig_labels = fqdn_labels,
/// name = fqdn
///
/// if rrsig_labels < fqdn_labels,
/// name = "*." | the rightmost rrsig_label labels of the
/// fqdn
///
/// if rrsig_labels > fqdn_labels
/// the RRSIG RR did not pass the necessary validation
/// checks and MUST NOT be used to authenticate this
/// RRset.
///
/// The canonical forms for names and RRsets are defined in [RFC4034].
///
/// NSEC RRsets at a delegation boundary require special processing.
/// There are two distinct NSEC RRsets associated with a signed delegated
/// name. One NSEC RRset resides in the parent zone, and specifies which
/// RRsets are present at the parent zone. The second NSEC RRset resides
/// at the child zone and identifies which RRsets are present at the apex
/// in the child zone. The parent NSEC RRset and child NSEC RRset can
/// always be distinguished as only a child NSEC RR will indicate that an
/// SOA RRset exists at the name. When reconstructing the original NSEC
/// RRset for the delegation from the parent zone, the NSEC RRs MUST NOT
/// be combined with NSEC RRs from the child zone. When reconstructing
/// the original NSEC RRset for the apex of the child zone, the NSEC RRs
/// MUST NOT be combined with NSEC RRs from the parent zone.
///
/// Note that each of the two NSEC RRsets at a delegation point has a
/// corresponding RRSIG RR with an owner name matching the delegated
/// name, and each of these RRSIG RRs is authoritative data associated
/// with the same zone that contains the corresponding NSEC RRset. If
/// necessary, a resolver can tell these RRSIG RRs apart by checking the
/// Signer's Name field.
///
/// 5.3.3. Checking the Signature
///
/// Once the resolver has validated the RRSIG RR as described in Section
/// 5.3.1 and reconstructed the original signed data as described in
/// Section 5.3.2, the validator can attempt to use the cryptographic
/// signature to authenticate the signed data, and thus (finally!)
/// authenticate the RRset.
///
/// The Algorithm field in the RRSIG RR identifies the cryptographic
/// algorithm used to generate the signature. The signature itself is
/// contained in the Signature field of the RRSIG RDATA, and the public
/// key used to verify the signature is contained in the Public Key field
/// of the matching DNSKEY RR(s) (found in Section 5.3.1). [RFC4034]
/// provides a list of algorithm types and provides pointers to the
/// documents that define each algorithm's use.
///
/// Note that it is possible for more than one DNSKEY RR to match the
/// conditions in Section 5.3.1. In this case, the validator can only
/// determine which DNSKEY RR is correct by trying each matching public
/// key until the validator either succeeds in validating the signature
/// or runs out of keys to try.
///
/// If the Labels field of the RRSIG RR is not equal to the number of
/// labels in the RRset's fully qualified owner name, then the RRset is
/// either invalid or the result of wildcard expansion. The resolver
/// MUST verify that wildcard expansion was applied properly before
/// considering the RRset to be authentic. Section 5.3.4 describes how
/// to determine whether a wildcard was applied properly.
///
/// If other RRSIG RRs also cover this RRset, the local resolver security
/// policy determines whether the resolver also has to test these RRSIG
/// RRs and how to resolve conflicts if these RRSIG RRs lead to differing
/// results.
///
/// If the resolver accepts the RRset as authentic, the validator MUST
/// set the TTL of the RRSIG RR and each RR in the authenticated RRset to
/// a value no greater than the minimum of:
///
/// o the RRset's TTL as received in the response;
///
/// o the RRSIG RR's TTL as received in the response;
///
/// o the value in the RRSIG RR's Original TTL field; and
///
/// o the difference of the RRSIG RR's Signature Expiration time and the
/// current time.
///
/// 5.3.4. Authenticating a Wildcard Expanded RRset Positive Response
///
/// If the number of labels in an RRset's owner name is greater than the
/// Labels field of the covering RRSIG RR, then the RRset and its
/// covering RRSIG RR were created as a result of wildcard expansion.
/// Once the validator has verified the signature, as described in
/// Section 5.3, it must take additional steps to verify the non-
/// existence of an exact match or closer wildcard match for the query.
/// Section 5.4 discusses these steps.
///
/// 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")]
pub struct Signer {
key: KeyPair,
algorithm: Algorithm,
rsa: RSA,
signer_name: Name,
sig_duration: Duration,
}
@ -46,39 +243,23 @@ pub struct Signer;
#[cfg(feature = "openssl")]
impl Signer {
/// Version of Signer for verifying RRSIGs and SIG0 records.
pub fn new_verifier(algorithm: Algorithm, rsa: RSA, signer_name: Name) -> Self {
Signer{ algorithm: algorithm, rsa: rsa, signer_name: signer_name, sig_duration: Duration::zero() }
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() }
}
/// Version of Signer for signing RRSIGs and SIG0 records.
pub fn new(algorithm: Algorithm, rsa: RSA, signer_name: Name, sig_duration: Duration) -> Self {
Signer{ algorithm: algorithm, rsa: rsa, signer_name: signer_name, sig_duration: sig_duration }
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 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 get_rsa(&self) -> &RSA { &self.rsa }
pub fn get_public_key(&self) -> Vec<u8> {
self.algorithm.public_key_to_vec(&self.rsa)
}
/// Creates a Record that represents the public key for this Signer
pub fn to_dnskey(&self, name: Name, ttl: u32) -> Record {
let mut record = Record::with(name.clone(), RecordType::DNSKEY, ttl);
record.rdata(RData::DNSKEY(
DNSKEY::new(true, true, false,
self.algorithm,
self.get_public_key())
));
record
}
/// The key tag is calculated as a hash to more quickly lookup a DNSKEY.
///
/// [RFC 1035, DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION, November 1987](https://tools.ietf.org/html/rfc1035)
/// [RFC 1035](https://tools.ietf.org/html/rfc1035), DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION, November 1987
///
/// ```text
/// RFC 2535 DNS Security Extensions March 1999
@ -132,7 +313,7 @@ impl Signer {
pub fn calculate_key_tag(&self) -> u16 {
let mut ac: usize = 0;
for (i,k) in self.get_public_key().iter().enumerate() {
for (i,k) in self.key.to_vec().iter().enumerate() {
ac += if i & 0x0001 == 0x0001 { *k as usize } else { (*k as usize) << 8 };
}
@ -160,6 +341,8 @@ impl Signer {
///
/// * `message` - the message to sign
///
/// [rfc2535](https://tools.ietf.org/html/rfc2535#section-4.1.8.1), Domain Name System Security Extensions, 1999
///
/// ```text
/// 4.1.8.1 Calculating Transaction and Request SIGs
///
@ -216,8 +399,8 @@ impl Signer {
///
/// # Arguments
///
/// `message` - the message to verify
/// `signature` - the signature to use for validation
/// * `message` - the message to verify
/// * `signature` - the signature to use for validation
///
/// # Return value
///
@ -227,203 +410,24 @@ impl Signer {
.and_then(|hash| self.verify(&hash, signature))
}
// RFC 4035 DNSSEC Protocol Modifications March 2005
//
// 5.3. Authenticating an RRset with an RRSIG RR
//
// A validator can use an RRSIG RR and its corresponding DNSKEY RR to
// attempt to authenticate RRsets. The validator first checks the RRSIG
// RR to verify that it covers the RRset, has a valid time interval, and
// identifies a valid DNSKEY RR. The validator then constructs the
// canonical form of the signed data by appending the RRSIG RDATA
// (excluding the Signature Field) with the canonical form of the
// covered RRset. Finally, the validator uses the public key and
// signature to authenticate the signed data. Sections 5.3.1, 5.3.2,
// and 5.3.3 describe each step in detail.
//
// 5.3.1. Checking the RRSIG RR Validity
//
// A security-aware resolver can use an RRSIG RR to authenticate an
// RRset if all of the following conditions hold:
//
// o The RRSIG RR and the RRset MUST have the same owner name and the
// same class.
//
// o The RRSIG RR's Signer's Name field MUST be the name of the zone
// that contains the RRset.
//
// o The RRSIG RR's Type Covered field MUST equal the RRset's type.
//
// o The number of labels in the RRset owner name MUST be greater than
// or equal to the value in the RRSIG RR's Labels field.
//
// o The validator's notion of the current time MUST be less than or
// equal to the time listed in the RRSIG RR's Expiration field.
//
// o The validator's notion of the current time MUST be greater than or
// equal to the time listed in the RRSIG RR's Inception field.
//
// o The RRSIG RR's Signer's Name, Algorithm, and Key Tag fields MUST
// match the owner name, algorithm, and key tag for some DNSKEY RR in
// the zone's apex DNSKEY RRset.
//
// o The matching DNSKEY RR MUST be present in the zone's apex DNSKEY
// RRset, and MUST have the Zone Flag bit (DNSKEY RDATA Flag bit 7)
// set.
//
// It is possible for more than one DNSKEY RR to match the conditions
// above. In this case, the validator cannot predetermine which DNSKEY
// RR to use to authenticate the signature, and it MUST try each
// matching DNSKEY RR until either the signature is validated or the
// validator has run out of matching public keys to try.
//
// Note that this authentication process is only meaningful if the
// validator authenticates the DNSKEY RR before using it to validate
// signatures. The matching DNSKEY RR is considered to be authentic if:
//
// o the apex DNSKEY RRset containing the DNSKEY RR is considered
// authentic; or
//
// o the RRset covered by the RRSIG RR is the apex DNSKEY RRset itself,
// and the DNSKEY RR either matches an authenticated DS RR from the
// parent zone or matches a trust anchor.
//
// 5.3.2. Reconstructing the Signed Data
//
// Once the RRSIG RR has met the validity requirements described in
// Section 5.3.1, the validator has to reconstruct the original signed
// data. The original signed data includes RRSIG RDATA (excluding the
// Signature field) and the canonical form of the RRset. Aside from
// being ordered, the canonical form of the RRset might also differ from
// the received RRset due to DNS name compression, decremented TTLs, or
// wildcard expansion. The validator should use the following to
// reconstruct the original signed data:
//
// signed_data = RRSIG_RDATA | RR(1) | RR(2)... where
//
// "|" denotes concatenation
//
// RRSIG_RDATA is the wire format of the RRSIG RDATA fields
// with the Signature field excluded and the Signer's Name
// in canonical form.
//
// RR(i) = name | type | class | OrigTTL | RDATA length | RDATA
//
// name is calculated according to the function below
//
// class is the RRset's class
//
// type is the RRset type and all RRs in the class
//
// OrigTTL is the value from the RRSIG Original TTL field
//
// All names in the RDATA field are in canonical form
//
// The set of all RR(i) is sorted into canonical order.
//
// To calculate the name:
// let rrsig_labels = the value of the RRSIG Labels field
//
// let fqdn = RRset's fully qualified domain name in
// canonical form
//
// let fqdn_labels = Label count of the fqdn above.
//
// if rrsig_labels = fqdn_labels,
// name = fqdn
//
// if rrsig_labels < fqdn_labels,
// name = "*." | the rightmost rrsig_label labels of the
// fqdn
//
// if rrsig_labels > fqdn_labels
// the RRSIG RR did not pass the necessary validation
// checks and MUST NOT be used to authenticate this
// RRset.
//
// The canonical forms for names and RRsets are defined in [RFC4034].
//
// NSEC RRsets at a delegation boundary require special processing.
// There are two distinct NSEC RRsets associated with a signed delegated
// name. One NSEC RRset resides in the parent zone, and specifies which
// RRsets are present at the parent zone. The second NSEC RRset resides
// at the child zone and identifies which RRsets are present at the apex
// in the child zone. The parent NSEC RRset and child NSEC RRset can
// always be distinguished as only a child NSEC RR will indicate that an
// SOA RRset exists at the name. When reconstructing the original NSEC
// RRset for the delegation from the parent zone, the NSEC RRs MUST NOT
// be combined with NSEC RRs from the child zone. When reconstructing
// the original NSEC RRset for the apex of the child zone, the NSEC RRs
// MUST NOT be combined with NSEC RRs from the parent zone.
//
// Note that each of the two NSEC RRsets at a delegation point has a
// corresponding RRSIG RR with an owner name matching the delegated
// name, and each of these RRSIG RRs is authoritative data associated
// with the same zone that contains the corresponding NSEC RRset. If
// necessary, a resolver can tell these RRSIG RRs apart by checking the
// Signer's Name field.
//
// 5.3.3. Checking the Signature
//
// Once the resolver has validated the RRSIG RR as described in Section
// 5.3.1 and reconstructed the original signed data as described in
// Section 5.3.2, the validator can attempt to use the cryptographic
// signature to authenticate the signed data, and thus (finally!)
// authenticate the RRset.
//
// The Algorithm field in the RRSIG RR identifies the cryptographic
// algorithm used to generate the signature. The signature itself is
// contained in the Signature field of the RRSIG RDATA, and the public
// key used to verify the signature is contained in the Public Key field
// of the matching DNSKEY RR(s) (found in Section 5.3.1). [RFC4034]
// provides a list of algorithm types and provides pointers to the
// documents that define each algorithm's use.
//
// Note that it is possible for more than one DNSKEY RR to match the
// conditions in Section 5.3.1. In this case, the validator can only
// determine which DNSKEY RR is correct by trying each matching public
// key until the validator either succeeds in validating the signature
// or runs out of keys to try.
//
// If the Labels field of the RRSIG RR is not equal to the number of
// labels in the RRset's fully qualified owner name, then the RRset is
// either invalid or the result of wildcard expansion. The resolver
// MUST verify that wildcard expansion was applied properly before
// considering the RRset to be authentic. Section 5.3.4 describes how
// to determine whether a wildcard was applied properly.
//
// If other RRSIG RRs also cover this RRset, the local resolver security
// policy determines whether the resolver also has to test these RRSIG
// RRs and how to resolve conflicts if these RRSIG RRs lead to differing
// results.
//
// If the resolver accepts the RRset as authentic, the validator MUST
// set the TTL of the RRSIG RR and each RR in the authenticated RRset to
// a value no greater than the minimum of:
//
// o the RRset's TTL as received in the response;
//
// o the RRSIG RR's TTL as received in the response;
//
// o the value in the RRSIG RR's Original TTL field; and
//
// o the difference of the RRSIG RR's Signature Expiration time and the
// current time.
//
// 5.3.4. Authenticating a Wildcard Expanded RRset Positive Response
//
// If the number of labels in an RRset's owner name is greater than the
// Labels field of the covering RRSIG RR, then the RRset and its
// covering RRSIG RR were created as a result of wildcard expansion.
// Once the validator has verified the signature, as described in
// Section 5.3, it must take additional steps to verify the non-
// existence of an exact match or closer wildcard match for the query.
// Section 5.4 discusses these steps.
//
// Note that the response received by the resolver should include all
// NSEC RRs needed to authenticate the response (see Section 3.1.3).
//
/// name is the the name of the records in the rrset
/// Computes the hash of the given record set
///
/// # Arguments
///
/// * `name` - RRset record name
/// * `dns_class` - DNSClass, i.e. IN, of the records
/// * `num_labels` - number of labels in the name, needed to deal with `*.example.com`
/// * `type_covered` - RecordType of the RRSet being hashed
/// * `algorithm` - The Algorithm type used for the hashing
/// * `original_ttl` - Original TTL is the TTL as specified in the SOA zones RRSet associated record
/// * `sig_expiration` - the epoch seconds of when this hashed signature will expire
/// * `key_inception` - the epoch seconds of when this hashed signature will be valid
/// * `signer_name` - label of the etity responsible for signing this hash
/// * `records` - RRSet to hash
///
/// # Returns
///
/// the binary hash of the specified RRSet and associated information
pub fn hash_rrset(&self, name: &Name, dns_class: DNSClass, num_labels: u8,
type_covered: RecordType, algorithm: Algorithm, original_ttl: u32,
sig_expiration: u32, sig_inception: u32, key_tag: u16, signer_name: &Name,
@ -449,6 +453,7 @@ impl Signer {
return Err(DnsSecErrorKind::Msg(format!("could not determine name from {}", name)).into())
};
// TODO: rather than buffering here, use the Signer/Verifier? might mean fewer allocations...
let mut buf: Vec<u8> = Vec::new();
{
@ -497,9 +502,21 @@ impl Signer {
}
}
DigestType::from(self.algorithm).hash(&buf)
// TODO: This used to return the hash, now it's a hashable record type?
// DigestType::from(self.algorithm).hash(&buf)
Ok(buf)
}
/// hashes the RRSet with information provided from the RRSig record
///
/// # Arguments
///
/// * `rrsig` - SIG or RRSIG record, which was produced from the RRSet
/// * `records` - RRSet records to sign with the information in the `rrsig`
///
/// # Return
///
/// binary hash of the RRSet with the information from the RRSIG record
pub fn hash_rrset_with_rrsig(&self, rrsig: &Record, records: &[Record]) -> DnsSecResult<Vec<u8>> {
if let &RData::SIG(ref sig) = rrsig.get_rdata() {
self.hash_rrset_with_sig(rrsig.get_name(), rrsig.get_dns_class(), sig, records)
@ -508,6 +525,18 @@ impl Signer {
}
}
/// hashes the RRSet with information provided from the RRSig record
///
/// # Arguments
///
/// * `name` - labels of the record to sign
/// * `dns_class` - DNSClass of the RRSet, i.e. IN
/// * `sig` - SIG or RRSIG record, which was produced from the RRSet
/// * `records` - RRSet records to sign with the information in the `rrsig`
///
/// # Return
///
/// binary hash of the RRSet with the information from the RRSIG record
pub fn hash_rrset_with_sig(&self, name: &Name, dns_class: DNSClass, sig: &SIG, records: &[Record]) -> DnsSecResult<Vec<u8>> {
self.hash_rrset(name, dns_class,
sig.get_num_labels(), sig.get_type_covered(), sig.get_algorithm(),
@ -563,7 +592,7 @@ impl Signer {
///
/// The signature, ready to be stored in an `RData::RRSIG`.
pub fn sign(&self, hash: &[u8]) -> DnsSecResult<Vec<u8>> {
self.rsa.sign(DigestType::from(self.algorithm).to_hash(), &hash).map_err(|e| e.into())
self.key.sign(self.algorithm, &hash).map_err(|e| e.into())
}
/// Verifies the hash matches the signature with the current `key`.
@ -579,13 +608,14 @@ impl Signer {
/// True if and only if the signature is valid for the hash. This will always return
/// false if the `key`.
pub fn verify(&self, hash: &[u8], signature: &[u8]) -> DnsSecResult<()> {
self.rsa.verify(DigestType::from(self.algorithm).to_hash(), hash, signature).map_err(|e| e.into())
self.key.verify(self.algorithm, hash, signature).map_err(|e| e.into())
}
}
#[test]
#[cfg(feature = "openssl")]
fn test_sign_and_verify_message_sig0() {
use openssl::rsa::Rsa;
use ::rr::Name;
use ::op::{Message, Query, UpdateMessage};
@ -595,8 +625,9 @@ fn test_sign_and_verify_message_sig0() {
query.name(origin.clone());
question.add_query(query);
let rsa = RSA::generate(512).unwrap();
let signer = Signer::new(Algorithm::RSASHA256, rsa, Name::root(), Duration::max_value());
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 sig = signer.sign_message(&question).unwrap();
println!("sig: {:?}", sig);
@ -620,11 +651,13 @@ fn test_sign_and_verify_message_sig0() {
#[test]
#[cfg(feature = "openssl")]
fn test_hash_rrset() {
use openssl::rsa::Rsa;
use ::rr::{Name, RecordType};
use ::rr::rdata::SIG;
let rsa = RSA::generate(512).unwrap();
let signer = Signer::new(Algorithm::RSASHA256, rsa, Name::root(), Duration::max_value());
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 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,
@ -649,12 +682,14 @@ fn test_hash_rrset() {
#[test]
#[cfg(feature = "openssl")]
fn test_sign_and_verify_rrset() {
use openssl::rsa::Rsa;
use ::rr::RecordType;
use ::rr::Name;
use ::rr::rdata::SIG;
let rsa = RSA::generate(512).unwrap();
let signer = Signer::new(Algorithm::RSASHA256, rsa, Name::root(), Duration::max_value());
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 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,
@ -671,9 +706,12 @@ fn test_sign_and_verify_rrset() {
#[test]
#[cfg(feature = "openssl")]
fn test_calculate_key_tag() {
let rsa = RSA::generate(512).unwrap();
use openssl::rsa::Rsa;
let rsa = Rsa::generate(512).unwrap();
println!("pkey: {:?}", rsa.public_key_to_pem().unwrap());
let signer = Signer::new(Algorithm::RSASHA256, rsa, Name::root(), Duration::max_value());
let key = KeyPair::from_rsa(rsa).unwrap();
let signer = Signer::new(Algorithm::RSASHA256, key, Name::root(), Duration::max_value());
let key_tag = signer.calculate_key_tag();
println!("key_tag: {}", key_tag);

View File

@ -42,8 +42,8 @@ impl SupportedAlgorithms {
Algorithm::RSASHA256 => 1,
Algorithm::RSASHA1NSEC3SHA1 => 2,
Algorithm::RSASHA512 => 3,
// ECDSAP256SHA256 => 4,
// ECDSAP384SHA384 => 5,
Algorithm::ECDSAP256SHA256 => 4,
Algorithm::ECDSAP384SHA384 => 5,
};
assert!(bit_pos <= u8::max_value());
@ -57,6 +57,8 @@ impl SupportedAlgorithms {
1 => Some(Algorithm::RSASHA256),
2 => Some(Algorithm::RSASHA1NSEC3SHA1),
3 => Some(Algorithm::RSASHA512),
4 => Some(Algorithm::ECDSAP256SHA256),
5 => Some(Algorithm::ECDSAP384SHA384),
_ => None,
}
}

View File

@ -19,10 +19,9 @@
use std::default::Default;
#[cfg(feature = "openssl")]
use openssl::crypto::rsa::RSA;
use openssl::rsa::Rsa;
#[cfg(feature = "openssl")]
use ::rr::dnssec::Algorithm;
use ::rr::dnssec::KeyPair;
#[cfg(feature = "openssl")]
const ROOT_ANCHOR: &'static str = include_str!("Kjqmt7v.pem");
@ -36,12 +35,10 @@ pub struct TrustAnchor {
impl Default for TrustAnchor {
#[cfg(feature = "openssl")]
fn default() -> TrustAnchor {
let rsa = RSA::public_key_from_pem(ROOT_ANCHOR.as_bytes()).expect("Error parsing Kjqmt7v.pem");
assert_eq!(rsa.size().unwrap(), 256);
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");
let alg = Algorithm::RSASHA256;
TrustAnchor{ pkeys: vec![alg.public_key_to_vec(&rsa)] }
TrustAnchor{ pkeys: vec![key.to_vec()] }
}
#[cfg(not(feature = "openssl"))]
@ -65,4 +62,36 @@ impl TrustAnchor {
self.pkeys.push(public_key)
}
}
pub fn get(&self, idx: usize) -> &[u8] {
&self.pkeys[idx]
}
}
#[test]
#[cfg(feature = "openssl")]
fn test_kjqmt7v() {
let trust = TrustAnchor::default();
let test_kjqmt7v: Vec<u8> = vec![3, 1, 0, 1, 168, 0, 32, 169, 85, 102, 186, 66, 232, 134, 187,
128, 76, 218, 132, 228, 126, 245, 109, 189, 122, 236, 97, 38,
21, 85, 44, 236, 144, 109, 33, 22, 208, 239, 32, 112, 40, 197,
21, 84, 20, 77, 254, 175, 231, 199, 203, 143, 0, 93, 209, 130,
52, 19, 58, 192, 113, 10, 129, 24, 44, 225, 253, 20, 173, 34,
131, 188, 131, 67, 95, 157, 242, 246, 49, 50, 81, 147, 26, 23,
109, 240, 218, 81, 229, 79, 66, 230, 4, 134, 13, 251, 53, 149,
128, 37, 15, 85, 156, 197, 67, 196, 255, 213, 28, 190, 61, 232,
207, 208, 103, 25, 35, 127, 159, 196, 126, 231, 41, 218, 6, 131,
95, 164, 82, 232, 37, 233, 161, 142, 188, 46, 203, 207, 86, 52,
116, 101, 44, 51, 207, 86, 169, 3, 59, 205, 245, 217, 115, 18,
23, 151, 236, 128, 137, 4, 27, 110, 3, 161, 183, 45, 10, 115,
91, 152, 78, 3, 104, 115, 9, 51, 35, 36, 242, 124, 45, 186,
133, 233, 219, 21, 232, 58, 1, 67, 56, 46, 151, 75, 6, 33,
193, 142, 98, 94, 206, 201, 7, 87, 125, 158, 123, 173, 233, 82,
65, 168, 30, 187, 232, 169, 1, 212, 211, 39, 110, 64, 177, 20,
192, 162, 230, 252, 56, 209, 156, 46, 106, 171, 2, 100, 75, 40,
19, 245, 117, 252, 33, 96, 30, 13, 238, 73, 205, 158, 233,
106, 67, 16, 62, 82, 77, 98, 135, 61];
assert_eq!(trust.get(0), &test_kjqmt7v as &[u8]);
assert!(trust.contains(&test_kjqmt7v));
}

35
scripts/cargo_publish.sh Executable file
View File

@ -0,0 +1,35 @@
#!/bin/bash -e
trust_dns_dir=$(dirname $0)/..
cd ${trust_dns_dir:?}
for i in client server; do
pushd $i
echo "$0: updating cargo on $i"
cargo update
popd
done
for i in client server; do
pushd $i
echo "$0: building cargo on $i"
cargo build
popd
done
for i in client server; do
pushd $i
echo "$0: testing cargo on $i"
cargo test
cargo publish
popd
done
for i in client server; do
pushd $i
echo "$0: testing cargo on $i"
cargo publish
popd
done

View File

@ -1,4 +0,0 @@
#!/bin/bash
trust_dns_dir=$(dirname $0)/..

View File

@ -1,6 +1,6 @@
[package]
name = "trust-dns-server"
version = "0.9.0"
version = "0.9.3"
authors = ["Benjamin Fry <benjaminfry@me.com>"]
# A short blurb about the package. This is not rendered in any format when
@ -56,7 +56,7 @@ futures = "^0.1"
lazy_static = "^0.2.1"
log = "^0.3.5"
mio = "^0.5.1"
openssl = "^0.8.3"
openssl = "^0.9"
rand = "^0.3"
rustc-serialize = "^0.3.18"
rusqlite = "^0.7.3"

View File

@ -20,7 +20,7 @@ use chrono::UTC;
use trust_dns::op::{Message, UpdateMessage, ResponseCode, Query};
use trust_dns::rr::{DNSClass, Name, RData, Record, RecordType, RrKey, RecordSet};
use trust_dns::rr::rdata::{NSEC, SIG};
use trust_dns::rr::dnssec::Signer;
use trust_dns::rr::dnssec::{KeyPair, Signer};
use ::authority::{Journal, UpdateResult, ZoneType};
use ::error::{PersistenceErrorKind, PersistenceResult};
@ -72,7 +72,7 @@ impl Authority {
pub fn add_secure_key(&mut self, signer: Signer) {
// also add the key to the zone
let zone_ttl = self.get_minimum_ttl();
let dnskey = signer.to_dnskey(self.origin.clone(), zone_ttl);
let dnskey = signer.get_key().to_dnskey(self.origin.clone(), zone_ttl, signer.get_algorithm());
// TODO: also generate the CDS and CDNSKEY
let serial = self.get_serial();
@ -438,7 +438,7 @@ 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 = key.get_algorithm().public_key_from_vec(key.get_public_key());
let pkey = KeyPair::from_vec(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
@ -1039,76 +1039,3 @@ impl Authority {
}
}
}
pub fn create_example() -> Authority {
use std::net::*;
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);
// 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);
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);
records.upsert(Record::new().name(origin.clone()).ttl(86400).rr_type(RecordType::NS).dns_class(DNSClass::IN).rdata(RData::NS(Name::parse("b.iana-servers.net.", None).unwrap()) ).clone(), 0);
// example.com. 60 IN TXT "v=spf1 -all"
//records.upsert(origin.clone(), Record::new().name(origin.clone()).ttl(60).rr_type(RecordType::TXT).dns_class(DNSClass::IN).rdata(RData::TXT{ txt_data: vec!["v=spf1 -all".to_string()] }).clone());
// example.com. 60 IN TXT "$Id: example.com 4415 2015-08-24 20:12:23Z davids $"
records.upsert(Record::new().name(origin.clone()).ttl(60).rr_type(RecordType::TXT).dns_class(DNSClass::IN).rdata(RData::TXT(TXT::new(vec!["$Id: example.com 4415 2015-08-24 20:12:23Z davids $".to_string()]))).clone(), 0);
// example.com. 86400 IN A 93.184.216.34
records.upsert(Record::new().name(origin.clone()).ttl(86400).rr_type(RecordType::A).dns_class(DNSClass::IN).rdata(RData::A(Ipv4Addr::new(93,184,216,34))).clone(), 0);
// example.com. 86400 IN AAAA 2606:2800:220:1:248:1893:25c8:1946
records.upsert(Record::new().name(origin.clone()).ttl(86400).rr_type(RecordType::AAAA).dns_class(DNSClass::IN).rdata(RData::AAAA(Ipv6Addr::new(0x2606,0x2800,0x220,0x1,0x248,0x1893,0x25c8,0x1946))).clone(), 0);
// TODO support these later...
// example.com. 3600 IN RRSIG NSEC 8 2 3600 20150926015219 20150905040848 54108 example.com. d0AXd6QRITqLeiYbQUlJ5O0Og9tSjk7IlxQr9aJO+r+rc1g0dW9i9OCc XXQxdC1/zyubecjD6kSs3vwxzzEEupivaKHKtNPXdnDZ5UUiaIC1VU9l 9h/ik+AR4rCTY6dYPCI6lafD/TlqQLbpEnb34ywkRpl5G3pasPrwEY7b nrAndEY=
// example.com. 3600 IN NSEC www.example.com. A NS SOA TXT AAAA RRSIG NSEC DNSKEY
// example.com. 86400 IN RRSIG NS 8 2 86400 20150915033148 20150824191224 54108 example.com. O2TCB5/v/b1XGlTQEj0/oGKp7dTueQ7zRmCtADDEDWrzLdWrKcmDGF37 mgKejcAlSYVhWLxyLlet7KqJhLu+oQcDTNf/BT3vNX/Ivx3sKhUUMpfi 8Mn5zhRqM9gbzZVCS/toJIYqOBqvAkS7UpkmpLzl0Zt2h4j0Gp/8GwRb ZU67l6M=
// example.com. 86400 IN RRSIG AAAA 8 2 86400 20150914212400 20150824191224 54108 example.com. AHd2BDNjtg4jPRQwyT4FHtlVTZDZ6IIusYVGCzWfnt5SZOoizyXnJhqX 44MeVTqi1/2cskpKvRkK3bkYnVUcjZiFgSaa9xJHmXrslaTr5mOmXt9s 6k95N1daYKhDKKcr0M4TXLUgdnBr+/pMFiLsyOoDb8GJDT8Llmpk52Ie ysJX8BY=
// example.com. 86400 IN RRSIG A 8 2 86400 20150914083326 20150824191224 54108 example.com. La1p2R7GPMrXEm3kcznSJ70sOspmfSDsgOZ74GlzgaFfMRveA20IDUnZ /HI9M95/tBWbHdHBtm9aCK+4n7EluhNPTAT1+88V6xK7Lc7pcBfBXIHg DAdUoj26VIh7NRml/0QR0dFu4PriA/wLNe+d1Q961qf0JZP80TU4IMBC X/W6Ijk=
// example.com. 60 IN RRSIG TXT 8 2 60 20150914201612 20150824191224 54108 example.com. Be/bPvaVVK/o66QOHJZMFBDCQVhP44jptS9sZe8Vpfmzd72/v+1gwn1z u2+xisePSpAMtDZsFJgqsCjpbLFvmhNdh8ktlq/kuCME5hZs7qY7DZIB VwkSTsJPIq8qhX22clfIbqzaypuIX9ajWr+5i0nGQLNekMB07t4/GCoJ q5QpQoE=
// example.com. 3600 IN RRSIG DNSKEY 8 2 3600 20150914090528 20150824071818 31406 example.com. rZJRBwHhYzCDwkDEXqECHNWezTNj2A683I/yHHqD1j9ytGHGskGEEyJC i5fk70YCm64GqDYKu70kgv7hCFqc4OM3aD88QDe3L4Uv7ZXqouNbjTEO 3BEBI13GetRkK5qLndl30Y/urOBASQFELQUJsvQBR2gJMdQsb6G0mHIW rubY2SxAGa9rQW7yehRQNK4ME37FqINBDuIV9o7kULPhn9Ux1Qx62prd 9nikzamGxFL+9dFDOfnYVw2C/OgGJNIXh5QyKMG4qXmXb6sB/V3P+FE+ +vkt3RToE2xPN5bf1vVIlEJof6LtojrowwnZpiphTXFJF/BJrgiotGt3 Gsd8Cw==
// example.com. 3600 IN DNSKEY 256 3 8 AwEAAcZMEndf6/+kG6Dp7re/grJ9f5CP5bQplBGokyxbM4oPNeBfWMIC +xY+ICgTyJarVB4aPYNMV7znsHM4XwU8hfpZ3ZcmT+69KyGqs+tt2pc/ si30dnUpPo/AMnN7Kul2SgqT9g1bb5O0D/CH2txo6YXr/BbuNHLqAh/x mof1QYkl6GoP
// example.com. 3600 IN DNSKEY 256 3 8 AwEAAeZFCLkW/sztmJmpmZo/udvAyqshiLO34zHzzkVPrhuUBA/xb3wk YeCvMO6iBxCD+/Dk7fWEAT1NR21bDKHySVHE5cre+fqnXI+9NCjkMoBE 193j8G5HscIpWpG1qgkelBhmucfUPv+R4AIhpfjc352eh1q/SniYUGR4 fytlDZVXCLhL
// example.com. 3600 IN DNSKEY 257 3 8 AwEAAbOFAxl+Lkt0UMglZizKEC1AxUu8zlj65KYatR5wBWMrh18TYzK/ ig6Y1t5YTWCO68bynorpNu9fqNFALX7bVl9/gybA0v0EhF+dgXmoUfRX 7ksMGgBvtfa2/Y9a3klXNLqkTszIQ4PEMVCjtryl19Be9/PkFeC9ITjg MRQsQhmB39eyMYnal+f3bUxKk4fq7cuEU0dbRpue4H/N6jPucXWOwiMA kTJhghqgy+o9FfIp+tR/emKao94/wpVXDcPf5B18j7xz2SvTTxiuqCzC MtsxnikZHcoh1j4g+Y1B8zIMIvrEM+pZGhh/Yuf4RwCBgaYCi9hpiMWV vS4WBzx0/lU=
// example.com. 3600 IN RRSIG SOA 8 2 3600 20150926132522 20150905040848 54108 example.com. q8psdDPaJVo9KPVgMNR2N1by3LMEci+3HyTmN/Xv3DgDFG5MqNlX9Dfj dUBIMbvYmkUUPQ9fIWYA+ldmDHiRBiHIcvvk/LYD8mODWL6RoF+GEsW0 zm43RNBnbE41wtNrch5WU/q1ko2svB98ooqePWWuFzmdyPpidtLCgSCz FCiCiVQ=
// www
let www_name: Name = Name::parse("www.example.com.", None).unwrap();
// www.example.com. 86400 IN TXT "v=spf1 -all"
records.upsert(Record::new().name(www_name.clone()).ttl(86400).rr_type(RecordType::TXT).dns_class(DNSClass::IN).rdata(RData::TXT(TXT::new(vec!["v=spf1 -all".to_string()]))).clone(), 0);
// www.example.com. 86400 IN A 93.184.216.34
records.upsert(Record::new().name(www_name.clone()).ttl(86400).rr_type(RecordType::A).dns_class(DNSClass::IN).rdata(RData::A(Ipv4Addr::new(93,184,216,34))).clone(), 0);
// www.example.com. 86400 IN AAAA 2606:2800:220:1:248:1893:25c8:1946
records.upsert(Record::new().name(www_name.clone()).ttl(86400).rr_type(RecordType::AAAA).dns_class(DNSClass::IN).rdata(RData::AAAA(Ipv6Addr::new(0x2606,0x2800,0x220,0x1,0x248,0x1893,0x25c8,0x1946))).clone(), 0);
// www.example.com. 3600 IN RRSIG NSEC 8 3 3600 20150925215757 20150905040848 54108 example.com. ZKIVt1IN3O1FWZPSfrQAH7nHt7RUFDjcbh7NxnEqd/uTGCnZ6SrAEgrY E9GMmBwvRjoucphGtjkYOpPJPe5MlnTHoYCjxL4qmG3LsD2KD0bfPufa ibtlQZRrPglxZ92hBKK3ZiPnPRe7I9yni2UQSQA7XDi7CQySYyo490It AxdXjAo=
// www.example.com. 3600 IN NSEC example.com. A TXT AAAA RRSIG NSEC
// www.example.com. 86400 IN RRSIG TXT 8 3 86400 20150914142952 20150824191224 54108 example.com. LvODnPb7NLDZfHPBOrr/qLnOKA670vVYKQSk5Qkz3MPNKDVAFJqsP2Y6 UYcypSJZfcSjfIk2mU9dUiansU2ZL80OZJUsUobqJt5De748ovITYDJ7 afbohQzPg+4E1GIWMkJZ/VQD3B2pmr7J5rPn+vejxSQSoI93AIQaTpCU L5O/Bac=
// www.example.com. 86400 IN RRSIG AAAA 8 3 86400 20150914082216 20150824191224 54108 example.com. kje4FKE+7d/j4OzWQelcKkePq6DxCRY/5btAiUcZNf+zVNlHK+o57h1r Y76ZviWChQB8Np2TjA1DrXGi/kHr2KKE60H5822mFZ2b9O+sgW4q6o3G kO2E1CQxbYe+nI1Z8lVfjdCNm81zfvYqDjo2/tGqagehxG1V9MBZO6br 4KKdoa4=
// www.example.com. 86400 IN RRSIG A 8 3 86400 20150915023456 20150824191224 54108 example.com. cWtw0nMvcXcYNnxejB3Le3KBfoPPQZLmbaJ8ybdmzBDefQOm1ZjZZMOP wHEIxzdjRhG9mLt1mpyo1H7OezKTGX+mDtskcECTl/+jB/YSZyvbwRxj e88Lrg4D+D2MiajQn3XSWf+6LQVe1J67gdbKTXezvux0tRxBNHHqWXRk pxCILes=
return records;
}
pub fn create_secure_example() -> Authority {
use chrono::Duration;
use openssl::crypto::rsa::RSA;
use trust_dns::rr::dnssec::*;
let mut authority: Authority = create_example();
let rsa = RSA::generate(2048).unwrap();
let signer = Signer::new(Algorithm::RSASHA256, rsa, authority.get_origin().clone(), Duration::weeks(1));
authority.add_secure_key(signer);
authority.secure_zone();
authority
}

View File

@ -48,14 +48,14 @@ use std::io::{Read, Write};
use chrono::{Duration};
use docopt::Docopt;
use log::LogLevel;
use openssl::crypto::rsa::RSA;
use openssl::rsa::Rsa;
use trust_dns::error::ParseResult;
use trust_dns::logger;
use trust_dns::version;
use trust_dns::serialize::txt::{Lexer, Parser};
use trust_dns::rr::Name;
use trust_dns::rr::dnssec::{Algorithm, Signer};
use trust_dns::rr::dnssec::{Algorithm, KeyPair, Signer};
use trust_dns_server::authority::{Authority, Catalog, Journal, ZoneType};
use trust_dns_server::config::{Config, ZoneConfig};
@ -162,7 +162,7 @@ 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 pkey = if key_path.exists() {
let rsa = if key_path.exists() {
info!("reading key: {:?}", key_path);
// TODO: validate owndership
@ -174,7 +174,7 @@ fn load_zone(zone_dir: &Path, zone: &ZoneConfig) -> Result<Authority, String> {
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) {
match Rsa::private_key_from_pem(&rsa_bytes) {
Ok(rsa) => rsa,
Err(e) => return Err(format!("error reading private key file: {:?}: {}", key_path, e)),
}
@ -187,7 +187,7 @@ fn load_zone(zone_dir: &Path, zone: &ZoneConfig) -> Result<Authority, String> {
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: 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) {
@ -198,6 +198,8 @@ fn load_zone(zone_dir: &Path, zone: &ZoneConfig) -> Result<Authority, String> {
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));

View File

@ -1,3 +1,6 @@
extern crate chrono;
extern crate futures;
extern crate openssl;
extern crate rusqlite;
extern crate trust_dns;
extern crate trust_dns_server;
@ -11,7 +14,9 @@ use trust_dns::rr::*;
use trust_dns::rr::rdata::*;
use trust_dns::op::*;
use trust_dns_server::authority::*;
use trust_dns_server::authority::authority::{create_example, create_secure_example};
mod common;
use common::authority::{create_example, create_secure_example};
#[test]
fn test_search() {

View File

@ -1,3 +1,6 @@
extern crate chrono;
extern crate futures;
extern crate openssl;
extern crate trust_dns;
extern crate trust_dns_server;
@ -9,7 +12,9 @@ use trust_dns::rr::*;
use trust_dns::rr::rdata::*;
use trust_dns_server::authority::*;
use trust_dns_server::authority::authority::create_example;
mod common;
use common::authority::create_example;
pub fn create_test() -> Authority {
let origin: Name = Name::parse("test.com.", None).unwrap();

View File

@ -16,7 +16,7 @@ use futures::{Async, Future, finished, Poll};
use futures::stream::{Fuse, Stream};
use futures::sync::mpsc::{unbounded, UnboundedReceiver};
use futures::task::park;
use openssl::crypto::rsa::RSA;
use openssl::rsa::Rsa;
use tokio_core::reactor::Core;
use trust_dns::client::{ClientFuture, BasicClientHandle, ClientHandle, ClientStreamHandle};
@ -24,15 +24,16 @@ use trust_dns::error::*;
use trust_dns::op::ResponseCode;
use trust_dns::rr::domain;
use trust_dns::rr::{DNSClass, IntoRecordSet, RData, Record, RecordType, RecordSet};
use trust_dns::rr::dnssec::{Algorithm, Signer};
use trust_dns::rr::dnssec::{Algorithm, KeyPair, Signer};
use trust_dns::rr::rdata::*;
use trust_dns::udp::UdpClientStream;
use trust_dns::tcp::TcpClientStream;
use trust_dns_server::authority::Catalog;
use trust_dns_server::authority::authority::{create_example};
mod common;
use common::TestClientStream;
use common::authority::create_example;
#[test]
fn test_query_nonet() {
@ -165,10 +166,11 @@ fn create_sig0_ready_client(io_loop: &Core) -> (BasicClientHandle, domain::Name)
authority.set_allow_update(true);
let origin = authority.get_origin().clone();
let rsa = RSA::generate(512).unwrap();
let rsa = Rsa::generate(512).unwrap();
let key = KeyPair::from_rsa(rsa).unwrap();
let signer = Signer::new(Algorithm::RSASHA256,
rsa,
key,
domain::Name::with_labels(vec!["trusted".to_string(), "example".to_string(), "com".to_string()]),
Duration::max_value());
@ -176,7 +178,7 @@ fn create_sig0_ready_client(io_loop: &Core) -> (BasicClientHandle, domain::Name)
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_public_key())));
auth_key.rdata(RData::KEY(DNSKEY::new(false, false, false, signer.get_algorithm(), signer.get_key().to_vec())));
authority.upsert(auth_key, 0);
// setup the catalog

View File

@ -1,4 +1,5 @@
extern crate chrono;
extern crate futures;
extern crate openssl;
extern crate trust_dns;
extern crate trust_dns_server;
@ -7,21 +8,23 @@ use std::net::*;
use std::fmt;
use chrono::Duration;
use openssl::crypto::rsa::RSA;
use openssl::rsa::Rsa;
#[allow(deprecated)]
use trust_dns::client::{Client, ClientConnection};
use trust_dns::error::*;
use trust_dns::op::*;
use trust_dns::rr::{DNSClass, Record, RecordType, domain, RData};
use trust_dns::rr::dnssec::{Algorithm, Signer, TrustAnchor};
use trust_dns::rr::dnssec::{Algorithm, KeyPair, Signer, TrustAnchor};
use trust_dns::rr::rdata::*;
use trust_dns::serialize::binary::{BinDecoder, BinEncoder, BinSerializable};
use trust_dns::tcp::TcpClientConnection;
use trust_dns::udp::UdpClientConnection;
use trust_dns_server::authority::Catalog;
use trust_dns_server::authority::authority::{create_example, create_secure_example};
mod common;
use common::authority::{create_example, create_secure_example};
pub struct TestClientConnection<'a> {
catalog: &'a Catalog
@ -120,17 +123,19 @@ fn test_query<C: ClientConnection>(client: Client<C>) {
fn test_secure_query_example_nonet() {
let authority = create_secure_example();
let public_key = {
let trust_anchor = {
let signers = authority.get_secure_keys();
signers.first().expect("expected a key in the authority").get_public_key()
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());
trust_anchor
};
let mut catalog = Catalog::new();
catalog.upsert(authority.get_origin().clone(), authority);
let mut trust_anchor = TrustAnchor::new();
trust_anchor.insert_trust_anchor(public_key);
let client = Client::with_trust_anchor(TestClientConnection::new(&catalog), trust_anchor);
test_secure_query_example(client);
@ -223,17 +228,19 @@ fn test_dnssec_rollernet_td_tcp_mixed_case() {
fn test_nsec_query_example_nonet() {
let authority = create_secure_example();
let public_key = {
let trust_anchor = {
let signers = authority.get_secure_keys();
signers.first().expect("expected a key in the authority").get_public_key()
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());
trust_anchor
};
let mut catalog = Catalog::new();
catalog.upsert(authority.get_origin().clone(), authority);
let mut trust_anchor = TrustAnchor::new();
trust_anchor.insert_trust_anchor(public_key);
let client = Client::with_trust_anchor(TestClientConnection::new(&catalog), trust_anchor);
test_nsec_query_example(client);
@ -331,9 +338,10 @@ fn create_sig0_ready_client<'a>(catalog: &'a mut Catalog) -> (Client<TestClientC
authority.set_allow_update(true);
let origin = authority.get_origin().clone();
let rsa = RSA::generate(512).unwrap();
let rsa = Rsa::generate(512).unwrap();
let key = KeyPair::from_rsa(rsa).unwrap();
let signer = Signer::new(Algorithm::RSASHA256, rsa,
let signer = Signer::new(Algorithm::RSASHA256, key,
domain::Name::with_labels(vec!["trusted".to_string(), "example".to_string(), "com".to_string()]),
Duration::max_value());
@ -341,7 +349,7 @@ fn create_sig0_ready_client<'a>(catalog: &'a mut Catalog) -> (Client<TestClientC
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_public_key())));
auth_key.rdata(RData::KEY(DNSKEY::new(false, false, false, signer.get_algorithm(), signer.get_key().to_vec())));
authority.upsert(auth_key, 0);
catalog.upsert(authority.get_origin().clone(), authority);

View File

@ -0,0 +1,82 @@
use std::collections::BTreeMap;
use trust_dns::rr::*;
use trust_dns_server::authority::Authority;
use trust_dns_server::authority::ZoneType;
#[allow(unused)]
pub fn create_example() -> Authority {
use std::net::*;
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);
// 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);
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);
records.upsert(Record::new().name(origin.clone()).ttl(86400).rr_type(RecordType::NS).dns_class(DNSClass::IN).rdata(RData::NS(Name::parse("b.iana-servers.net.", None).unwrap()) ).clone(), 0);
// example.com. 60 IN TXT "v=spf1 -all"
//records.upsert(origin.clone(), Record::new().name(origin.clone()).ttl(60).rr_type(RecordType::TXT).dns_class(DNSClass::IN).rdata(RData::TXT{ txt_data: vec!["v=spf1 -all".to_string()] }).clone());
// example.com. 60 IN TXT "$Id: example.com 4415 2015-08-24 20:12:23Z davids $"
records.upsert(Record::new().name(origin.clone()).ttl(60).rr_type(RecordType::TXT).dns_class(DNSClass::IN).rdata(RData::TXT(TXT::new(vec!["$Id: example.com 4415 2015-08-24 20:12:23Z davids $".to_string()]))).clone(), 0);
// example.com. 86400 IN A 93.184.216.34
records.upsert(Record::new().name(origin.clone()).ttl(86400).rr_type(RecordType::A).dns_class(DNSClass::IN).rdata(RData::A(Ipv4Addr::new(93,184,216,34))).clone(), 0);
// example.com. 86400 IN AAAA 2606:2800:220:1:248:1893:25c8:1946
records.upsert(Record::new().name(origin.clone()).ttl(86400).rr_type(RecordType::AAAA).dns_class(DNSClass::IN).rdata(RData::AAAA(Ipv6Addr::new(0x2606,0x2800,0x220,0x1,0x248,0x1893,0x25c8,0x1946))).clone(), 0);
// TODO support these later...
// example.com. 3600 IN RRSIG NSEC 8 2 3600 20150926015219 20150905040848 54108 example.com. d0AXd6QRITqLeiYbQUlJ5O0Og9tSjk7IlxQr9aJO+r+rc1g0dW9i9OCc XXQxdC1/zyubecjD6kSs3vwxzzEEupivaKHKtNPXdnDZ5UUiaIC1VU9l 9h/ik+AR4rCTY6dYPCI6lafD/TlqQLbpEnb34ywkRpl5G3pasPrwEY7b nrAndEY=
// example.com. 3600 IN NSEC www.example.com. A NS SOA TXT AAAA RRSIG NSEC DNSKEY
// example.com. 86400 IN RRSIG NS 8 2 86400 20150915033148 20150824191224 54108 example.com. O2TCB5/v/b1XGlTQEj0/oGKp7dTueQ7zRmCtADDEDWrzLdWrKcmDGF37 mgKejcAlSYVhWLxyLlet7KqJhLu+oQcDTNf/BT3vNX/Ivx3sKhUUMpfi 8Mn5zhRqM9gbzZVCS/toJIYqOBqvAkS7UpkmpLzl0Zt2h4j0Gp/8GwRb ZU67l6M=
// example.com. 86400 IN RRSIG AAAA 8 2 86400 20150914212400 20150824191224 54108 example.com. AHd2BDNjtg4jPRQwyT4FHtlVTZDZ6IIusYVGCzWfnt5SZOoizyXnJhqX 44MeVTqi1/2cskpKvRkK3bkYnVUcjZiFgSaa9xJHmXrslaTr5mOmXt9s 6k95N1daYKhDKKcr0M4TXLUgdnBr+/pMFiLsyOoDb8GJDT8Llmpk52Ie ysJX8BY=
// example.com. 86400 IN RRSIG A 8 2 86400 20150914083326 20150824191224 54108 example.com. La1p2R7GPMrXEm3kcznSJ70sOspmfSDsgOZ74GlzgaFfMRveA20IDUnZ /HI9M95/tBWbHdHBtm9aCK+4n7EluhNPTAT1+88V6xK7Lc7pcBfBXIHg DAdUoj26VIh7NRml/0QR0dFu4PriA/wLNe+d1Q961qf0JZP80TU4IMBC X/W6Ijk=
// example.com. 60 IN RRSIG TXT 8 2 60 20150914201612 20150824191224 54108 example.com. Be/bPvaVVK/o66QOHJZMFBDCQVhP44jptS9sZe8Vpfmzd72/v+1gwn1z u2+xisePSpAMtDZsFJgqsCjpbLFvmhNdh8ktlq/kuCME5hZs7qY7DZIB VwkSTsJPIq8qhX22clfIbqzaypuIX9ajWr+5i0nGQLNekMB07t4/GCoJ q5QpQoE=
// example.com. 3600 IN RRSIG DNSKEY 8 2 3600 20150914090528 20150824071818 31406 example.com. rZJRBwHhYzCDwkDEXqECHNWezTNj2A683I/yHHqD1j9ytGHGskGEEyJC i5fk70YCm64GqDYKu70kgv7hCFqc4OM3aD88QDe3L4Uv7ZXqouNbjTEO 3BEBI13GetRkK5qLndl30Y/urOBASQFELQUJsvQBR2gJMdQsb6G0mHIW rubY2SxAGa9rQW7yehRQNK4ME37FqINBDuIV9o7kULPhn9Ux1Qx62prd 9nikzamGxFL+9dFDOfnYVw2C/OgGJNIXh5QyKMG4qXmXb6sB/V3P+FE+ +vkt3RToE2xPN5bf1vVIlEJof6LtojrowwnZpiphTXFJF/BJrgiotGt3 Gsd8Cw==
// example.com. 3600 IN DNSKEY 256 3 8 AwEAAcZMEndf6/+kG6Dp7re/grJ9f5CP5bQplBGokyxbM4oPNeBfWMIC +xY+ICgTyJarVB4aPYNMV7znsHM4XwU8hfpZ3ZcmT+69KyGqs+tt2pc/ si30dnUpPo/AMnN7Kul2SgqT9g1bb5O0D/CH2txo6YXr/BbuNHLqAh/x mof1QYkl6GoP
// example.com. 3600 IN DNSKEY 256 3 8 AwEAAeZFCLkW/sztmJmpmZo/udvAyqshiLO34zHzzkVPrhuUBA/xb3wk YeCvMO6iBxCD+/Dk7fWEAT1NR21bDKHySVHE5cre+fqnXI+9NCjkMoBE 193j8G5HscIpWpG1qgkelBhmucfUPv+R4AIhpfjc352eh1q/SniYUGR4 fytlDZVXCLhL
// example.com. 3600 IN DNSKEY 257 3 8 AwEAAbOFAxl+Lkt0UMglZizKEC1AxUu8zlj65KYatR5wBWMrh18TYzK/ ig6Y1t5YTWCO68bynorpNu9fqNFALX7bVl9/gybA0v0EhF+dgXmoUfRX 7ksMGgBvtfa2/Y9a3klXNLqkTszIQ4PEMVCjtryl19Be9/PkFeC9ITjg MRQsQhmB39eyMYnal+f3bUxKk4fq7cuEU0dbRpue4H/N6jPucXWOwiMA kTJhghqgy+o9FfIp+tR/emKao94/wpVXDcPf5B18j7xz2SvTTxiuqCzC MtsxnikZHcoh1j4g+Y1B8zIMIvrEM+pZGhh/Yuf4RwCBgaYCi9hpiMWV vS4WBzx0/lU=
// example.com. 3600 IN RRSIG SOA 8 2 3600 20150926132522 20150905040848 54108 example.com. q8psdDPaJVo9KPVgMNR2N1by3LMEci+3HyTmN/Xv3DgDFG5MqNlX9Dfj dUBIMbvYmkUUPQ9fIWYA+ldmDHiRBiHIcvvk/LYD8mODWL6RoF+GEsW0 zm43RNBnbE41wtNrch5WU/q1ko2svB98ooqePWWuFzmdyPpidtLCgSCz FCiCiVQ=
// www
let www_name: Name = Name::parse("www.example.com.", None).unwrap();
// www.example.com. 86400 IN TXT "v=spf1 -all"
records.upsert(Record::new().name(www_name.clone()).ttl(86400).rr_type(RecordType::TXT).dns_class(DNSClass::IN).rdata(RData::TXT(TXT::new(vec!["v=spf1 -all".to_string()]))).clone(), 0);
// www.example.com. 86400 IN A 93.184.216.34
records.upsert(Record::new().name(www_name.clone()).ttl(86400).rr_type(RecordType::A).dns_class(DNSClass::IN).rdata(RData::A(Ipv4Addr::new(93,184,216,34))).clone(), 0);
// www.example.com. 86400 IN AAAA 2606:2800:220:1:248:1893:25c8:1946
records.upsert(Record::new().name(www_name.clone()).ttl(86400).rr_type(RecordType::AAAA).dns_class(DNSClass::IN).rdata(RData::AAAA(Ipv6Addr::new(0x2606,0x2800,0x220,0x1,0x248,0x1893,0x25c8,0x1946))).clone(), 0);
// www.example.com. 3600 IN RRSIG NSEC 8 3 3600 20150925215757 20150905040848 54108 example.com. ZKIVt1IN3O1FWZPSfrQAH7nHt7RUFDjcbh7NxnEqd/uTGCnZ6SrAEgrY E9GMmBwvRjoucphGtjkYOpPJPe5MlnTHoYCjxL4qmG3LsD2KD0bfPufa ibtlQZRrPglxZ92hBKK3ZiPnPRe7I9yni2UQSQA7XDi7CQySYyo490It AxdXjAo=
// www.example.com. 3600 IN NSEC example.com. A TXT AAAA RRSIG NSEC
// www.example.com. 86400 IN RRSIG TXT 8 3 86400 20150914142952 20150824191224 54108 example.com. LvODnPb7NLDZfHPBOrr/qLnOKA670vVYKQSk5Qkz3MPNKDVAFJqsP2Y6 UYcypSJZfcSjfIk2mU9dUiansU2ZL80OZJUsUobqJt5De748ovITYDJ7 afbohQzPg+4E1GIWMkJZ/VQD3B2pmr7J5rPn+vejxSQSoI93AIQaTpCU L5O/Bac=
// www.example.com. 86400 IN RRSIG AAAA 8 3 86400 20150914082216 20150824191224 54108 example.com. kje4FKE+7d/j4OzWQelcKkePq6DxCRY/5btAiUcZNf+zVNlHK+o57h1r Y76ZviWChQB8Np2TjA1DrXGi/kHr2KKE60H5822mFZ2b9O+sgW4q6o3G kO2E1CQxbYe+nI1Z8lVfjdCNm81zfvYqDjo2/tGqagehxG1V9MBZO6br 4KKdoa4=
// www.example.com. 86400 IN RRSIG A 8 3 86400 20150915023456 20150824191224 54108 example.com. cWtw0nMvcXcYNnxejB3Le3KBfoPPQZLmbaJ8ybdmzBDefQOm1ZjZZMOP wHEIxzdjRhG9mLt1mpyo1H7OezKTGX+mDtskcECTl/+jB/YSZyvbwRxj e88Lrg4D+D2MiajQn3XSWf+6LQVe1J67gdbKTXezvux0tRxBNHHqWXRk pxCILes=
return records;
}
#[allow(unused)]
pub fn create_secure_example() -> Authority {
use chrono::Duration;
use openssl::rsa::Rsa;
use trust_dns::rr::dnssec::*;
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));
authority.add_secure_key(signer);
authority.secure_zone();
authority
}

View File

@ -12,11 +12,15 @@ use trust_dns::serialize::binary::*;
use trust_dns_server::authority::Catalog;
pub mod authority;
#[allow(unused)]
pub struct TestClientStream {
catalog: Catalog,
outbound_messages: Fuse<UnboundedReceiver<Vec<u8>>>,
}
#[allow(unused)]
impl TestClientStream {
pub fn new(catalog: Catalog) -> (Box<Future<Item=Self, Error=io::Error>>, Box<ClientStreamHandle>) {
let (message_sender, outbound_messages) = unbounded();

View File

@ -18,10 +18,10 @@ use trust_dns::tcp::TcpClientStream;
use trust_dns::udp::UdpClientStream;
use trust_dns_server::authority::Catalog;
use trust_dns_server::authority::authority::create_secure_example;
mod common;
use common::TestClientStream;
use common::authority::create_secure_example;
#[test]
fn test_secure_query_example_nonet() {
@ -171,17 +171,19 @@ fn with_nonet<F>(test: F) where F: Fn(SecureClientHandle<MemoizeClientHandle<Bas
let authority = create_secure_example();
let public_key = {
let trust_anchor = {
let signers = authority.get_secure_keys();
signers.first().expect("expected a key in the authority").get_public_key()
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());
trust_anchor
};
let mut catalog = Catalog::new();
catalog.upsert(authority.get_origin().clone(), authority);
let mut trust_anchor = TrustAnchor::new();
trust_anchor.insert_trust_anchor(public_key);
let io_loop = Core::new().unwrap();
let (stream, sender) = TestClientStream::new(catalog);
let client = ClientFuture::new(stream, sender, io_loop.handle(), None);

View File

@ -1,4 +1,7 @@
extern crate chrono;
extern crate futures;
extern crate mio;
extern crate openssl;
extern crate trust_dns;
extern crate trust_dns_server;
@ -14,8 +17,9 @@ use trust_dns::tcp::TcpClientConnection;
use trust_dns_server::ServerFuture;
use trust_dns_server::authority::*;
use trust_dns_server::authority::authority::create_example;
mod common;
use common::authority::create_example;
#[test]
fn test_server_www_udp() {

View File

@ -1,4 +1,7 @@
extern crate chrono;
extern crate futures;
extern crate mio;
extern crate openssl;
extern crate trust_dns;
extern crate trust_dns_server;
@ -17,7 +20,9 @@ use trust_dns::rr::*;
#[allow(deprecated)]
use trust_dns_server::Server;
use trust_dns_server::authority::*;
use trust_dns_server::authority::authority::create_example;
mod common;
use common::authority::create_example;
#[test]
fn test_server_www_udp() {