diff --git a/Cargo.toml b/Cargo.toml index 14796b57..607e66db 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ with-eui48 = ["eui48"] with-openssl = ["openssl"] with-native-tls = ["native-tls"] with-rustc-serialize = ["rustc-serialize"] +with-schannel = ["schannel"] with-security-framework = ["security-framework"] with-serde_json = ["serde_json"] with-time = ["time"] @@ -47,6 +48,7 @@ eui48 = { version = "0.1", optional = true } openssl = { version = "0.9", optional = true } native-tls = { version = "0.1", optional = true } rustc-serialize = { version = "0.3", optional = true } +schannel = { version = "0.1", optional = true } security-framework = { version = "0.1.2", optional = true } serde_json = { version = ">= 0.6, < 0.9", optional = true } time = { version = "0.1.14", optional = true } diff --git a/src/lib.rs b/src/lib.rs index b0dadc1b..d8ab6a0c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,9 +43,9 @@ //! //! This crate supports TLS secured connections. The `TlsMode` enum is passed to connection methods //! and indicates if the connection will not, may, or must be secured by TLS. The TLS implementation -//! is pluggable through the `TlsHandshake` trait. Implementations for OpenSSL and OSX's Secure -//! Transport are provided behind the `with-openssl`, `with-security-framework`, and -//! `with-native-tls` feature flags respectively. +//! is pluggable through the `TlsHandshake` trait. Implementations for OpenSSL, Secure Transport, +//! SChannel, and the `native-tls` crate are provided behind the `with-openssl`, +//! `with-security-framework`, `with-schannel`, and `with-native-tls` feature flags respectively. //! //! ## Examples //! diff --git a/src/tls/mod.rs b/src/tls/mod.rs index 381976f8..86b44232 100644 --- a/src/tls/mod.rs +++ b/src/tls/mod.rs @@ -5,12 +5,14 @@ use std::error::Error; use std::io::prelude::*; use std::fmt; -#[cfg(feature = "with-openssl")] -pub mod openssl; -#[cfg(feature = "with-security-framework")] -pub mod security_framework; #[cfg(feature = "with-native-tls")] pub mod native_tls; +#[cfg(feature = "with-openssl")] +pub mod openssl; +#[cfg(feature = "with-schannel")] +pub mod schannel; +#[cfg(feature = "with-security-framework")] +pub mod security_framework; /// A trait implemented by TLS streams. pub trait TlsStream: fmt::Debug + Read + Write + Send { diff --git a/src/tls/schannel.rs b/src/tls/schannel.rs new file mode 100644 index 00000000..1a58341f --- /dev/null +++ b/src/tls/schannel.rs @@ -0,0 +1,51 @@ +//! SChannel support. + +extern crate schannel; + +use std::error::Error; +use std::fmt; + +use self::schannel::schannel_cred::{SchannelCred, Direction}; +use self::schannel::tls_stream; +use tls::{TlsStream, Stream, TlsHandshake}; + +impl TlsStream for tls_stream::TlsStream { + fn get_ref(&self) -> &Stream { + self.get_ref() + } + + fn get_mut(&mut self) -> &mut Stream { + self.get_mut() + } +} + +/// A `TlsHandshake` implementation that uses the `schannel` crate. +/// +/// Requires the `with-schannel` feature. +pub struct Schannel(()); + +impl fmt::Debug for Schannel { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("Schannel").finish() + } +} + +impl Schannel { + /// Constructs a new `SChannel` with a default configuration. + pub fn new() -> Schannel { + Schannel(()) + } +} + +impl TlsHandshake for Schannel { + fn tls_handshake(&self, + host: &str, + stream: Stream) + -> Result, Box> { + let creds = try!(SchannelCred::builder().acquire(Direction::Outbound)); + let stream = try!(tls_stream::Builder::new() + .domain(host) + .connect(creds, stream)); + Ok(Box::new(stream)) + } +}