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}