1use futures_rustls::{rustls, webpki, TlsConnector, TlsAcceptor};
22use std::{fmt, io, sync::Arc};
23
24#[derive(Clone)]
26pub struct Config {
27 pub(crate) client: TlsConnector,
28 pub(crate) server: Option<TlsAcceptor>
29}
30
31impl fmt::Debug for Config {
32 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33 f.write_str("Config")
34 }
35}
36
37#[derive(Clone)]
39pub struct PrivateKey(rustls::PrivateKey);
40
41impl PrivateKey {
42 pub fn new(bytes: Vec<u8>) -> Self {
44 PrivateKey(rustls::PrivateKey(bytes))
45 }
46}
47
48#[derive(Debug, Clone)]
50pub struct Certificate(rustls::Certificate);
51
52impl Certificate {
53 pub fn new(bytes: Vec<u8>) -> Self {
55 Certificate(rustls::Certificate(bytes))
56 }
57}
58
59impl Config {
60 pub fn new<I>(key: PrivateKey, certs: I) -> Result<Self, Error>
62 where
63 I: IntoIterator<Item = Certificate>
64 {
65 let mut builder = Config::builder();
66 builder.server(key, certs)?;
67 Ok(builder.finish())
68 }
69
70 pub fn client() -> Self {
72 Config {
73 client: Arc::new(client_config()).into(),
74 server: None
75 }
76 }
77
78 pub fn builder() -> Builder {
80 Builder { client: client_config(), server: None }
81 }
82}
83
84fn client_config() -> rustls::ClientConfig {
86 let mut client = rustls::ClientConfig::new();
87 client.root_store.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
88 client
89}
90
91pub struct Builder {
93 client: rustls::ClientConfig,
94 server: Option<rustls::ServerConfig>
95}
96
97impl Builder {
98 pub fn server<I>(&mut self, key: PrivateKey, certs: I) -> Result<&mut Self, Error>
100 where
101 I: IntoIterator<Item = Certificate>
102 {
103 let mut server = rustls::ServerConfig::new(rustls::NoClientAuth::new());
104 let certs = certs.into_iter().map(|c| c.0).collect();
105 server.set_single_cert(certs, key.0).map_err(|e| Error::Tls(Box::new(e)))?;
106 self.server = Some(server);
107 Ok(self)
108 }
109
110 pub fn add_trust(&mut self, cert: &Certificate) -> Result<&mut Self, Error> {
112 self.client.root_store.add(&cert.0).map_err(|e| Error::Tls(Box::new(e)))?;
113 Ok(self)
114 }
115
116 pub fn finish(self) -> Config {
118 Config {
119 client: Arc::new(self.client).into(),
120 server: self.server.map(|s| Arc::new(s).into())
121 }
122 }
123}
124
125pub(crate) fn dns_name_ref(name: &str) -> Result<webpki::DNSNameRef<'_>, Error> {
126 webpki::DNSNameRef::try_from_ascii_str(name).map_err(|_| Error::InvalidDnsName(name.into()))
127}
128
129#[derive(Debug)]
133#[non_exhaustive]
134pub enum Error {
135 Io(io::Error),
137 Tls(Box<dyn std::error::Error + Send + Sync>),
139 InvalidDnsName(String),
141}
142
143impl fmt::Display for Error {
144 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
145 match self {
146 Error::Io(e) => write!(f, "i/o error: {}", e),
147 Error::Tls(e) => write!(f, "tls error: {}", e),
148 Error::InvalidDnsName(n) => write!(f, "invalid DNS name: {}", n),
149 }
150 }
151}
152
153impl std::error::Error for Error {
154 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
155 match self {
156 Error::Io(e) => Some(e),
157 Error::Tls(e) => Some(&**e),
158 Error::InvalidDnsName(_) => None
159 }
160 }
161}
162
163impl From<io::Error> for Error {
164 fn from(e: io::Error) -> Self {
165 Error::Io(e)
166 }
167}