-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Expand file tree
/
Copy pathtls_native_tls.rs
More file actions
100 lines (83 loc) 路 3.3 KB
/
Copy pathtls_native_tls.rs
File metadata and controls
100 lines (83 loc) 路 3.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
use std::io::{self, Read, Write};
use crate::io::ReadBuf;
use crate::net::tls::util::StdSocket;
use crate::net::tls::TlsConfig;
use crate::net::Socket;
use crate::rt;
use crate::Error;
use native_tls::{HandshakeError, Identity};
use std::task::{Context, Poll};
pub struct NativeTlsSocket<S: Socket> {
stream: native_tls::TlsStream<StdSocket<S>>,
}
impl<S: Socket> Socket for NativeTlsSocket<S> {
fn try_read(&mut self, buf: &mut dyn ReadBuf) -> io::Result<usize> {
self.stream.read(buf.init_mut())
}
fn try_write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.stream.write(buf)
}
fn poll_read_ready(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
self.stream.get_mut().poll_ready(cx)
}
fn poll_write_ready(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
self.stream.get_mut().poll_ready(cx)
}
fn poll_shutdown(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
match self.stream.shutdown() {
Err(e) if e.kind() == io::ErrorKind::WouldBlock => self.stream.get_mut().poll_ready(cx),
ready => Poll::Ready(ready),
}
}
}
#[derive(Debug, Clone)]
pub struct NativeTlsConnector {
connector: native_tls::TlsConnector,
}
pub async fn connector(config: TlsConfig<'_>) -> crate::Result<NativeTlsConnector> {
let mut builder = native_tls::TlsConnector::builder();
builder
.danger_accept_invalid_certs(config.accept_invalid_certs)
.danger_accept_invalid_hostnames(config.accept_invalid_hostnames);
if let Some(root_cert_path) = config.root_cert_path {
let data = root_cert_path.data().await?;
builder.add_root_certificate(native_tls::Certificate::from_pem(&data).map_err(Error::tls)?);
}
// authentication using user's key-file and its associated certificate
if let (Some(cert_path), Some(key_path)) = (config.client_cert_path, config.client_key_path) {
let cert_path = cert_path.data().await?;
let key_path = key_path.data().await?;
let identity = Identity::from_pkcs8(&cert_path, &key_path).map_err(Error::tls)?;
builder.identity(identity);
}
// The openssl TlsConnector synchronously loads certificates from files.
// Loading these files can block for tens of milliseconds.
let connector = rt::spawn_blocking(move || builder.build())
.await
.map_err(Error::tls)?;
Ok(NativeTlsConnector { connector })
}
pub async fn handshake<S: Socket>(
socket: S,
hostname: &str,
connector: &NativeTlsConnector,
) -> crate::Result<NativeTlsSocket<S>> {
let mut mid_handshake = match connector
.connector
.connect(hostname, StdSocket::new(socket))
{
Ok(tls_stream) => return Ok(NativeTlsSocket { stream: tls_stream }),
Err(HandshakeError::Failure(e)) => return Err(Error::tls(e)),
Err(HandshakeError::WouldBlock(mid_handshake)) => mid_handshake,
};
loop {
mid_handshake.get_mut().ready().await?;
match mid_handshake.handshake() {
Ok(tls_stream) => return Ok(NativeTlsSocket { stream: tls_stream }),
Err(HandshakeError::Failure(e)) => return Err(Error::tls(e)),
Err(HandshakeError::WouldBlock(mid_handshake_)) => {
mid_handshake = mid_handshake_;
}
}
}
}