#![doc(html_root_url="https://docs.rs/native-tls/0.1.4")]
#![warn(missing_docs)]
use std::any::Any;
use std::error;
use std::error::Error as StdError;
use std::io;
use std::fmt;
use std::result;
pub mod backend;
#[cfg(target_os = "macos")]
#[path = "imp/security_framework.rs"]
mod imp;
#[cfg(target_os = "windows")]
#[path = "imp/schannel.rs"]
mod imp;
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
#[path = "imp/openssl.rs"]
mod imp;
#[cfg(test)]
mod test;
pub type Result<T> = result::Result<T, Error>;
pub struct Error(imp::Error);
impl error::Error for Error {
fn description(&self) -> &str {
error::Error::description(&self.0)
}
fn cause(&self) -> Option<&error::Error> {
error::Error::cause(&self.0)
}
}
impl fmt::Display for Error {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.0, fmt)
}
}
impl fmt::Debug for Error {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&self.0, fmt)
}
}
impl<T: Into<imp::Error>> From<T> for Error {
fn from(err: T) -> Error {
Error(err.into())
}
}
pub struct Pkcs12(imp::Pkcs12);
impl Pkcs12 {
pub fn from_der(der: &[u8], password: &str) -> Result<Pkcs12> {
let pkcs12 = try!(imp::Pkcs12::from_der(der, password));
Ok(Pkcs12(pkcs12))
}
}
pub struct Certificate(imp::Certificate);
impl Certificate {
pub fn from_der(der: &[u8]) -> Result<Certificate> {
let cert = try!(imp::Certificate::from_der(der));
Ok(Certificate(cert))
}
}
pub struct MidHandshakeTlsStream<S>(imp::MidHandshakeTlsStream<S>);
impl<S> fmt::Debug for MidHandshakeTlsStream<S>
where
S: fmt::Debug,
{
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&self.0, fmt)
}
}
impl<S> MidHandshakeTlsStream<S>
where
S: io::Read + io::Write,
{
pub fn get_ref(&self) -> &S {
self.0.get_ref()
}
pub fn get_mut(&mut self) -> &mut S {
self.0.get_mut()
}
pub fn handshake(self) -> result::Result<TlsStream<S>, HandshakeError<S>> {
match self.0.handshake() {
Ok(s) => Ok(TlsStream(s)),
Err(e) => Err(e.into()),
}
}
}
#[derive(Debug)]
pub enum HandshakeError<S> {
Failure(Error),
Interrupted(MidHandshakeTlsStream<S>),
}
impl<S> error::Error for HandshakeError<S>
where
S: Any + fmt::Debug,
{
fn description(&self) -> &str {
match *self {
HandshakeError::Failure(ref e) => e.description(),
HandshakeError::Interrupted(_) => "the handshake process was interrupted",
}
}
fn cause(&self) -> Option<&error::Error> {
match *self {
HandshakeError::Failure(ref e) => Some(e),
HandshakeError::Interrupted(_) => None,
}
}
}
impl<S> fmt::Display for HandshakeError<S>
where
S: Any + fmt::Debug,
{
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
try!(fmt.write_str(self.description()));
if let Some(cause) = self.cause() {
try!(write!(fmt, ": {}", cause));
}
Ok(())
}
}
impl<S> From<imp::HandshakeError<S>> for HandshakeError<S> {
fn from(e: imp::HandshakeError<S>) -> HandshakeError<S> {
match e {
imp::HandshakeError::Failure(e) => HandshakeError::Failure(Error(e)),
imp::HandshakeError::Interrupted(s) => {
HandshakeError::Interrupted(MidHandshakeTlsStream(s))
}
}
}
}
#[derive(Debug, Copy, Clone)]
pub enum Protocol {
Sslv3,
Tlsv10,
Tlsv11,
Tlsv12,
#[doc(hidden)]
__NonExhaustive,
}
pub struct TlsConnectorBuilder(imp::TlsConnectorBuilder);
impl TlsConnectorBuilder {
pub fn identity(&mut self, pkcs12: Pkcs12) -> Result<&mut TlsConnectorBuilder> {
try!(self.0.identity(pkcs12.0));
Ok(self)
}
pub fn supported_protocols(
&mut self,
protocols: &[Protocol],
) -> Result<&mut TlsConnectorBuilder> {
try!(self.0.supported_protocols(protocols));
Ok(self)
}
pub fn add_root_certificate(&mut self, cert: Certificate) -> Result<&mut TlsConnectorBuilder> {
try!(self.0.add_root_certificate(cert.0));
Ok(self)
}
pub fn build(self) -> Result<TlsConnector> {
let connector = try!(self.0.build());
Ok(TlsConnector(connector))
}
}
#[derive(Clone)]
pub struct TlsConnector(imp::TlsConnector);
impl TlsConnector {
pub fn builder() -> Result<TlsConnectorBuilder> {
let builder = try!(imp::TlsConnector::builder());
Ok(TlsConnectorBuilder(builder))
}
pub fn connect<S>(
&self,
domain: &str,
stream: S,
) -> result::Result<TlsStream<S>, HandshakeError<S>>
where
S: io::Read + io::Write,
{
let s = try!(self.0.connect(domain, stream));
Ok(TlsStream(s))
}
pub fn danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication<S>(
&self, stream: S) -> result::Result<TlsStream<S>, HandshakeError<S>>
where S: io::Read + io::Write
{
let s = try!(self.0.connect_no_domain(stream));
Ok(TlsStream(s))
}
}
pub struct TlsAcceptorBuilder(imp::TlsAcceptorBuilder);
impl TlsAcceptorBuilder {
pub fn supported_protocols(
&mut self,
protocols: &[Protocol],
) -> Result<&mut TlsAcceptorBuilder> {
try!(self.0.supported_protocols(protocols));
Ok(self)
}
pub fn build(self) -> Result<TlsAcceptor> {
let acceptor = try!(self.0.build());
Ok(TlsAcceptor(acceptor))
}
}
#[derive(Clone)]
pub struct TlsAcceptor(imp::TlsAcceptor);
impl TlsAcceptor {
pub fn builder(pkcs12: Pkcs12) -> Result<TlsAcceptorBuilder> {
let builder = try!(imp::TlsAcceptor::builder(pkcs12.0));
Ok(TlsAcceptorBuilder(builder))
}
pub fn accept<S>(&self, stream: S) -> result::Result<TlsStream<S>, HandshakeError<S>>
where
S: io::Read + io::Write,
{
match self.0.accept(stream) {
Ok(s) => Ok(TlsStream(s)),
Err(e) => Err(e.into()),
}
}
}
pub struct TlsStream<S>(imp::TlsStream<S>);
impl<S: fmt::Debug> fmt::Debug for TlsStream<S> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&self.0, fmt)
}
}
impl<S: io::Read + io::Write> TlsStream<S> {
pub fn get_ref(&self) -> &S {
self.0.get_ref()
}
pub fn get_mut(&mut self) -> &mut S {
self.0.get_mut()
}
pub fn buffered_read_size(&self) -> Result<usize> {
Ok(try!(self.0.buffered_read_size()))
}
pub fn shutdown(&mut self) -> io::Result<()> {
try!(self.0.shutdown());
Ok(())
}
}
impl<S: io::Read + io::Write> io::Read for TlsStream<S> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf)
}
}
impl<S: io::Read + io::Write> io::Write for TlsStream<S> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.0.flush()
}
}
fn _check_kinds() {
use std::net::TcpStream;
fn is_sync<T: Sync>() {}
fn is_send<T: Send>() {}
is_sync::<Error>();
is_send::<Error>();
is_sync::<TlsConnectorBuilder>();
is_send::<TlsConnectorBuilder>();
is_sync::<TlsConnector>();
is_send::<TlsConnector>();
is_sync::<TlsAcceptorBuilder>();
is_send::<TlsAcceptorBuilder>();
is_sync::<TlsAcceptor>();
is_send::<TlsAcceptor>();
is_sync::<TlsStream<TcpStream>>();
is_send::<TlsStream<TcpStream>>();
is_sync::<MidHandshakeTlsStream<TcpStream>>();
is_send::<MidHandshakeTlsStream<TcpStream>>();
}