rama_boring/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
26#[allow(clippy::inconsistent_digit_grouping)]
27fn ctx(method: SslMethod) -> Result<SslContextBuilder, ErrorStack> {
28 let mut ctx = SslContextBuilder::new(method)?;
29
30 let mut opts = SslOptions::ALL
31 | SslOptions::NO_COMPRESSION
32 | SslOptions::NO_SSLV2
33 | SslOptions::NO_SSLV3
34 | SslOptions::SINGLE_DH_USE
35 | SslOptions::SINGLE_ECDH_USE;
36 opts &= !SslOptions::DONT_INSERT_EMPTY_FRAGMENTS;
37
38 ctx.set_options(opts);
39
40 let mut mode =
41 SslMode::AUTO_RETRY | SslMode::ACCEPT_MOVING_WRITE_BUFFER | SslMode::ENABLE_PARTIAL_WRITE;
42
43 if version::number() >= 0x1000_1080 {
47 mode |= SslMode::RELEASE_BUFFERS;
48 }
49
50 ctx.set_mode(mode);
51
52 Ok(ctx)
53}
54
55#[derive(Clone, Debug)]
63pub struct SslConnector(SslContext);
64
65impl SslConnector {
66 pub fn builder(method: SslMethod) -> Result<SslConnectorBuilder, ErrorStack> {
70 let mut ctx = ctx(method)?;
71 ctx.set_default_verify_paths()?;
72 ctx.set_cipher_list(
73 "DEFAULT:!aNULL:!eNULL:!MD5:!3DES:!DES:!RC4:!IDEA:!SEED:!aDSS:!SRP:!PSK",
74 )?;
75 setup_verify(&mut ctx);
76
77 Ok(SslConnectorBuilder(ctx))
78 }
79
80 pub fn setup_connect<S>(
84 &self,
85 domain: &str,
86 stream: S,
87 ) -> Result<MidHandshakeSslStream<S>, ErrorStack>
88 where
89 S: Read + Write,
90 {
91 self.configure()?.setup_connect(domain, stream)
92 }
93
94 pub fn connect<S>(&self, domain: &str, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
101 where
102 S: Read + Write,
103 {
104 self.setup_connect(domain, stream)
105 .map_err(HandshakeError::SetupFailure)?
106 .handshake()
107 }
108
109 pub fn configure(&self) -> Result<ConnectConfiguration, ErrorStack> {
111 Ssl::new(&self.0).map(|ssl| ConnectConfiguration {
112 ssl,
113 sni: true,
114 verify_hostname: true,
115 })
116 }
117
118 #[must_use]
120 pub fn into_context(self) -> SslContext {
121 self.0
122 }
123
124 #[must_use]
126 pub fn context(&self) -> &SslContextRef {
127 &self.0
128 }
129}
130
131pub struct SslConnectorBuilder(SslContextBuilder);
133
134impl SslConnectorBuilder {
135 #[must_use]
137 pub fn build(self) -> SslConnector {
138 SslConnector(self.0.build())
139 }
140}
141
142impl Deref for SslConnectorBuilder {
143 type Target = SslContextBuilder;
144
145 fn deref(&self) -> &SslContextBuilder {
146 &self.0
147 }
148}
149
150impl DerefMut for SslConnectorBuilder {
151 fn deref_mut(&mut self) -> &mut SslContextBuilder {
152 &mut self.0
153 }
154}
155
156pub struct ConnectConfiguration {
158 ssl: Ssl,
159 sni: bool,
160 verify_hostname: bool,
161}
162
163impl ConnectConfiguration {
164 #[must_use]
166 pub fn use_server_name_indication(mut self, use_sni: bool) -> ConnectConfiguration {
167 self.set_use_server_name_indication(use_sni);
168 self
169 }
170
171 pub fn set_use_server_name_indication(&mut self, use_sni: bool) {
175 self.sni = use_sni;
176 }
177
178 #[must_use]
180 pub fn verify_hostname(mut self, verify_hostname: bool) -> ConnectConfiguration {
181 self.set_verify_hostname(verify_hostname);
182 self
183 }
184
185 pub fn set_verify_hostname(&mut self, verify_hostname: bool) {
195 self.verify_hostname = verify_hostname;
196 }
197
198 pub fn into_ssl(mut self, domain: &str) -> Result<Ssl, ErrorStack> {
202 if self.sni && domain.parse::<IpAddr>().is_err() {
203 self.ssl.set_hostname(domain)?;
204 }
205
206 if self.verify_hostname {
207 setup_verify_hostname(&mut self.ssl, domain)?;
208 }
209
210 Ok(self.ssl)
211 }
212
213 pub fn setup_connect<S>(
220 self,
221 domain: &str,
222 stream: S,
223 ) -> Result<MidHandshakeSslStream<S>, ErrorStack>
224 where
225 S: Read + Write,
226 {
227 Ok(self.into_ssl(domain)?.setup_connect(stream))
228 }
229
230 pub fn connect<S>(self, domain: &str, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
237 where
238 S: Read + Write,
239 {
240 self.setup_connect(domain, stream)
241 .map_err(HandshakeError::SetupFailure)?
242 .handshake()
243 }
244}
245
246impl Deref for ConnectConfiguration {
247 type Target = SslRef;
248
249 fn deref(&self) -> &SslRef {
250 &self.ssl
251 }
252}
253
254impl DerefMut for ConnectConfiguration {
255 fn deref_mut(&mut self) -> &mut SslRef {
256 &mut self.ssl
257 }
258}
259
260#[derive(Clone)]
265pub struct SslAcceptor(SslContext);
266
267impl SslAcceptor {
268 pub fn mozilla_intermediate_v5(method: SslMethod) -> Result<SslAcceptorBuilder, ErrorStack> {
276 let mut ctx = ctx(method)?;
277 ctx.set_options(SslOptions::NO_TLSV1 | SslOptions::NO_TLSV1_1);
278 let dh = Dh::params_from_pem(FFDHE_2048.as_bytes())?;
279 ctx.set_tmp_dh(&dh)?;
280 ctx.set_cipher_list(
281 "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:\
282 ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:\
283 DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384"
284 )?;
285 Ok(SslAcceptorBuilder(ctx))
286 }
287
288 pub fn mozilla_intermediate(method: SslMethod) -> Result<SslAcceptorBuilder, ErrorStack> {
297 let mut ctx = ctx(method)?;
298 ctx.set_options(SslOptions::CIPHER_SERVER_PREFERENCE);
299 ctx.set_options(SslOptions::NO_TLSV1_3);
300 let dh = Dh::params_from_pem(FFDHE_2048.as_bytes())?;
301 ctx.set_tmp_dh(&dh)?;
302 ctx.set_cipher_list(
303 "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:\
304 ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:\
305 DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:\
306 ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:\
307 ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:\
308 DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:\
309 EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:\
310 AES256-SHA:DES-CBC3-SHA:!DSS",
311 )?;
312 Ok(SslAcceptorBuilder(ctx))
313 }
314
315 pub fn mozilla_modern(method: SslMethod) -> Result<SslAcceptorBuilder, ErrorStack> {
323 let mut ctx = ctx(method)?;
324 ctx.set_options(
325 SslOptions::CIPHER_SERVER_PREFERENCE | SslOptions::NO_TLSV1 | SslOptions::NO_TLSV1_1,
326 );
327 ctx.set_options(SslOptions::NO_TLSV1_3);
328 ctx.set_cipher_list(
329 "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:\
330 ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:\
331 ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256",
332 )?;
333 Ok(SslAcceptorBuilder(ctx))
334 }
335
336 pub fn setup_accept<S>(&self, stream: S) -> Result<MidHandshakeSslStream<S>, ErrorStack>
340 where
341 S: Read + Write,
342 {
343 let ssl = Ssl::new(&self.0)?;
344
345 Ok(ssl.setup_accept(stream))
346 }
347
348 pub fn accept<S>(&self, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
353 where
354 S: Read + Write,
355 {
356 self.setup_accept(stream)
357 .map_err(HandshakeError::SetupFailure)?
358 .handshake()
359 }
360
361 #[must_use]
363 pub fn into_context(self) -> SslContext {
364 self.0
365 }
366
367 #[must_use]
369 pub fn context(&self) -> &SslContextRef {
370 &self.0
371 }
372}
373
374pub struct SslAcceptorBuilder(SslContextBuilder);
376
377impl SslAcceptorBuilder {
378 #[must_use]
380 pub fn build(self) -> SslAcceptor {
381 SslAcceptor(self.0.build())
382 }
383}
384
385impl Deref for SslAcceptorBuilder {
386 type Target = SslContextBuilder;
387
388 fn deref(&self) -> &SslContextBuilder {
389 &self.0
390 }
391}
392
393impl DerefMut for SslAcceptorBuilder {
394 fn deref_mut(&mut self) -> &mut SslContextBuilder {
395 &mut self.0
396 }
397}
398
399fn setup_verify(ctx: &mut SslContextBuilder) {
400 ctx.set_verify(SslVerifyMode::PEER);
401}
402
403fn setup_verify_hostname(ssl: &mut SslRef, domain: &str) -> Result<(), ErrorStack> {
404 use crate::x509::verify::X509CheckFlags;
405
406 let param = ssl.param_mut();
407 param.set_hostflags(X509CheckFlags::NO_PARTIAL_WILDCARDS);
408 match domain.parse() {
409 Ok(ip) => param.set_ip(ip),
410 Err(_) => param.set_host(domain),
411 }
412}