bertie/
tls13api.rs

1//! # Public TLS 1.3 API
2//!
3//! This is the entry point for consumers of Bertie.
4//! It defines the public API that users of Bertie use to establish TLS connections.
5//!
6//! **NOTE:** This is a low level TLS API that needs careful handling.
7//!           We will add a more usable API on top in future. But the verifiable
8//!           core of the protocol starts here.
9
10use rand::CryptoRng;
11
12use crate::{
13    server::ServerDB,
14    tls13crypto::*,
15    tls13formats::{handshake_data::HandshakeType, *},
16    tls13handshake::*,
17    tls13record::*,
18    tls13utils::*,
19};
20
21/// The TLS Client state.
22pub enum Client {
23    /// The initial client handshake state.
24    Client0(ClientPostClientHello, Option<ClientCipherState0>),
25
26    /// The client handshake state after receiving the server hello message.
27    ClientH(
28        ClientPostServerHello,
29        Option<ClientCipherState0>,
30        DuplexCipherStateH,
31        handshake_data::HandshakeData,
32    ),
33
34    /// The client handshake state after finishing the handshake.
35    Client1(ClientPostClientFinished, DuplexCipherState1),
36}
37
38/// Check if the client is using a PSK mode or not.
39///
40/// Returns `true` if the client is in PSK mode and `false` otherwise.
41pub fn in_psk_mode(c: &Client) -> bool {
42    match c {
43        Client::Client0(cstate, _) => algs_post_client_hello(cstate).psk_mode(),
44        Client::ClientH(cstate, _, _, _) => algs_post_server_hello(cstate).psk_mode(),
45        Client::Client1(cstate, _) => algs_post_client_finished(cstate).psk_mode(),
46    }
47}
48
49impl Client {
50    /// Start a TLS handshake as client.
51    /// Note that Bertie clients only support a single ciphersuite at a time and
52    /// do not perform ciphersuite negotiation.
53    ///
54    /// This function takes the
55    /// * `ciphersuite` to use for this client
56    /// * `server_name` for the server to connect to
57    /// * `session_ticket` for an optional session ticket
58    /// * `psk` for an optional pre-shared-key
59    /// * `entropy` for the randomness required in the handshake
60    ///
61    /// The function returns a [`Result`].
62    /// When successful, the function returns a tuple with the first element the
63    /// client hello record as bytes, and the [`Client`] state as the second element.
64    /// If an error occurs, it returns a [`TLSError`].
65    pub fn connect(
66        ciphersuite: Algorithms,
67        server_name: &Bytes,
68        session_ticket: Option<Bytes>,
69        psk: Option<Key>,
70        rng: &mut impl CryptoRng,
71    ) -> Result<(Bytes, Self), TLSError> {
72        let (client_hello, cipherstate0, client_state) =
73            client_init(ciphersuite, server_name, session_ticket, psk, rng)?;
74        let mut client_hello_record = handshake_record(client_hello)?;
75        client_hello_record[2] = U8(0x01);
76        Ok((
77            client_hello_record,
78            Client::Client0(client_state, cipherstate0),
79        ))
80    }
81
82    // This function reads handshake records and decrypts them using the TLS 1.3 record protocol
83    // A slightly modified version would work for QUIC
84    /// Read the next handshake Message.
85    ///
86    /// This function takes the current state and `handshake_bytes` and returns
87    /// the next state or a [`TLSError`].
88    ///
89    /// The function returns a [`Result`].
90    /// When successful, the function returns a tuple with the first element the
91    /// next client handshake message as bytes option, and the next [`Client`] state as
92    /// the second element.
93    /// If there's no handshake message, the first element is [`None`].
94    /// If an error occurs, it returns a [`TLSError`].
95    pub fn read_handshake(
96        self,
97        handshake_bytes: &Bytes,
98    ) -> Result<(Option<Bytes>, Self), TLSError> {
99        match self {
100            Client::Client0(state, cipher_state) => {
101                let sf = get_handshake_record(handshake_bytes)?;
102                let (cipher1, cstate) = client_set_params(&sf, state)?;
103                let buf = handshake_data::HandshakeData::from(Bytes::new());
104                Ok((None, Client::ClientH(cstate, cipher_state, cipher1, buf)))
105            }
106            Client::ClientH(cstate, cipher0, cipher_hs, buf) => {
107                let (hd, cipher_hs) = decrypt_handshake(handshake_bytes, cipher_hs)?;
108                let buf = buf.concat(&hd);
109                if buf.find_handshake_message(HandshakeType::Finished, 0) {
110                    let (cfin, cipher1, cstate) = client_finish(&buf, cstate)?;
111                    let (cf_rec, _cipher_hs) = encrypt_handshake(cfin, 0, cipher_hs)?;
112                    Ok((Some(cf_rec), Client::Client1(cstate, cipher1)))
113                } else {
114                    Ok((None, Client::ClientH(cstate, cipher0, cipher_hs, buf)))
115                }
116            }
117            _ => Err(INCORRECT_STATE),
118        }
119    }
120
121    /// Read application data and session tickets.
122    ///
123    /// This function can be used when the TLS handshake is complete, to read
124    /// application data and session tickets from the server.
125    ///
126    /// It takes the current state and `message_bytes` and returns
127    /// the next state or a [`TLSError`].
128    ///
129    /// The function returns a [`Result`].
130    /// When successful, the function returns a tuple with the first element the
131    /// application data as bytes option, and the new [`Client`] state as the second element.
132    /// If there's no application data, the first element is [`None`].
133    /// If an error occurs, it returns a [`TLSError`].
134    pub fn read(self, message_bytes: &Bytes) -> Result<(Option<AppData>, Self), TLSError> {
135        match self {
136            Client::Client1(state, cipher1) => {
137                let (ty, hd, cipher1) = decrypt_data_or_hs(message_bytes, cipher1)?;
138                match ty {
139                    ContentType::ApplicationData => {
140                        Ok((Some(AppData::new(hd)), Client::Client1(state, cipher1)))
141                    }
142                    ContentType::Handshake => Ok((None, Client::Client1(state, cipher1))),
143                    _ => Err(PARSE_FAILED),
144                }
145            }
146            _ => Err(INCORRECT_STATE),
147        }
148    }
149
150    /// Send application data to the server.
151    ///
152    /// The function returns a [`Result`].
153    /// When successful, the function returns a tuple with the first element the
154    /// encrypted `application_data` as bytes, and the new [`Client`] state as the second element.
155    /// If an error occurs, it returns a [`TLSError`].
156    pub fn write(self, application_data: AppData) -> Result<(Bytes, Client), TLSError> {
157        match self {
158            Client::Client1(cstate, cipher1) => {
159                let (by, cipher1) = encrypt_data(application_data, 0, cipher1)?;
160                Ok((by, Client::Client1(cstate, cipher1)))
161            }
162            _ => Err(INCORRECT_STATE),
163        }
164    }
165}
166
167/// The TLS server state.
168pub enum Server {
169    /// The initial server state. The server accepts a new connection in this state.
170    ServerH(
171        ServerPostServerFinished,
172        Option<ServerCipherState0>,
173        DuplexCipherStateH,
174        DuplexCipherState1,
175    ),
176
177    /// The final server state. The server communicates via the encrypted TLS
178    /// channel in this state.
179    Server1(ServerPostClientFinished, DuplexCipherState1),
180}
181impl Server {
182    /// Start a new TLS handshake as server.
183    /// Note that Bertie servers only support a single ciphersuite at a time and
184    /// do not perform ciphersuite negotiation.
185    ///
186    /// This function takes the
187    /// * `ciphersuite` to use for this server
188    /// * `db` for the server database containing certificates and keys
189    /// * `client_hello` for the initial client hello message
190    /// * `entropy` for the randomness required in the handshake
191    ///
192    /// The function returns a [`Result`].
193    /// When successful, the function returns a three-tuple with the first element the
194    /// server hello record as bytes, the second the server finished record as bytes,
195    /// and the new [`Server`] state as the third element.
196    /// If an error occurs, it returns a [`TLSError`].
197    pub fn accept(
198        ciphersuite: Algorithms,
199        db: ServerDB,
200        client_hello: &Bytes,
201        rng: &mut impl CryptoRng,
202    ) -> Result<(Bytes, Bytes, Self), TLSError> {
203        let mut ch_rec = client_hello.clone();
204        ch_rec[2] = U8(0x03);
205        let ch = get_handshake_record(&ch_rec)?;
206        let (server_hello, server_finished, cipher0, cipher_hs, cipher1, sstate) =
207            server_init(ciphersuite, &ch, db, rng)?;
208        let sh_rec = handshake_record(server_hello)?;
209        let (sf_rec, cipher_hs) = encrypt_handshake(server_finished, 0, cipher_hs)?;
210        Ok((
211            sh_rec,
212            sf_rec,
213            Server::ServerH(sstate, cipher0, cipher_hs, cipher1),
214        ))
215    }
216
217    /// Read the next handshake Message.
218    ///
219    /// This function takes the current state and `handshake_bytes` and returns
220    /// the next state or a [`TLSError`].
221    ///
222    /// The function returns a [`Result`].
223    /// When successful, the function returns the next [`Server`] state.
224    /// If an error occurs, it returns a [`TLSError`].
225    pub fn read_handshake(self, handshake_bytes: &Bytes) -> Result<Self, TLSError> {
226        match self {
227            Server::ServerH(sstate, _cipher0, cipher_hs, cipher1) => {
228                let (cf, _cipher_hs) = decrypt_handshake(handshake_bytes, cipher_hs)?;
229                let sstate = server_finish(&cf, sstate)?;
230                Ok(Server::Server1(sstate, cipher1))
231            }
232            _ => Err(INCORRECT_STATE),
233        }
234    }
235
236    /// Send application data to the client.
237    ///
238    /// The function returns a [`Result`].
239    /// When successful, the function returns a tuple with the first element the
240    /// encrypted `application_data` as bytes, and the new [`Server`] state as the second element.
241    /// If an error occurs, it returns a [`TLSError`].
242    pub fn write(self, application_data: AppData) -> Result<(Bytes, Self), TLSError> {
243        match self {
244            Server::Server1(sstate, cipher1) => {
245                let (by, cipher1) = encrypt_data(application_data, 0, cipher1)?;
246                Ok((by, Server::Server1(sstate, cipher1)))
247            }
248            _ => Err(INCORRECT_STATE),
249        }
250    }
251
252    /// Read application data.
253    ///
254    /// This function can be used when the TLS handshake is complete, to read
255    /// application data from the client.
256    ///
257    /// It takes the current state and `application_data` and returns
258    /// the next state or a [`TLSError`].
259    ///
260    /// The function returns a [`Result`].
261    /// When successful, the function returns a tuple with the first element the
262    /// application data as bytes option, and the new [`Server`] state as the second element.
263    /// If there's no application data, the first element is [`None`].
264    /// If an error occurs, it returns a [`TLSError`].
265    pub fn read(self, application_data: &Bytes) -> Result<(Option<AppData>, Self), TLSError> {
266        match self {
267            Server::Server1(sstate, cipher1) => {
268                let (ad, cipher1) = decrypt_data(application_data, cipher1)?;
269                Ok((Some(ad), Server::Server1(sstate, cipher1)))
270            }
271            _ => Err(INCORRECT_STATE),
272        }
273    }
274}