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
|
use std::io::{Read, Write};
use std::net::TcpStream;
use zagan_bet::protocol::{FrameBuffer, write_frame};
#[derive(Clone)]
pub struct TlsServer {
acceptor: native_tls::TlsAcceptor,
}
impl TlsServer {
pub fn new(cert_path: &str) -> Result<Self, Box<dyn std::error::Error>> {
let cert_data = match std::fs::read(cert_path) {
Ok(data) => data,
Err(error) => {
return Err(format!(
"Could not read TLS identity '{}': {}\n\
\n\
First-time setup:\n\
\x20 cargo run --bin server -- --init\n\
\n\
Or generate it manually:\n\
\x20 openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem \\\n\
\x20 -days 3650 -nodes -subj \"/CN=localhost\"\n\
\x20 openssl pkcs12 -export -out identity.p12 -inkey key.pem -in cert.pem \\\n\
\x20 -passout pass:",
cert_path, error
)
.into());
}
};
let identity = native_tls::Identity::from_pkcs12(&cert_data, "")?;
let acceptor = native_tls::TlsAcceptor::new(identity)?;
Ok(Self { acceptor })
}
pub fn accept(&self, stream: TcpStream) -> Result<TlsStream, Box<dyn std::error::Error>> {
let stream = self.acceptor.accept(stream)?;
Ok(TlsStream::new(stream))
}
}
pub struct TlsStream {
stream: native_tls::TlsStream<TcpStream>,
frames: FrameBuffer,
}
impl TlsStream {
pub fn new(stream: native_tls::TlsStream<TcpStream>) -> Self {
Self {
stream,
frames: FrameBuffer::new(),
}
}
/// Read one protocol frame. `Ok(0)` is EOF with no partial frame.
pub fn read_frame(&mut self, out: &mut String) -> std::io::Result<usize> {
match self.frames.read_frame(&mut self.stream)? {
Some(frame) => {
let length = frame.len();
out.push_str(&frame);
Ok(length)
}
None => Ok(0),
}
}
pub fn write_frame(&mut self, msg: &str) -> std::io::Result<()> {
write_frame(&mut self.stream, msg)
}
pub fn peer_addr(&self) -> std::io::Result<std::net::SocketAddr> {
self.stream.get_ref().peer_addr()
}
/// Read timeout for the socket. The connection loop uses a short one so it
/// can advance crash rounds while no request is in flight.
pub fn set_read_timeout(&self, duration: Option<std::time::Duration>) -> std::io::Result<()> {
self.stream.get_ref().set_read_timeout(duration)
}
}
impl Read for TlsStream {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
self.stream.read(buf)
}
}
impl Write for TlsStream {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.stream.write(buf)
}
fn flush(&mut self) -> std::io::Result<()> {
self.stream.flush()
}
}
|