s2n_quic_tls/
server.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::{
5    certificate::{Format, IntoCertificate, IntoPrivateKey},
6    keylog::KeyLogHandle,
7    params::Params,
8    session::Session,
9    ConfigLoader,
10};
11use s2n_codec::EncoderValue;
12use s2n_quic_core::{application::ServerName, crypto::tls, endpoint};
13#[cfg(any(test, feature = "unstable_client_hello"))]
14use s2n_tls::callbacks::ClientHelloCallback;
15#[cfg(any(test, feature = "unstable_private_key"))]
16use s2n_tls::callbacks::PrivateKeyCallback;
17use s2n_tls::{
18    callbacks::VerifyHostNameCallback,
19    config::{self, Config},
20    enums::ClientAuthType,
21    error::Error,
22};
23use std::sync::Arc;
24
25pub struct Server<L: ConfigLoader = Config> {
26    loader: L,
27    #[allow(dead_code)] // we need to hold on to the handle to ensure it is cleaned up correctly
28    keylog: Option<KeyLogHandle>,
29    params: Params,
30}
31
32impl Server {
33    pub fn builder() -> Builder {
34        Builder::default()
35    }
36}
37
38impl<L: ConfigLoader> Server<L> {
39    /// Creates a [`Server`] from a [`ConfigLoader`]
40    ///
41    /// The caller is responsible for building the `Config`
42    /// correctly for QUIC settings. This includes:
43    /// * setting a security policy that supports TLS 1.3
44    /// * enabling QUIC support
45    /// * setting at least one application protocol
46    pub fn from_loader(loader: L) -> Self {
47        Self {
48            loader,
49            keylog: None,
50            params: Default::default(),
51        }
52    }
53}
54
55impl Default for Server {
56    fn default() -> Self {
57        Self::builder()
58            .build()
59            .expect("could not create a default server")
60    }
61}
62
63impl<L: ConfigLoader> ConfigLoader for Server<L> {
64    #[inline]
65    fn load(&mut self, cx: crate::ConnectionContext) -> s2n_tls::config::Config {
66        self.loader.load(cx)
67    }
68}
69
70impl<L: ConfigLoader> From<Server<L>> for Config {
71    fn from(mut server: Server<L>) -> Self {
72        server.load(crate::ConnectionContext { server_name: None })
73    }
74}
75
76pub struct Builder {
77    config: config::Builder,
78    keylog: Option<KeyLogHandle>,
79}
80
81impl Default for Builder {
82    fn default() -> Self {
83        let mut config = config::Builder::default();
84        config.enable_quic().unwrap();
85        // https://github.com/aws/s2n-tls/blob/main/docs/USAGE-GUIDE.md#s2n_config_set_cipher_preferences
86        config.set_security_policy(crate::DEFAULT_POLICY).unwrap();
87        config.set_application_protocol_preference([b"h3"]).unwrap();
88
89        Self {
90            config,
91            keylog: None,
92        }
93    }
94}
95
96impl Builder {
97    pub fn config_mut(&mut self) -> &mut s2n_tls::config::Builder {
98        &mut self.config
99    }
100
101    #[cfg(any(test, feature = "unstable_client_hello"))]
102    pub fn with_client_hello_handler<T: 'static + ClientHelloCallback>(
103        mut self,
104        handler: T,
105    ) -> Result<Self, Error> {
106        self.config.set_client_hello_callback(handler)?;
107        Ok(self)
108    }
109
110    #[cfg(any(test, feature = "unstable_private_key"))]
111    pub fn with_private_key_handler<T: 'static + PrivateKeyCallback>(
112        mut self,
113        handler: T,
114    ) -> Result<Self, Error> {
115        self.config.set_private_key_callback(handler)?;
116        Ok(self)
117    }
118
119    pub fn with_application_protocols<P: IntoIterator<Item = I>, I: AsRef<[u8]>>(
120        mut self,
121        protocols: P,
122    ) -> Result<Self, Error> {
123        self.config.set_application_protocol_preference(protocols)?;
124        Ok(self)
125    }
126
127    pub fn with_certificate<C: IntoCertificate, PK: IntoPrivateKey>(
128        mut self,
129        certificate: C,
130        private_key: PK,
131    ) -> Result<Self, Error> {
132        let private_key = private_key.into_private_key()?.0;
133        let certificate = certificate.into_certificate()?.0;
134        let certificate = certificate
135            .as_pem()
136            .expect("pem is currently the only certificate format supported");
137        match private_key {
138            Format::Pem(bytes) => self.config.load_pem(certificate, bytes.as_ref())?,
139            Format::None => self.config.load_public_pem(certificate)?,
140            Format::Der(_) => panic!("der private keys not supported"),
141        };
142        Ok(self)
143    }
144
145    pub fn with_trusted_certificate<C: IntoCertificate>(
146        mut self,
147        certificate: C,
148    ) -> Result<Self, Error> {
149        let certificate = certificate.into_certificate()?;
150        let certificate = certificate
151            .0
152            .as_pem()
153            .expect("pem is currently the only certificate format supported");
154        self.config.trust_pem(certificate)?;
155        Ok(self)
156    }
157
158    /// Clears the default trust store for this client.
159    ///
160    /// By default, the trust store is initialized with common
161    /// trust store locations for the host operating system.
162    /// By invoking this method, the trust store will be cleared.
163    ///
164    /// Note that call ordering matters. The caller should call this
165    /// method before making any calls to `with_trusted_certificate()`.
166    /// Calling this method after a method that modifies the trust store will clear it.
167    pub fn with_empty_trust_store(mut self) -> Result<Self, Error> {
168        self.config.wipe_trust_store()?;
169        Ok(self)
170    }
171
172    /// Configures this server instance to require client authentication (mutual TLS).
173    pub fn with_client_authentication(mut self) -> Result<Self, Error> {
174        self.config.set_client_auth_type(ClientAuthType::Required)?;
175        Ok(self)
176    }
177
178    /// Set the application level certificate verification handler which will be invoked on this
179    /// server instance when a client certificate is presented during the mutual TLS handshake.
180    #[deprecated(note = "use `with_verify_host_name_callback` instead")]
181    pub fn with_verify_client_certificate_handler<T: 'static + VerifyHostNameCallback>(
182        mut self,
183        handler: T,
184    ) -> Result<Self, Error> {
185        self.config.set_verify_host_callback(handler)?;
186        Ok(self)
187    }
188
189    /// Set the host name verification callback.
190    ///
191    /// This will be invoked when a client certificate is presented during a mutual TLS
192    /// handshake.
193    pub fn with_verify_host_name_callback<T: 'static + VerifyHostNameCallback>(
194        mut self,
195        handler: T,
196    ) -> Result<Self, Error> {
197        self.config.set_verify_host_callback(handler)?;
198        Ok(self)
199    }
200
201    pub fn with_key_logging(mut self) -> Result<Self, Error> {
202        use crate::keylog::KeyLog;
203
204        self.keylog = KeyLog::try_open();
205
206        unsafe {
207            // Safety: the KeyLog is stored on `self` to ensure it outlives `config`
208            if let Some(keylog) = self.keylog.as_ref() {
209                self.config
210                    .set_key_log_callback(Some(KeyLog::callback), Arc::as_ptr(keylog) as *mut _)?;
211            } else {
212                // disable key logging if it failed to create a file
213                self.config
214                    .set_key_log_callback(None, core::ptr::null_mut())?;
215            }
216        }
217
218        Ok(self)
219    }
220
221    pub fn build(self) -> Result<Server, Error> {
222        #[cfg(feature = "fips")]
223        assert!(s2n_tls::init::fips_mode()?.is_enabled());
224
225        Ok(Server {
226            loader: self.config.build()?,
227            keylog: self.keylog,
228            params: Default::default(),
229        })
230    }
231}
232
233impl<L: ConfigLoader> tls::Endpoint for Server<L> {
234    type Session = Session;
235
236    fn new_server_session<Params: EncoderValue>(&mut self, params: &Params) -> Self::Session {
237        let config = self
238            .loader
239            .load(crate::ConnectionContext { server_name: None });
240        self.params.with(params, |params| {
241            Session::new(endpoint::Type::Server, config, params, None).unwrap()
242        })
243    }
244
245    fn new_client_session<Params: EncoderValue>(
246        &mut self,
247        _transport_parameters: &Params,
248        _erver_name: ServerName,
249    ) -> Self::Session {
250        panic!("cannot create a client session from a server config");
251    }
252
253    fn max_tag_length(&self) -> usize {
254        s2n_quic_crypto::MAX_TAG_LEN
255    }
256}