s2n_quic_rustls/
client.rs1use crate::{certificate, cipher_suite::default_crypto_provider, session::Session, Error};
5use core::convert::TryFrom;
6use rustls::{ClientConfig, ConfigBuilder, WantsVerifier};
7use s2n_codec::EncoderValue;
8use s2n_quic_core::{application::ServerName, crypto::tls};
9use std::sync::Arc;
10
11fn default_config_builder() -> Result<ConfigBuilder<ClientConfig, WantsVerifier>, rustls::Error> {
15 let tls13_cipher_suite_crypto_provider = default_crypto_provider()?;
16 ClientConfig::builder_with_provider(tls13_cipher_suite_crypto_provider.into())
17 .with_protocol_versions(crate::PROTOCOL_VERSIONS)
18}
19
20#[derive(Clone)]
21pub struct Client {
22 config: Arc<ClientConfig>,
23}
24
25impl Client {
26 #[deprecated = "client and server builders should be used instead"]
34 pub fn new(config: ClientConfig) -> Self {
35 Self {
36 config: Arc::new(config),
37 }
38 }
39
40 pub fn builder() -> Builder {
41 Builder::new()
42 }
43}
44
45impl Default for Client {
46 fn default() -> Self {
47 Self::builder()
49 .build()
50 .expect("could not create default client")
51 }
52}
53
54impl From<ClientConfig> for Client {
56 fn from(config: ClientConfig) -> Self {
57 Self::from(Arc::new(config))
58 }
59}
60
61impl From<Arc<ClientConfig>> for Client {
63 fn from(config: Arc<ClientConfig>) -> Self {
64 Self { config }
65 }
66}
67
68impl tls::Endpoint for Client {
69 type Session = Session;
70
71 fn new_server_session<Params: EncoderValue>(
72 &mut self,
73 _transport_parameters: &Params,
74 _connection_info: tls::ConnectionInfo,
75 ) -> Self::Session {
76 panic!("cannot create a server session from a client config");
77 }
78
79 fn new_client_session<Params: EncoderValue>(
80 &mut self,
81 transport_parameters: &Params,
82 server_name: ServerName,
83 ) -> Self::Session {
84 let transport_parameters = transport_parameters.encode_to_vec();
87
88 let rustls_server_name = rustls::pki_types::ServerName::try_from(server_name.to_string())
89 .expect("invalid server name");
90
91 let session = rustls::quic::ClientConnection::new(
92 self.config.clone(),
93 crate::QUIC_VERSION,
94 rustls_server_name,
95 transport_parameters,
96 )
97 .expect("could not create rustls client session");
98
99 Session::new(session.into(), Some(server_name))
100 }
101
102 fn max_tag_length(&self) -> usize {
103 s2n_quic_crypto::MAX_TAG_LEN
104 }
105}
106
107pub struct Builder {
108 cert_store: rustls::RootCertStore,
109 application_protocols: Vec<Vec<u8>>,
110 key_log: Option<Arc<dyn rustls::KeyLog>>,
111}
112
113impl Default for Builder {
114 fn default() -> Self {
115 Self::new()
116 }
117}
118
119impl Builder {
120 pub fn new() -> Self {
121 Self {
122 cert_store: rustls::RootCertStore::empty(),
123 application_protocols: vec![b"h3".to_vec()],
124 key_log: None,
125 }
126 }
127
128 pub fn with_certificate<C: certificate::IntoCertificate>(
129 mut self,
130 certificate: C,
131 ) -> Result<Self, Error> {
132 let certificates = certificate.into_certificate()?;
133 let root_certificate = certificates.0.first().ok_or_else(|| {
134 rustls::Error::General("Certificate chain needs to have at least one entry".to_string())
135 })?;
136 self.cert_store
137 .add(root_certificate.to_owned())
138 .map_err(|err| rustls::Error::General(err.to_string()))?;
139 Ok(self)
140 }
141
142 pub fn with_max_cert_chain_depth(self, len: u16) -> Result<Self, Error> {
143 let _ = len;
145 Ok(self)
146 }
147
148 pub fn with_application_protocols<P: Iterator<Item = I>, I: AsRef<[u8]>>(
149 mut self,
150 protocols: P,
151 ) -> Result<Self, rustls::Error> {
152 self.application_protocols = protocols.map(|p| p.as_ref().to_vec()).collect();
153 Ok(self)
154 }
155
156 pub fn with_key_logging(mut self) -> Result<Self, Error> {
157 self.key_log = Some(Arc::new(rustls::KeyLogFile::new()));
158 Ok(self)
159 }
160
161 pub fn build(self) -> Result<Client, Error> {
162 if self.cert_store.is_empty() {
164 return Err(
167 rustls::Error::General("missing trusted root certificate(s)".to_string()).into(),
168 );
169 }
170
171 let mut config = default_config_builder()?
172 .with_root_certificates(self.cert_store)
173 .with_no_client_auth();
174
175 config.max_fragment_size = None;
176 config.alpn_protocols = self.application_protocols;
177
178 if let Some(key_log) = self.key_log {
179 config.key_log = key_log;
180 }
181
182 #[allow(deprecated)]
183 Ok(Client::new(config))
184 }
185}