1use futures_rustls::{rustls, TlsAcceptor, TlsConnector};
22use std::convert::TryFrom;
23use std::{fmt, io, sync::Arc};
24
25#[derive(Clone)]
27pub struct Config {
28 pub(crate) client: TlsConnector,
29 pub(crate) server: Option<TlsAcceptor>,
30}
31
32impl fmt::Debug for Config {
33 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34 f.write_str("Config")
35 }
36}
37
38#[derive(Clone)]
40pub struct PrivateKey(rustls::PrivateKey);
41
42impl PrivateKey {
43 pub fn new(bytes: Vec<u8>) -> Self {
45 PrivateKey(rustls::PrivateKey(bytes))
46 }
47}
48
49#[derive(Debug, Clone)]
51pub struct Certificate(rustls::Certificate);
52
53impl Certificate {
54 pub fn new(bytes: Vec<u8>) -> Self {
56 Certificate(rustls::Certificate(bytes))
57 }
58}
59
60impl Config {
61 pub fn new<I>(key: PrivateKey, certs: I) -> Result<Self, Error>
63 where
64 I: IntoIterator<Item = Certificate>,
65 {
66 let mut builder = Config::builder();
67 builder.server(key, certs)?;
68 Ok(builder.finish())
69 }
70
71 pub fn client() -> Self {
73 let client = rustls::ClientConfig::builder()
74 .with_safe_defaults()
75 .with_root_certificates(client_root_store())
76 .with_no_client_auth();
77 Config {
78 client: Arc::new(client).into(),
79 server: None,
80 }
81 }
82
83 pub fn builder() -> Builder {
85 Builder {
86 client_root_store: client_root_store(),
87 server: None,
88 }
89 }
90}
91
92fn client_root_store() -> rustls::RootCertStore {
94 let mut client_root_store = rustls::RootCertStore::empty();
95 client_root_store.add_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.iter().map(|ta| {
96 rustls::OwnedTrustAnchor::from_subject_spki_name_constraints(
97 ta.subject,
98 ta.spki,
99 ta.name_constraints,
100 )
101 }));
102 client_root_store
103}
104
105pub struct Builder {
107 client_root_store: rustls::RootCertStore,
108 server: Option<rustls::ServerConfig>,
109}
110
111impl Builder {
112 pub fn server<I>(&mut self, key: PrivateKey, certs: I) -> Result<&mut Self, Error>
114 where
115 I: IntoIterator<Item = Certificate>,
116 {
117 let certs = certs.into_iter().map(|c| c.0).collect();
118 let server = rustls::ServerConfig::builder()
119 .with_safe_defaults()
120 .with_no_client_auth()
121 .with_single_cert(certs, key.0)
122 .map_err(|e| Error::Tls(Box::new(e)))?;
123 self.server = Some(server);
124 Ok(self)
125 }
126
127 pub fn add_trust(&mut self, cert: &Certificate) -> Result<&mut Self, Error> {
129 self.client_root_store
130 .add(&cert.0)
131 .map_err(|e| Error::Tls(Box::new(e)))?;
132 Ok(self)
133 }
134
135 pub fn finish(self) -> Config {
137 let client = rustls::ClientConfig::builder()
138 .with_safe_defaults()
139 .with_root_certificates(self.client_root_store)
140 .with_no_client_auth();
141
142 Config {
143 client: Arc::new(client).into(),
144 server: self.server.map(|s| Arc::new(s).into()),
145 }
146 }
147}
148
149pub(crate) fn dns_name_ref(name: &str) -> Result<rustls::ServerName, Error> {
150 rustls::ServerName::try_from(name).map_err(|_| Error::InvalidDnsName(name.into()))
151}
152
153#[derive(Debug)]
157#[non_exhaustive]
158pub enum Error {
159 Io(io::Error),
161 Tls(Box<dyn std::error::Error + Send + Sync>),
163 InvalidDnsName(String),
165}
166
167impl fmt::Display for Error {
168 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
169 match self {
170 Error::Io(e) => write!(f, "i/o error: {e}"),
171 Error::Tls(e) => write!(f, "tls error: {e}"),
172 Error::InvalidDnsName(n) => write!(f, "invalid DNS name: {n}"),
173 }
174 }
175}
176
177impl std::error::Error for Error {
178 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
179 match self {
180 Error::Io(e) => Some(e),
181 Error::Tls(e) => Some(&**e),
182 Error::InvalidDnsName(_) => None,
183 }
184 }
185}
186
187impl From<io::Error> for Error {
188 fn from(e: io::Error) -> Self {
189 Error::Io(e)
190 }
191}