boring_imp/ssl/
connector.rs1use std::io::{Read, Write};
2use std::ops::{Deref, DerefMut};
3
4use crate::dh::Dh;
5use crate::error::ErrorStack;
6use crate::ssl::{
7 HandshakeError, Ssl, SslContext, SslContextBuilder, SslContextRef, SslMethod, SslMode,
8 SslOptions, SslRef, SslStream, SslVerifyMode,
9};
10use crate::version;
11use std::net::IpAddr;
12
13use super::MidHandshakeSslStream;
14
15const FFDHE_2048: &str = "
16-----BEGIN DH PARAMETERS-----
17MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz
18+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a
1987VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7
20YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi
217MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD
22ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
23-----END DH PARAMETERS-----
24";
25
26enum ContextType {
27 WithMethod(SslMethod),
28 #[cfg(feature = "rpk")]
29 Rpk,
30}
31
32#[allow(clippy::inconsistent_digit_grouping)]
33fn ctx(ty: ContextType) -> Result<SslContextBuilder, ErrorStack> {
34 let mut ctx = match ty {
35 ContextType::WithMethod(method) => SslContextBuilder::new(method),
36 #[cfg(feature = "rpk")]
37 ContextType::Rpk => SslContextBuilder::new_rpk(),
38 }?;
39
40 let mut opts = SslOptions::ALL
41 | SslOptions::NO_COMPRESSION
42 | SslOptions::NO_SSLV2
43 | SslOptions::NO_SSLV3
44 | SslOptions::SINGLE_DH_USE
45 | SslOptions::SINGLE_ECDH_USE;
46 opts &= !SslOptions::DONT_INSERT_EMPTY_FRAGMENTS;
47
48 ctx.set_options(opts);
49
50 let mut mode =
51 SslMode::AUTO_RETRY | SslMode::ACCEPT_MOVING_WRITE_BUFFER | SslMode::ENABLE_PARTIAL_WRITE;
52
53 if version::number() >= 0x1000_1080 {
57 mode |= SslMode::RELEASE_BUFFERS;
58 }
59
60 ctx.set_mode(mode);
61
62 Ok(ctx)
63}
64
65#[derive(Clone, Debug)]
73pub struct SslConnector(SslContext);
74
75impl SslConnector {
76 pub fn builder(method: SslMethod) -> Result<SslConnectorBuilder, ErrorStack> {
80 let mut ctx = ctx(ContextType::WithMethod(method))?;
81 ctx.set_default_verify_paths()?;
82 ctx.set_cipher_list(
83 "DEFAULT:!aNULL:!eNULL:!MD5:!3DES:!DES:!RC4:!IDEA:!SEED:!aDSS:!SRP:!PSK",
84 )?;
85 setup_verify(&mut ctx);
86
87 Ok(SslConnectorBuilder(ctx))
88 }
89
90 #[cfg(feature = "rpk")]
92 pub fn rpk_builder() -> Result<SslConnectorBuilder, ErrorStack> {
93 let mut ctx = ctx(ContextType::Rpk)?;
94 ctx.set_cipher_list(
95 "DEFAULT:!aNULL:!eNULL:!MD5:!3DES:!DES:!RC4:!IDEA:!SEED:!aDSS:!SRP:!PSK",
96 )?;
97
98 Ok(SslConnectorBuilder(ctx))
99 }
100
101 pub fn setup_connect<S>(
105 &self,
106 domain: &str,
107 stream: S,
108 ) -> Result<MidHandshakeSslStream<S>, ErrorStack>
109 where
110 S: Read + Write,
111 {
112 self.configure()?.setup_connect(domain, stream)
113 }
114
115 pub fn connect<S>(&self, domain: &str, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
122 where
123 S: Read + Write,
124 {
125 self.setup_connect(domain, stream)
126 .map_err(HandshakeError::SetupFailure)?
127 .handshake()
128 }
129
130 pub fn configure(&self) -> Result<ConnectConfiguration, ErrorStack> {
132 Ssl::new(&self.0).map(|ssl| ConnectConfiguration {
133 ssl,
134 sni: true,
135 verify_hostname: true,
136 })
137 }
138
139 pub fn into_context(self) -> SslContext {
141 self.0
142 }
143
144 pub fn context(&self) -> &SslContextRef {
146 &self.0
147 }
148}
149
150pub struct SslConnectorBuilder(SslContextBuilder);
152
153impl SslConnectorBuilder {
154 pub fn build(self) -> SslConnector {
156 SslConnector(self.0.build())
157 }
158}
159
160impl Deref for SslConnectorBuilder {
161 type Target = SslContextBuilder;
162
163 fn deref(&self) -> &SslContextBuilder {
164 &self.0
165 }
166}
167
168impl DerefMut for SslConnectorBuilder {
169 fn deref_mut(&mut self) -> &mut SslContextBuilder {
170 &mut self.0
171 }
172}
173
174pub struct ConnectConfiguration {
176 ssl: Ssl,
177 sni: bool,
178 verify_hostname: bool,
179}
180
181impl ConnectConfiguration {
182 pub fn use_server_name_indication(mut self, use_sni: bool) -> ConnectConfiguration {
184 self.set_use_server_name_indication(use_sni);
185 self
186 }
187
188 pub fn set_use_server_name_indication(&mut self, use_sni: bool) {
192 self.sni = use_sni;
193 }
194
195 pub fn verify_hostname(mut self, verify_hostname: bool) -> ConnectConfiguration {
197 self.set_verify_hostname(verify_hostname);
198 self
199 }
200
201 pub fn set_verify_hostname(&mut self, verify_hostname: bool) {
211 self.verify_hostname = verify_hostname;
212 }
213
214 pub fn into_ssl(mut self, domain: &str) -> Result<Ssl, ErrorStack> {
218 if self.sni && domain.parse::<IpAddr>().is_err() {
219 self.ssl.set_hostname(domain)?;
220 }
221
222 #[cfg(feature = "rpk")]
223 let verify_hostname = !self.ssl.ssl_context().is_rpk() && self.verify_hostname;
224
225 #[cfg(not(feature = "rpk"))]
226 let verify_hostname = self.verify_hostname;
227
228 if verify_hostname {
229 setup_verify_hostname(&mut self.ssl, domain)?;
230 }
231
232 Ok(self.ssl)
233 }
234
235 pub fn setup_connect<S>(
242 self,
243 domain: &str,
244 stream: S,
245 ) -> Result<MidHandshakeSslStream<S>, ErrorStack>
246 where
247 S: Read + Write,
248 {
249 Ok(self.into_ssl(domain)?.setup_connect(stream))
250 }
251
252 pub fn connect<S>(self, domain: &str, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
259 where
260 S: Read + Write,
261 {
262 self.setup_connect(domain, stream)
263 .map_err(HandshakeError::SetupFailure)?
264 .handshake()
265 }
266}
267
268impl Deref for ConnectConfiguration {
269 type Target = SslRef;
270
271 fn deref(&self) -> &SslRef {
272 &self.ssl
273 }
274}
275
276impl DerefMut for ConnectConfiguration {
277 fn deref_mut(&mut self) -> &mut SslRef {
278 &mut self.ssl
279 }
280}
281
282#[derive(Clone)]
287pub struct SslAcceptor(SslContext);
288
289impl SslAcceptor {
290 #[cfg(feature = "rpk")]
292 pub fn rpk() -> Result<SslAcceptorBuilder, ErrorStack> {
293 let mut ctx = ctx(ContextType::Rpk)?;
294 ctx.set_options(SslOptions::NO_TLSV1 | SslOptions::NO_TLSV1_1);
295 let dh = Dh::params_from_pem(FFDHE_2048.as_bytes())?;
296 ctx.set_tmp_dh(&dh)?;
297 ctx.set_cipher_list(
298 "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:\
299 ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:\
300 DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384"
301 )?;
302 Ok(SslAcceptorBuilder(ctx))
303 }
304
305 pub fn mozilla_intermediate_v5(method: SslMethod) -> Result<SslAcceptorBuilder, ErrorStack> {
313 let mut ctx = ctx(ContextType::WithMethod(method))?;
314 ctx.set_options(SslOptions::NO_TLSV1 | SslOptions::NO_TLSV1_1);
315 let dh = Dh::params_from_pem(FFDHE_2048.as_bytes())?;
316 ctx.set_tmp_dh(&dh)?;
317 ctx.set_cipher_list(
318 "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:\
319 ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:\
320 DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384"
321 )?;
322 Ok(SslAcceptorBuilder(ctx))
323 }
324
325 pub fn mozilla_intermediate(method: SslMethod) -> Result<SslAcceptorBuilder, ErrorStack> {
334 let mut ctx = ctx(ContextType::WithMethod(method))?;
335 ctx.set_options(SslOptions::CIPHER_SERVER_PREFERENCE);
336 ctx.set_options(SslOptions::NO_TLSV1_3);
337 let dh = Dh::params_from_pem(FFDHE_2048.as_bytes())?;
338 ctx.set_tmp_dh(&dh)?;
339 ctx.set_cipher_list(
340 "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:\
341 ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:\
342 DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:\
343 ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:\
344 ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:\
345 DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:\
346 EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:\
347 AES256-SHA:DES-CBC3-SHA:!DSS",
348 )?;
349 Ok(SslAcceptorBuilder(ctx))
350 }
351
352 pub fn mozilla_modern(method: SslMethod) -> Result<SslAcceptorBuilder, ErrorStack> {
360 let mut ctx = ctx(ContextType::WithMethod(method))?;
361 ctx.set_options(
362 SslOptions::CIPHER_SERVER_PREFERENCE | SslOptions::NO_TLSV1 | SslOptions::NO_TLSV1_1,
363 );
364 ctx.set_options(SslOptions::NO_TLSV1_3);
365 ctx.set_cipher_list(
366 "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:\
367 ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:\
368 ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256",
369 )?;
370 Ok(SslAcceptorBuilder(ctx))
371 }
372
373 pub fn setup_accept<S>(&self, stream: S) -> Result<MidHandshakeSslStream<S>, ErrorStack>
377 where
378 S: Read + Write,
379 {
380 let ssl = Ssl::new(&self.0)?;
381
382 Ok(ssl.setup_accept(stream))
383 }
384
385 pub fn accept<S>(&self, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
390 where
391 S: Read + Write,
392 {
393 self.setup_accept(stream)
394 .map_err(HandshakeError::SetupFailure)?
395 .handshake()
396 }
397
398 pub fn into_context(self) -> SslContext {
400 self.0
401 }
402
403 pub fn context(&self) -> &SslContextRef {
405 &self.0
406 }
407}
408
409pub struct SslAcceptorBuilder(SslContextBuilder);
411
412impl SslAcceptorBuilder {
413 pub fn build(self) -> SslAcceptor {
415 SslAcceptor(self.0.build())
416 }
417}
418
419impl Deref for SslAcceptorBuilder {
420 type Target = SslContextBuilder;
421
422 fn deref(&self) -> &SslContextBuilder {
423 &self.0
424 }
425}
426
427impl DerefMut for SslAcceptorBuilder {
428 fn deref_mut(&mut self) -> &mut SslContextBuilder {
429 &mut self.0
430 }
431}
432
433fn setup_verify(ctx: &mut SslContextBuilder) {
434 ctx.set_verify(SslVerifyMode::PEER);
435}
436
437fn setup_verify_hostname(ssl: &mut SslRef, domain: &str) -> Result<(), ErrorStack> {
438 use crate::x509::verify::X509CheckFlags;
439
440 let param = ssl.param_mut();
441 param.set_hostflags(X509CheckFlags::NO_PARTIAL_WILDCARDS);
442 match domain.parse() {
443 Ok(ip) => param.set_ip(ip),
444 Err(_) => param.set_host(domain),
445 }
446}