bertie/stream/
client.rs

1//! # TLS Client
2//!
3//! TLS streaming client API.
4
5use rand::CryptoRng;
6use std::{
7    eprintln,
8    io::{Read, Write},
9    net::TcpStream,
10    println,
11    string::ToString,
12    vec,
13    vec::Vec,
14};
15// use tracing::{event, Level};
16
17use super::bertie_stream::{read_record, BertieError, BertieStream, TlsStream};
18use crate::{tls13crypto::*, tls13utils::*, Client};
19
20pub struct ClientState<Stream: Read + Write> {
21    stream: Stream,
22    read_buffer: Vec<u8>,
23    cstate: Option<Client>,
24}
25
26impl<Stream: Read + Write> ClientState<Stream> {
27    /// Create a new client state for a `Stream`.
28    pub(crate) fn new(stream: Stream) -> Self {
29        Self {
30            stream,
31            read_buffer: vec![],
32            cstate: None,
33        }
34    }
35}
36
37impl<T: Read + Write> TlsStream<T> for ClientState<T> {
38    fn write_tls(&mut self, bytes: &[u8]) -> Result<(), BertieError> {
39        let cstate = match self.cstate.take() {
40            Some(state) => state,
41            None => return Err(BertieError::InvalidState),
42        };
43
44        let (wire_bytes, new_state) = cstate.write(AppData::new(bytes.into()))?;
45        self.cstate = Some(new_state);
46
47        // Write out the request
48        self.stream
49            .write_all(&wire_bytes.declassify())
50            .map_err(|e| e.into())
51    }
52
53    fn read_tls(&mut self) -> Result<Vec<u8>, BertieError> {
54        let mut state = match self.cstate.take() {
55            Some(state) => state,
56            None => return Err(BertieError::InvalidState),
57        };
58
59        let application_data = loop {
60            let record = read_record(&mut self.read_buffer, &mut self.stream)?;
61            let ad;
62            (ad, state) = state.read(&record.into())?;
63            match ad {
64                Some(application_data) => break application_data,
65                None => continue,
66            }
67        };
68        self.cstate = Some(state);
69        Ok(application_data.into_raw().declassify())
70    }
71
72    fn stream_mut(&mut self) -> &mut T {
73        &mut self.stream
74    }
75}
76
77impl<Stream: Read + Write> BertieStream<ClientState<Stream>> {
78    /// Open a connection with the given stream, ciphersuite, and host.
79    pub fn open_with_stream(
80        host: &str,
81        ciphersuite: Algorithms,
82        stream: Stream,
83    ) -> Result<Self, BertieError> {
84        Ok(Self {
85            state: ClientState::new(stream),
86            ciphersuite,
87            host: host.to_string(),
88        })
89    }
90}
91
92impl BertieStream<ClientState<TcpStream>> {
93    /// Create a new Bertie stream connecting to `host:port`.
94    ///
95    /// This uses a set of default ciphersuites.
96    /// If you want to define your own set of ciphersuites, use [`open`],
97    /// [`with_ciphersuites`], and [`start`].
98    pub fn client(
99        host: &str,
100        port: u16,
101        ciphersuite: Algorithms,
102        rng: &mut impl CryptoRng,
103    ) -> Result<Self, BertieError> {
104        let mut stream = Self::open(host, port, ciphersuite)?;
105        stream.ciphersuite = ciphersuite;
106        stream.start(rng)?;
107        Ok(stream)
108    }
109
110    /// Open a connection to `host:port`.
111    pub fn open(host: &str, port: u16, ciphersuite: Algorithms) -> Result<Self, BertieError> {
112        let stream = TcpStream::connect((host, port))?;
113        stream.set_nodelay(true)?;
114        Ok(Self {
115            state: ClientState::new(stream),
116            ciphersuite,
117            host: host.to_string(),
118        })
119    }
120
121    /// Open the connection.
122    ///
123    /// This will fail if the connection wasn't set up correctly.
124    pub fn start(&mut self, rng: &mut impl CryptoRng) -> Result<(), BertieError> {
125        // Initialize TLS 1.3 client.
126        if self.state.cstate.is_some() {
127            return Err(BertieError::InvalidState);
128        }
129
130        // Client Hello
131        let (client_hello, cstate) = {
132            let sni = self.host.as_bytes();
133            Client::connect(self.ciphersuite, &Bytes::from(sni), None, None, rng)?
134        };
135        // event!(Level::TRACE, "client hello: {}", client_hello.as_hex());
136        // event!(Level::DEBUG, "  {ciphersuite:?}");
137        self.write_all(&client_hello.declassify())?;
138
139        let mut read_buffer = Vec::new();
140
141        // Server Hello
142        let server_hello = read_record(&mut read_buffer, &mut self.state.stream)?;
143
144        // Check for alerts
145        if server_hello[0] == 21 {
146            eprintln!(
147                "Server does not support proposed algorithms. {:?}",
148                self.ciphersuite
149            );
150            return Err(UNSUPPORTED_ALGORITHM.into());
151        }
152
153        // Read server hello
154        let cstate = match cstate.read_handshake(&Bytes::from(server_hello)) {
155            Ok((_, cstate)) => cstate,
156            Err(e) => {
157                println!(" >>> ERROR {e}");
158                match e {
159                    UNSUPPORTED_ALGORITHM => {
160                        eprintln!("Server does not support proposed algorithms.")
161                    }
162                    PROTOCOL_VERSION_ALERT => eprintln!("Wrong TLS protocol version TLS({:?})", e),
163                    APPLICATION_DATA_INSTEAD_OF_HANDSHAKE => {
164                        eprintln!("Server sent application data instead of a handshake message.")
165                    }
166                    MISSING_KEY_SHARE => eprintln!("Hello message was missing a key share."),
167                    DECODE_ERROR => eprintln!("Decode error."), // parsing of the server hello failed
168                    _ => eprintln!("Bertie client error {}", e),
169                }
170                return Err(e.into());
171            }
172        };
173
174        // Read change cipherspec
175        // This is sent in many cases for middlebox compatibility. But it's not
176        // actually part of TLS 1.3
177        let change_cipher_spec = read_record(&mut read_buffer, &mut self.state.stream)?;
178
179        // Finish the handshake
180        let mut cf_rec = None;
181        let mut cstate = cstate;
182        while cf_rec.is_none() {
183            let rec = read_record(&mut read_buffer, &mut self.state.stream)?;
184
185            let (new_cf_rec, new_cstate) = match cstate.read_handshake(&rec.into()) {
186                Ok((new_cf_rec, new_cstate)) => (new_cf_rec, new_cstate),
187                Err(e) => {
188                    match e {
189                        // signature verification failed or parsing of the certificate failed
190                        INVALID_SIGNATURE => eprintln!("Invalid server signature"),
191                        _ => eprintln!("Bertie client error {}", e),
192                    }
193                    return Err(e.into());
194                }
195            };
196            cf_rec = new_cf_rec;
197            cstate = new_cstate;
198        }
199
200        // Let's pretend to be TLS 1.2 as well.
201        let change_cipher_spec = Bytes::from_hex("140303000101");
202        self.write_all(&change_cipher_spec.declassify())?;
203
204        let cf_rec = cf_rec.unwrap();
205        self.write_all(&cf_rec.declassify())?;
206
207        // Store the state.
208        self.state.cstate = Some(cstate);
209
210        Ok(())
211    }
212
213    fn write_all(&mut self, bytes: &[u8]) -> Result<(), BertieError> {
214        self.state
215            .stream_mut()
216            .write_all(bytes)
217            .map_err(|e| e.into())
218    }
219
220    /// Read from the stream.
221    ///
222    /// This reads from the encrypted TLS channel
223    pub fn read(&mut self) -> Result<Vec<u8>, BertieError> {
224        self.state.read_tls()
225    }
226
227    /// Write to the stream.
228    ///
229    /// This writes to the encrypted TLS stream.
230    pub fn write(&mut self, bytes: &[u8]) -> Result<usize, BertieError> {
231        self.state.write_tls(bytes)?;
232        Ok(bytes.len())
233    }
234}
235
236#[cfg(test)]
237mod tests {
238    use rand::{self, rng};
239
240    use crate::tls13crypto::SHA256_Chacha20Poly1305_EcdsaSecp256r1Sha256_X25519;
241
242    use super::*;
243    use std::{format, string::String};
244
245    #[test]
246    fn client() {
247        let host = "google.com";
248        let port = 443;
249        let mut stream = BertieStream::client(
250            host,
251            port,
252            SHA256_Chacha20Poly1305_EcdsaSecp256r1Sha256_X25519,
253            &mut rng(),
254        )
255        .expect("Error connecting to server");
256
257        // Send HTTP GET
258        let request = format!("GET / HTTP/1.1\r\nHost: {}\r\n\r\n", host);
259        stream
260            .write(request.as_bytes())
261            .expect("Error writing to Bertie stream");
262        let response = stream.read().unwrap();
263        let response_string = String::from_utf8_lossy(&response);
264        eprintln!("{response_string:}");
265    }
266}