make openssl optional

This commit is contained in:
Benjamin Fry 2016-12-18 17:39:09 -08:00
parent 71559fcf95
commit 8559dc0d47
16 changed files with 163 additions and 24 deletions

View File

@ -2,6 +2,10 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## 0.9.1
### Changed
- OpenSSL is now an optional feature for the client
## 0.9.0
### Added
- new ServerFuture tokio and futures based server, #61

View File

@ -37,6 +37,7 @@ license = "MIT/Apache-2.0"
build = "build.rs"
[features]
default = ["openssl"]
[lib]
name = "trust_dns"
@ -51,7 +52,7 @@ futures = "^0.1"
lazy_static = "^0.2.1"
log = "^0.3.5"
mio = "^0.5.1"
openssl = "^0.8.3"
openssl = { version = "^0.8.3", optional = true }
rand = "^0.3"
rustc-serialize = "^0.3.18"
time = "^0.1"

View File

@ -13,11 +13,15 @@
// limitations under the License.
use std::cell::RefCell;
#[cfg(feature = "openssl")]
use std::collections::HashSet;
#[cfg(feature = "openssl")]
use std::sync::Arc as Rc;
#[cfg(feature = "openssl")]
use std::convert::From;
use chrono::UTC;
#[cfg(feature = "openssl")]
use data_encoding::base32hex;
use rand;
@ -25,8 +29,12 @@ use ::error::*;
use ::rr::{DNSClass, RecordType, Record, RData};
use ::rr::rdata::NULL;
use ::rr::domain;
use ::rr::dnssec::{Signer, TrustAnchor};
use ::op::{ Message, MessageType, OpCode, Query, ResponseCode, UpdateMessage };
use ::rr::dnssec::Signer;
#[cfg(feature = "openssl")]
use ::rr::dnssec::TrustAnchor;
use ::op::{Message, MessageType, OpCode, Query, UpdateMessage};
#[cfg(feature = "openssl")]
use ::op::ResponseCode;
use ::serialize::binary::*;
use ::client::ClientConnection;
@ -40,6 +48,7 @@ use ::client::ClientConnection;
#[deprecated = "see trust_dns::client::ClientFuture"]
pub struct Client<C: ClientConnection> {
client_connection: RefCell<C>,
#[cfg(feature = "openssl")]
trust_anchor: TrustAnchor,
}
@ -51,11 +60,23 @@ impl<C: ClientConnection> Client<C> {
///
/// * `client_connection` - the client_connection to use for all communication
#[allow(deprecated)]
#[cfg(feature = "openssl")]
pub fn new(client_connection: C) -> Client<C> {
Client{ client_connection: RefCell::new(client_connection),
trust_anchor: TrustAnchor::default() }
Self::with_trust_anchor(client_connection, TrustAnchor::default())
}
/// Creates a new DNS client with the specified connection type
///
/// # Arguments
///
/// * `client_connection` - the client_connection to use for all communication
#[allow(deprecated)]
#[cfg(not(feature = "openssl"))]
pub fn new(client_connection: C) -> Client<C> {
Client{ client_connection: RefCell::new(client_connection) }
}
/// This variant allows for the trust_anchor to be replaced
///
/// # Arguments
@ -64,6 +85,7 @@ impl<C: ClientConnection> Client<C> {
/// * `trust_anchor` - the set of trusted DNSKEY public_keys, by default this only contains the
/// root public_key.
#[allow(deprecated)]
#[cfg(feature = "openssl")]
pub fn with_trust_anchor(client_connection: C, trust_anchor: TrustAnchor) -> Client<C> {
Client{ client_connection: RefCell::new(client_connection),
trust_anchor: trust_anchor }
@ -89,6 +111,7 @@ impl<C: ClientConnection> Client<C> {
/// * `query_name` - the label to lookup
/// * `query_class` - most likely this should always be DNSClass::IN
/// * `query_type` - record type to lookup
#[cfg(feature = "openssl")]
pub fn secure_query(&self, query_name: &domain::Name, query_class: DNSClass, query_type: RecordType) -> ClientResult<Message> {
// TODO: if we knew we were talking with a DNS server that supported multiple queries, these
// could be a single multiple query request...
@ -164,6 +187,7 @@ impl<C: ClientConnection> Client<C> {
/// Verifies a record set against the supplied signatures, looking up the DNSKey chain.
/// returns the chain of proof or an error if there is none.
#[cfg(feature = "openssl")]
fn recursive_query_verify(&self, name: &domain::Name, rrset: Vec<&Record>, rrsigs: Vec<&Record>,
query_type: RecordType, query_class: DNSClass) -> ClientResult<Vec<Record>> {
@ -252,6 +276,7 @@ impl<C: ClientConnection> Client<C> {
/// attempts to verify the DNSKey against the DS of the parent.
/// returns the chain of proof or an error if there is none.
#[cfg(feature = "openssl")]
fn verify_dnskey(&self, dnskey: &Record) -> ClientResult<Vec<Record>> {
let name: &domain::Name = dnskey.get_name();
@ -366,6 +391,7 @@ impl<C: ClientConnection> Client<C> {
// Since a validated NSEC RR proves the existence of both itself and its
// corresponding RRSIG RR, a validator MUST ignore the settings of the
// NSEC and RRSIG bits in an NSEC RR.
#[cfg(feature = "openssl")]
fn verify_nsec(&self, query_name: &domain::Name, query_type: RecordType,
_: DNSClass, nsecs: Vec<&Record>) -> ClientResult<()> {
// first look for a record with the same name
@ -465,6 +491,7 @@ impl<C: ClientConnection> Client<C> {
// encloser proof for X" means that the algorithm above (or an
// equivalent algorithm) proves that X does not exist by proving that an
// ancestor of X is its closest encloser.
#[cfg(feature = "openssl")]
fn verify_nsec3(&self, query_name: &domain::Name, query_type: RecordType,
_: DNSClass, soa: Option<&Record>,
nsec3s: Vec<&Record>) -> ClientResult<()> {

View File

@ -16,7 +16,9 @@ use ::client::ClientHandle;
use ::error::*;
use ::op::{Message, OpCode, Query};
use ::rr::{domain, DNSClass, RData, Record, RecordType};
use ::rr::dnssec::{Signer, TrustAnchor};
#[cfg(feature = "openssl")]
use ::rr::dnssec::Signer;
use ::rr::dnssec::TrustAnchor;
use ::rr::rdata::{dnskey, DNSKEY, DS, SIG};
use ::serialize::binary::{BinEncoder, BinSerializable};
@ -647,6 +649,7 @@ fn verify_default_rrset<H>(
}
/// Verifies the given SIG of the RRSET with the DNSKEY.
#[cfg(feature = "openssl")]
fn verify_rrset_with_dnskey(dnskey: &DNSKEY,
sig: &SIG,
rrset: &Rrset) -> ClientResult<()> {
@ -667,6 +670,13 @@ fn verify_rrset_with_dnskey(dnskey: &DNSKEY,
.map_err(|e| e.into()))
}
/// Will always return an error. To enable record verification compile with the openssl feature.
#[cfg(not(feature = "openssl"))]
fn verify_rrset_with_dnskey(_: &DNSKEY, _: &SIG, _: &Rrset) -> ClientResult<()> {
Err(ClientErrorKind::Message("openssl feature not enabled").into())
}
/// Verifies NSEC records
///
/// ```text

View File

@ -18,11 +18,14 @@ use std::io::Error as IoError;
use futures::Canceled;
use futures::sync::mpsc::SendError;
#[cfg(feature = "openssl")]
use openssl::error::ErrorStack as SslErrorStack;
#[cfg(not(feature = "openssl"))]
use ::error::dnssec_error::not_openssl::SslErrorStack;
use ::op::ResponseCode;
use ::rr::{Name, Record};
use ::rr::dnssec::{DnsSecError, DnsSecErrorKind};
use ::error::{DnsSecError, DnsSecErrorKind};
error_chain! {
// The type defined for this error. These are the conventional

View File

@ -16,8 +16,11 @@
use std::string::FromUtf8Error;
#[cfg(feature = "openssl")]
use openssl::error::ErrorStack as SslErrorStack;
use ::rr::dnssec::{DnsSecError, DnsSecErrorKind};
#[cfg(not(feature = "openssl"))]
use ::error::dnssec_error::not_openssl::SslErrorStack;
use ::error::{DnsSecError, DnsSecErrorKind};
use ::rr::Name;

View File

@ -15,7 +15,10 @@
*/
use std::io::Error as IoError;
#[cfg(feature = "openssl")]
use openssl::error::ErrorStack as SslErrorStack;
#[cfg(not(feature = "openssl"))]
use self::not_openssl::SslErrorStack;
error_chain! {
// The type defined for this error. These are the conventional
@ -55,3 +58,24 @@ error_chain! {
}
}
}
#[cfg(not(feature = "openssl"))]
pub mod not_openssl {
use std;
#[derive(Debug)]
pub struct SslErrorStack;
impl std::fmt::Display for SslErrorStack {
fn fmt(&self, _: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
Ok(())
}
}
impl std::error::Error for SslErrorStack {
fn description(&self) -> &str {
"openssl feature not enabled"
}
}
}

View File

@ -17,30 +17,35 @@
//! All defined errors for Trust-DNS
mod decode_error;
mod dnssec_error;
mod encode_error;
mod client_error;
mod lexer_error;
mod parse_error;
pub use self::decode_error::Error as DecodeError;
pub use self::dnssec_error::Error as DnsSecError;
pub use self::encode_error::Error as EncodeError;
pub use self::client_error::Error as ClientError;
pub use self::lexer_error::Error as LexerError;
pub use self::parse_error::Error as ParseError;
pub use self::decode_error::ErrorKind as DecodeErrorKind;
pub use self::dnssec_error::ErrorKind as DnsSecErrorKind;
pub use self::encode_error::ErrorKind as EncodeErrorKind;
pub use self::client_error::ErrorKind as ClientErrorKind;
pub use self::lexer_error::ErrorKind as LexerErrorKind;
pub use self::parse_error::ErrorKind as ParseErrorKind;
pub use self::decode_error::ChainErr as DecodeChainErr;
pub use self::dnssec_error::ChainErr as DnsSecChainErr;
pub use self::encode_error::ChainErr as EncodeChainErr;
pub use self::client_error::ChainErr as ClientChainErr;
pub use self::lexer_error::ChainErr as LexerChainErr;
pub use self::parse_error::ChainErr as ParseChainErr;
pub type DecodeResult<T> = Result<T, DecodeError>;
pub type DnsSecResult<T> = Result<T, DnsSecError>;
pub type EncodeResult = Result<(), EncodeError>;
pub type ClientResult<T> = Result<T, ClientError>;
pub type LexerResult<T> = Result<T, LexerError>;

View File

@ -34,6 +34,7 @@ extern crate data_encoding;
#[macro_use] extern crate lazy_static;
#[macro_use] extern crate log;
extern crate mio;
#[cfg(feature = "openssl")]
extern crate openssl;
extern crate rand;
extern crate rustc_serialize;

View File

@ -20,11 +20,12 @@ use std::fmt::Debug;
use std::mem;
use ::error::*;
use ::rr::resource::Record;
use ::rr::domain::Name;
use ::rr::{RData, RecordType, DNSClass};
use ::rr::{Record, RecordType};
#[cfg(feature = "openssl")]
use ::rr::{DNSClass, Name, RData};
#[cfg(feature = "openssl")]
use ::rr::rdata::SIG;
use ::rr::dnssec::{DnsSecResult, Signer};
use ::rr::dnssec::Signer;
use ::serialize::binary::{BinEncoder, BinDecoder, BinSerializable, EncodeMode};
use super::{MessageType, Header, Query, Edns, OpCode, ResponseCode};
@ -437,7 +438,7 @@ impl Message {
}
// TODO: where's the 'right' spot for this function
// TODO: probably a bad idea to expose consumers to the SslErrorStack...
#[cfg(feature = "openssl")]
pub fn sign(&mut self, signer: &Signer, inception_time: u32) -> DnsSecResult<()> {
debug!("signing message: {:?}", self);
let signature: Vec<u8> = try!(signer.sign_message(self));
@ -487,6 +488,11 @@ impl Message {
self.add_sig0(sig0);
Ok(())
}
#[cfg(not(feature = "openssl"))]
pub fn sign(&mut self, _: &Signer, _: u32) -> DnsSecResult<()> {
Err(DnsSecErrorKind::Message("openssl feature not enabled").into())
}
}
/// to reduce errors in using the Message struct as an Update, this will do the call throughs
@ -550,7 +556,8 @@ impl UpdateMessage for Message {
fn get_sig0(&self) -> &[Record] { self.get_sig0() }
// TODO: where's the 'right' spot for this function
fn sign(&mut self, signer: &Signer, inception_time: u32) -> DnsSecResult<()> { self.sign(signer, inception_time) }
fn sign(&mut self, signer: &Signer, inception_time: u32) -> DnsSecResult<()> { Message::sign(self, signer, inception_time) }
}
impl BinSerializable<Message> for Message {

View File

@ -15,10 +15,13 @@
*/
use std::str::FromStr;
#[cfg(feature = "openssl")]
use openssl::crypto::rsa::RSA;
#[cfg(feature = "openssl")]
use openssl::bn::BigNum;
use ::rr::dnssec::{DigestType, DnsSecResult};
#[cfg(feature = "openssl")]
use ::rr::dnssec::DigestType;
use ::serialize::binary::*;
use ::error::*;
@ -108,6 +111,7 @@ pub enum Algorithm {
}
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...
@ -118,6 +122,7 @@ impl Algorithm {
}
#[cfg(feature = "openssl")]
pub fn verify(&self, public_key: &RSA, data: &[u8], signature: &[u8]) -> DnsSecResult<()> {
let digest_type = DigestType::from(*self);
@ -150,6 +155,7 @@ impl Algorithm {
}
}
#[cfg(feature = "openssl")]
pub fn public_key_from_vec(&self, public_key: &[u8]) -> DecodeResult<RSA> {
match *self {
Algorithm::RSASHA1 |
@ -203,6 +209,12 @@ impl Algorithm {
}
}
#[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 |
@ -287,8 +299,10 @@ impl From<Algorithm> for u8 {
}
#[cfg(test)]
#[cfg(feature = "openssl")]
mod test {
use super::Algorithm;
#[cfg(feature = "openssl")]
use openssl::crypto::rsa;
#[test]

View File

@ -13,9 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#[cfg(feature = "openssl")]
use openssl::crypto::hash;
use ::rr::dnssec::{Algorithm, DnsSecResult};
use ::rr::dnssec::Algorithm;
use ::error::*;
// 0 Reserved - [RFC3658]
@ -45,6 +46,7 @@ impl DigestType {
}
}
#[cfg(feature = "openssl")]
pub fn to_hash(&self) -> hash::Type {
match *self {
DigestType::SHA1 => hash::Type::SHA1,
@ -54,9 +56,15 @@ impl DigestType {
}
}
#[cfg(feature = "openssl")]
pub fn hash(&self, data: &[u8]) -> DnsSecResult<Vec<u8>> {
hash::hash(self.to_hash(), data).map_err(|e| e.into())
}
#[cfg(not(feature = "openssl"))]
pub fn hash(&self, _: &[u8]) -> DnsSecResult<Vec<u8>> {
Err(DnsSecErrorKind::Message("openssl feature not enabled").into())
}
}
impl From<Algorithm> for DigestType {

View File

@ -18,7 +18,6 @@
mod algorithm;
mod digest_type;
mod error;
mod nsec3;
mod signer;
mod supported_algorithm;
@ -31,8 +30,7 @@ pub use self::signer::Signer;
pub use self::supported_algorithm::SupportedAlgorithms;
pub use self::trust_anchor::TrustAnchor;
pub use self::error::Error as DnsSecError;
pub use self::error::ErrorKind as DnsSecErrorKind;
pub use self::error::ChainErr as DnsSecChainErr;
pub type DnsSecResult<T> = Result<T, DnsSecError>;
pub use ::error::DnsSecError;
pub use ::error::DnsSecErrorKind;
pub use ::error::DnsSecChainErr;
pub use ::error::DnsSecResult;

View File

@ -13,12 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#[cfg(feature = "openssl")]
use std::io::Write;
#[cfg(feature = "openssl")]
use openssl::crypto::hash;
use ::error::*;
use ::rr::dnssec::{DigestType, DnsSecResult};
#[cfg(feature = "openssl")]
use ::rr::dnssec::DigestType;
#[cfg(feature = "openssl")]
use ::rr::Name;
#[cfg(feature = "openssl")]
use ::serialize::binary::{BinEncoder, BinSerializable};
// RFC 5155 NSEC3 March 2008
@ -136,6 +141,7 @@ impl Nsec3HashAlgorithm {
// 3. If the owner name is a wildcard name, the owner name is in its
// original unexpanded form, including the "*" label (no wildcard
// substitution);
#[cfg(feature = "openssl")]
pub fn hash(&self, salt: &[u8], name: &Name, iterations: u16) -> DnsSecResult<Vec<u8>> {
match *self {
// if there ever is more than just SHA1 support, this should be a genericized method
@ -153,6 +159,7 @@ impl Nsec3HashAlgorithm {
}
// until there is another supported algorithm, just hardcoded to this.
#[cfg(feature = "openssl")]
fn sha1_recursive_hash(salt: &[u8], bytes: Vec<u8>, iterations: u16) -> DnsSecResult<Vec<u8>> {
hash::Hasher::new(DigestType::SHA1.to_hash())
.map_err(|e| e.into())
@ -178,6 +185,7 @@ impl From<Nsec3HashAlgorithm> for u8 {
}
#[test]
#[cfg(feature = "openssl")]
fn test_hash() {
let name = Name::new().label("www").label("example").label("com");
@ -189,6 +197,7 @@ fn test_hash() {
}
#[test]
#[cfg(feature = "openssl")]
fn test_known_hashes() {
// H(example) = 0p9mhaveqvm6t7vbl5lop2u3t2rp3tom
assert_eq!(hash_with_base32("example"), "0p9mhaveqvm6t7vbl5lop2u3t2rp3tom");
@ -225,6 +234,7 @@ fn test_known_hashes() {
}
#[cfg(test)]
#[cfg(feature = "openssl")]
fn hash_with_base32(name: &str) -> String {
use data_encoding::base32hex;

View File

@ -15,17 +15,24 @@
*/
//! 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;
#[cfg(feature = "openssl")]
use ::rr::{DNSClass, Name, Record, RecordType, RData};
#[cfg(feature = "openssl")]
use ::rr::dnssec::{Algorithm, DigestType, DnsSecErrorKind, DnsSecResult};
#[cfg(feature = "openssl")]
use ::rr::rdata::{DNSKEY, sig, SIG};
#[cfg(feature = "openssl")]
use ::serialize::binary::{BinEncoder, BinSerializable, EncodeMode};
/// Use for performing signing and validation of DNSSec based components.
#[cfg(feature = "openssl")]
pub struct Signer {
algorithm: Algorithm,
rsa: RSA,
@ -33,6 +40,10 @@ pub struct Signer {
sig_duration: Duration,
}
#[cfg(not(feature = "openssl"))]
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 {
@ -573,6 +584,7 @@ impl Signer {
}
#[test]
#[cfg(feature = "openssl")]
fn test_sign_and_verify_message_sig0() {
use ::rr::Name;
use ::op::{Message, Query, UpdateMessage};
@ -606,6 +618,7 @@ fn test_sign_and_verify_message_sig0() {
}
#[test]
#[cfg(feature = "openssl")]
fn test_hash_rrset() {
use ::rr::{Name, RecordType};
use ::rr::rdata::SIG;
@ -634,6 +647,7 @@ fn test_hash_rrset() {
}
#[test]
#[cfg(feature = "openssl")]
fn test_sign_and_verify_rrset() {
use ::rr::RecordType;
use ::rr::Name;
@ -655,6 +669,7 @@ fn test_sign_and_verify_rrset() {
}
#[test]
#[cfg(feature = "openssl")]
fn test_calculate_key_tag() {
let rsa = RSA::generate(512).unwrap();
println!("pkey: {:?}", rsa.public_key_to_pem().unwrap());

View File

@ -18,10 +18,13 @@
use std::default::Default;
#[cfg(feature = "openssl")]
use openssl::crypto::rsa::RSA;
#[cfg(feature = "openssl")]
use ::rr::dnssec::Algorithm;
#[cfg(feature = "openssl")]
const ROOT_ANCHOR: &'static str = include_str!("Kjqmt7v.pem");
// TODO: these should also store some information, or more specifically, metadata from the signed
@ -31,6 +34,7 @@ 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);
@ -39,6 +43,11 @@ impl Default for TrustAnchor {
TrustAnchor{ pkeys: vec![alg.public_key_to_vec(&rsa)] }
}
#[cfg(not(feature = "openssl"))]
fn default() -> TrustAnchor {
TrustAnchor{ pkeys: vec![] }
}
}
impl TrustAnchor {