1 // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 // SPDX-License-Identifier: Apache-2.0
3 
4 use crate::raw::{
5     error::{Error, Fallible},
6     security,
7 };
8 use alloc::sync::Arc;
9 use core::{convert::TryInto, ptr::NonNull};
10 use s2n_tls_sys::*;
11 use std::ffi::CString;
12 
13 struct Owned(NonNull<s2n_config>);
14 
15 impl Default for Owned {
default() -> Self16     fn default() -> Self {
17         Self::new()
18     }
19 }
20 
21 impl Owned {
new() -> Self22     fn new() -> Self {
23         crate::raw::init::init();
24         let config = unsafe { s2n_config_new().into_result() }.unwrap();
25         Self(config)
26     }
27 
as_mut_ptr(&mut self) -> *mut s2n_config28     pub(crate) fn as_mut_ptr(&mut self) -> *mut s2n_config {
29         self.0.as_ptr()
30     }
31 }
32 
33 impl Drop for Owned {
drop(&mut self)34     fn drop(&mut self) {
35         let _ = unsafe { s2n_config_free(self.0.as_ptr()).into_result() };
36     }
37 }
38 
39 /// Safety: s2n_config objects can be sent across threads
40 unsafe impl Send for Owned {}
41 
42 #[derive(Clone, Default)]
43 pub struct Config(Arc<Owned>);
44 
45 impl Config {
new() -> Self46     pub fn new() -> Self {
47         Self::default()
48     }
49 
builder() -> Builder50     pub fn builder() -> Builder {
51         Builder::default()
52     }
53 
as_mut_ptr(&mut self) -> *mut s2n_config54     pub(crate) fn as_mut_ptr(&mut self) -> *mut s2n_config {
55         (self.0).0.as_ptr()
56     }
57 }
58 
59 #[derive(Default)]
60 pub struct Builder(Owned);
61 
62 impl Builder {
new() -> Self63     pub fn new() -> Self {
64         Default::default()
65     }
66 
set_alert_behavior( &mut self, value: s2n_alert_behavior::Type, ) -> Result<&mut Self, Error>67     pub fn set_alert_behavior(
68         &mut self,
69         value: s2n_alert_behavior::Type,
70     ) -> Result<&mut Self, Error> {
71         unsafe { s2n_config_set_alert_behavior(self.as_mut_ptr(), value).into_result() }?;
72         Ok(self)
73     }
74 
set_security_policy(&mut self, policy: &security::Policy) -> Result<&mut Self, Error>75     pub fn set_security_policy(&mut self, policy: &security::Policy) -> Result<&mut Self, Error> {
76         unsafe {
77             s2n_config_set_cipher_preferences(self.as_mut_ptr(), policy.as_cstr().as_ptr())
78                 .into_result()
79         }?;
80         Ok(self)
81     }
82 
83     /// sets the application protocol preferences on an s2n_config object.
84     ///
85     /// protocols is a list in order of preference, with most preferred protocol first,
86     /// and of length protocol_count. When acting as an S2N_CLIENT the protocol list is
87     /// included in the Client Hello message as the ALPN extension. As an S2N_SERVER, the
88     /// list is used to negotiate a mutual application protocol with the client. After
89     /// the negotiation for the connection has completed, the agreed upon protocol can
90     /// be retrieved with s2n_get_application_protocol
set_alpn_preference<P: IntoIterator<Item = I>, I: AsRef<[u8]>>( &mut self, protocols: P, ) -> Result<&mut Self, Error>91     pub fn set_alpn_preference<P: IntoIterator<Item = I>, I: AsRef<[u8]>>(
92         &mut self,
93         protocols: P,
94     ) -> Result<&mut Self, Error> {
95         // reset the list
96         unsafe {
97             s2n_config_set_protocol_preferences(self.as_mut_ptr(), core::ptr::null(), 0)
98                 .into_result()
99         }?;
100 
101         for protocol in protocols {
102             self.append_alpn_preference(protocol.as_ref())?;
103         }
104 
105         Ok(self)
106     }
107 
108     /// Turns off x509 verification
109     ///
110     /// # Safety
111     /// This functionality will weaken the security of the connections. As such, it should only
112     /// be used in development environments where obtaining a valid certificate would not be possible.
disable_x509_verification(&mut self) -> Result<&mut Self, Error>113     pub unsafe fn disable_x509_verification(&mut self) -> Result<&mut Self, Error> {
114         s2n_config_disable_x509_verification(self.as_mut_ptr()).into_result()?;
115         Ok(self)
116     }
117 
load_pem(&mut self, certificate: &[u8], private_key: &[u8]) -> Result<&mut Self, Error>118     pub fn load_pem(&mut self, certificate: &[u8], private_key: &[u8]) -> Result<&mut Self, Error> {
119         let certificate = CString::new(certificate).map_err(|_| Error::InvalidInput)?;
120         let private_key = CString::new(private_key).map_err(|_| Error::InvalidInput)?;
121         unsafe {
122             s2n_config_add_cert_chain_and_key(
123                 self.as_mut_ptr(),
124                 certificate.as_ptr(),
125                 private_key.as_ptr(),
126             )
127             .into_result()
128         }?;
129         Ok(self)
130     }
131 
trust_pem(&mut self, certificate: &[u8]) -> Result<&mut Self, Error>132     pub fn trust_pem(&mut self, certificate: &[u8]) -> Result<&mut Self, Error> {
133         let certificate = CString::new(certificate).map_err(|_| Error::InvalidInput)?;
134         unsafe {
135             s2n_config_add_pem_to_trust_store(self.as_mut_ptr(), certificate.as_ptr()).into_result()
136         }?;
137         Ok(self)
138     }
139 
append_alpn_preference(&mut self, protocol: &[u8]) -> Result<&mut Self, Error>140     pub fn append_alpn_preference(&mut self, protocol: &[u8]) -> Result<&mut Self, Error> {
141         unsafe {
142             s2n_config_append_protocol_preference(
143                 self.as_mut_ptr(),
144                 protocol.as_ptr(),
145                 protocol.len().try_into().map_err(|_| Error::InvalidInput)?,
146             )
147             .into_result()
148         }?;
149         Ok(self)
150     }
151 
152     /// # Safety
153     ///
154     /// The `context` pointer must live at least as long as the config
set_verify_host_callback( &mut self, callback: s2n_verify_host_fn, context: *mut core::ffi::c_void, ) -> Result<&mut Self, Error>155     pub unsafe fn set_verify_host_callback(
156         &mut self,
157         callback: s2n_verify_host_fn,
158         context: *mut core::ffi::c_void,
159     ) -> Result<&mut Self, Error> {
160         s2n_config_set_verify_host_callback(self.as_mut_ptr(), callback, context).into_result()?;
161         Ok(self)
162     }
163 
164     /// # Safety
165     ///
166     /// The `context` pointer must live at least as long as the config
set_key_log_callback( &mut self, callback: s2n_key_log_fn, context: *mut core::ffi::c_void, ) -> Result<&mut Self, Error>167     pub unsafe fn set_key_log_callback(
168         &mut self,
169         callback: s2n_key_log_fn,
170         context: *mut core::ffi::c_void,
171     ) -> Result<&mut Self, Error> {
172         s2n_config_set_key_log_cb(self.as_mut_ptr(), callback, context).into_result()?;
173         Ok(self)
174     }
175 
build(self) -> Result<Config, Error>176     pub fn build(self) -> Result<Config, Error> {
177         Ok(Config(Arc::new(self.0)))
178     }
179 
as_mut_ptr(&mut self) -> *mut s2n_config180     fn as_mut_ptr(&mut self) -> *mut s2n_config {
181         self.0.as_mut_ptr()
182     }
183 }
184 
185 #[cfg(feature = "quic")]
186 impl Builder {
enable_quic(&mut self) -> Result<&mut Self, Error>187     pub fn enable_quic(&mut self) -> Result<&mut Self, Error> {
188         unsafe { s2n_tls_sys::s2n_config_enable_quic(self.as_mut_ptr()).into_result() }?;
189         Ok(self)
190     }
191 }
192