libp2p_websocket/
tls.rs

1// Copyright 2019 Parity Technologies (UK) Ltd.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the "Software"),
5// to deal in the Software without restriction, including without limitation
6// the rights to use, copy, modify, merge, publish, distribute, sublicense,
7// and/or sell copies of the Software, and to permit persons to whom the
8// Software is furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19// DEALINGS IN THE SOFTWARE.
20
21use futures_rustls::{rustls, webpki, TlsConnector, TlsAcceptor};
22use std::{fmt, io, sync::Arc};
23
24/// TLS configuration.
25#[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/// Private key, DER-encoded ASN.1 in either PKCS#8 or PKCS#1 format.
38#[derive(Clone)]
39pub struct PrivateKey(rustls::PrivateKey);
40
41impl PrivateKey {
42    /// Assert the given bytes are DER-encoded ASN.1 in either PKCS#8 or PKCS#1 format.
43    pub fn new(bytes: Vec<u8>) -> Self {
44        PrivateKey(rustls::PrivateKey(bytes))
45    }
46}
47
48/// Certificate, DER-encoded X.509 format.
49#[derive(Debug, Clone)]
50pub struct Certificate(rustls::Certificate);
51
52impl Certificate {
53    /// Assert the given bytes are in DER-encoded X.509 format.
54    pub fn new(bytes: Vec<u8>) -> Self {
55        Certificate(rustls::Certificate(bytes))
56    }
57}
58
59impl Config {
60    /// Create a new TLS configuration with the given server key and certificate chain.
61    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    /// Create a client-only configuration.
71    pub fn client() -> Self {
72        Config {
73            client: Arc::new(client_config()).into(),
74            server: None
75        }
76    }
77
78    /// Create a new TLS configuration builder.
79    pub fn builder() -> Builder {
80        Builder { client: client_config(), server: None }
81    }
82}
83
84/// Setup the rustls client configuration.
85fn 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
91/// TLS configuration builder.
92pub struct Builder {
93    client: rustls::ClientConfig,
94    server: Option<rustls::ServerConfig>
95}
96
97impl Builder {
98    /// Set server key and certificate chain.
99    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    /// Add an additional trust anchor.
111    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    /// Finish configuration.
117    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// Error //////////////////////////////////////////////////////////////////////////////////////////
130
131/// TLS related errors.
132#[derive(Debug)]
133#[non_exhaustive]
134pub enum Error {
135    /// An underlying I/O error.
136    Io(io::Error),
137    /// Actual TLS error.
138    Tls(Box<dyn std::error::Error + Send + Sync>),
139    /// The DNS name was invalid.
140    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}