ytls_client/client_ctx/
c_handshake.rs

1//! yTls Client Handshake Context
2
3use ytls_record::Content;
4use ytls_record::MsgType;
5use ytls_record::Record;
6
7use ytls_traits::CryptoConfig;
8use ytls_traits::{TlsLeftIn, TlsLeftOut};
9
10use ytls_traits::CryptoSha256TranscriptProcessor;
11//use ytls_traits::CryptoSha256HkdfExtractProcessor;
12//use ytls_traits::CryptoSha256HkdfGenProcessor;
13//use ytls_traits::CryptoSha384TranscriptProcessor;
14use ytls_traits::CryptoX25519Processor;
15
16use ytls_keys::Tls13Keys;
17use ytls_traits::SecretStore;
18use ytls_traits::Tls13KeyScheduleApSha256;
19use ytls_traits::Tls13KeyScheduleDerivedSha256;
20use ytls_traits::Tls13KeyScheduleHandshakeSha256;
21use ytls_traits::Tls13KeyScheduleInit;
22
23use rand_core::CryptoRng;
24
25use crate::TlsClientCtxConfig;
26use crate::{CtxError, Rfc8446Error};
27
28use ytls_util::Nonce12;
29
30use ytls_ctx::HandshakeOrder;
31use ytls_keys::Tls13KeysHandshakeSha256;
32
33mod c_client_hello;
34
35mod c_client_finished;
36mod p_server_hello;
37mod p_wrapped;
38use p_server_hello::{ServerHello, ServerRecord};
39
40/// State machine context for yTLS CLient
41pub struct ClientHandshakeCtx<Config, Crypto: CryptoConfig, Rng> {
42    /// Downstream config implementation
43    config: Config,
44    /// Downstream crypto implementation
45    crypto: Crypto,
46    /// Downstream rng implementation
47    rng: Rng,
48
49    cur: HandshakeOrder,
50
51    transcript: Crypto::Hasher,
52    x25519: Option<Crypto::X25519>,
53
54    handshake_client_key: Option<[u8; 32]>,
55    handshake_client_iv: Option<Nonce12>,
56    handshake_server_key: Option<[u8; 32]>,
57    handshake_server_iv: Option<Nonce12>,
58
59    handshake_finished_server_key: Option<[u8; 32]>,
60    handshake_finished_client_key: Option<[u8; 32]>,
61
62    key_schedule: Option<([u8; 32], [u8; 32], [u8; 32])>,
63
64    is_complete: bool,
65}
66
67impl<Config, Crypto, Rng> ClientHandshakeCtx<Config, Crypto, Rng>
68where
69    Config: TlsClientCtxConfig,
70    Crypto: CryptoConfig,
71    Rng: CryptoRng,
72{
73    /// New yTLS server context with the given configuration
74    pub fn with_required(config: Config, crypto: Crypto, mut rng: Rng) -> Self {
75        let x25519 = Crypto::ecdhe_x25519(&mut rng);
76
77        Self {
78            config,
79            crypto,
80            rng,
81
82            cur: HandshakeOrder::default(),
83            transcript: Crypto::hasher_sha256(),
84            x25519: Some(x25519),
85
86            handshake_client_key: None,
87            handshake_client_iv: None,
88            handshake_server_key: None,
89            handshake_server_iv: None,
90
91            handshake_finished_server_key: None,
92            handshake_finished_client_key: None,
93
94            key_schedule: None,
95
96            is_complete: false,
97        }
98    }
99}
100
101use ytls_traits::CtxHandshakeProcessor;
102use ytls_traits::HandshakeComplete;
103
104impl<Config, Crypto, Rng> CtxHandshakeProcessor for ClientHandshakeCtx<Config, Crypto, Rng>
105where
106    Config: TlsClientCtxConfig,
107    Crypto: CryptoConfig,
108    Rng: CryptoRng,
109{
110    type Error = CtxError;
111    /// Spin yTLS Client Handshake Context
112    #[inline]
113    fn spin_handshake<Li: TlsLeftIn, Lo: TlsLeftOut, Ks: SecretStore>(
114        &mut self,
115        li: &mut Li,
116        lo: &mut Lo,
117        ks: &mut Ks,
118    ) -> Result<Option<HandshakeComplete>, Self::Error> {
119        if self.is_complete {
120            return Ok(Some(HandshakeComplete));
121        }
122
123        if self.cur.cur_is_created() {
124            self.do_client_hello(lo)?;
125            self.cur = HandshakeOrder::ClientHello;
126        }
127
128        let init_data = li.left_buf_in();
129        let init_len = init_data.len();
130        let mut data = init_data;
131
132        #[allow(unused_assignments)]
133        let mut consumed = 0;
134
135        loop {
136            if data.len() == 0 {
137                break;
138            }
139
140            let mut prc = ServerRecord::default();
141
142            let (rec, remaining) =
143                Record::parse_server(&mut prc, data).map_err(|e| CtxError::Record(e))?;
144
145            consumed = init_len - remaining.len();
146
147            match rec.content() {
148                Content::ChangeCipherSpec => {
149                    // ignore
150                    // todo: check the content compliant w/ 8446
151                }
152                Content::ApplicationData => {
153                    match self.cur {
154                        HandshakeOrder::ServerHello => {}
155                        HandshakeOrder::ServerCertificates => {}
156                        HandshakeOrder::ServerCertificateVerify => {}
157                        HandshakeOrder::ServerFinished => {}
158                        _ => return Err(CtxError::Rfc8446(Rfc8446Error::Unexpected)),
159                    }
160
161                    let key = match self.handshake_server_key {
162                        Some(k) => k,
163                        None => {
164                            return Err(CtxError::Bug(
165                                "Expected to have Server Key by now and was not guarded.",
166                            ))
167                        }
168                    };
169
170                    let nonce: [u8; 12] = match self.handshake_server_iv {
171                        None => {
172                            return Err(CtxError::Bug(
173                                "Expected to have Server Iv by now and was not guarded.",
174                            ))
175                        }
176                        Some(ref mut n) => match n.use_and_incr() {
177                            Some(cur) => cur,
178                            None => return Err(CtxError::ExhaustedIv),
179                        },
180                    };
181
182                    let cipher = Crypto::aead_chaha20poly1305(&key);
183
184                    let full_payload = rec.as_bytes();
185                    let full_payload_len = full_payload.len();
186
187                    let mut tag: [u8; 16] = [0; 16];
188
189                    let body_len = full_payload_len - 16;
190                    let mut body: [u8; 8192] = [0; 8192];
191
192                    body[0..body_len].copy_from_slice(&full_payload[0..body_len]);
193
194                    tag.copy_from_slice(&full_payload[body_len..body_len + 16]);
195
196                    let additional_data = rec.header_as_bytes();
197
198                    use ytls_traits::CryptoChaCha20Poly1305Processor;
199                    cipher
200                        .decrypt_in_place(&nonce, &additional_data, &mut body[0..body_len], &tag)
201                        .map_err(|_| CtxError::Rfc8446(Rfc8446Error::Decrypt))?;
202
203                    use ytls_record::{WrappedMsgType, WrappedRecord};
204                    let r = WrappedRecord::parse_server(self, &body[0..body_len])
205                        .map_err(|_| CtxError::Rfc8446(Rfc8446Error::Unexpected))?;
206
207                    let hashing_body = &body[0..body_len - 1];
208
209                    use ytls_record::HandshakeMsg;
210
211                    match r.msg() {
212                        WrappedMsgType::Alert(_alert) => {
213                            // do nothing with it for now
214                        }
215                        WrappedMsgType::Handshake(HandshakeMsg {
216                            msg: MsgType::EncryptedExtensions,
217                            ..
218                        }) => {
219                            // do nothing with it for now (we ensure it's 00 00)
220                            self.transcript.sha256_update(hashing_body);
221                        }
222                        WrappedMsgType::Handshake(HandshakeMsg {
223                            msg: MsgType::ServerCertificate,
224                            req_ctx: Some(0),
225                        }) => {
226                            self.transcript.sha256_update(hashing_body);
227                        }
228                        WrappedMsgType::Handshake(HandshakeMsg {
229                            msg: MsgType::ServerCertificateVerify,
230                            ..
231                        }) => {
232                            self.transcript.sha256_update(hashing_body);
233                        }
234                        WrappedMsgType::Handshake(HandshakeMsg {
235                            msg: MsgType::ServerFinished,
236                            ..
237                        }) => {
238                            self.transcript.sha256_update(hashing_body);
239
240                            let finish_hasher = self.transcript.sha256_fork();
241
242                            self.do_client_handshake_finished(lo)?;
243
244                            let hs_k: Tls13KeysHandshakeSha256<Crypto> = match self.key_schedule {
245                                Some(secrets) => Tls13KeysHandshakeSha256::from_secrets(
246                                    secrets.0, secrets.1, secrets.2,
247                                ),
248                                None => {
249                                    return Err(CtxError::Bug(
250                                        "Key schedule was not guarded for finish.",
251                                    ))
252                                }
253                            };
254
255                            let finish_handshake_hash = finish_hasher.sha256_finalize();
256
257                            let ap_k = hs_k.finished_handshake(&finish_handshake_hash);
258
259                            let mut server_application_iv: [u8; 12] = [0; 12];
260                            let mut server_application_key: [u8; 32] = [0; 32];
261                            let mut client_application_iv: [u8; 12] = [0; 12];
262                            let mut client_application_key: [u8; 32] = [0; 32];
263
264                            ap_k.application_server_key(&mut server_application_key);
265                            ap_k.application_server_iv(&mut server_application_iv);
266                            ap_k.application_client_key(&mut client_application_key);
267                            ap_k.application_client_iv(&mut client_application_iv);
268
269                            ks.store_ap_client_key(&client_application_key);
270                            ks.store_ap_client_iv(&client_application_iv);
271                            ks.store_ap_server_key(&server_application_key);
272                            ks.store_ap_server_iv(&server_application_iv);
273
274                            self.is_complete = true;
275                        }
276                        _ => {
277                            return Err(CtxError::Rfc8446(Rfc8446Error::Unexpected));
278                        }
279                    }
280                }
281                Content::Handshake(content) => {
282                    let msg = content.msg();
283
284                    match msg {
285                        MsgType::ServerHello(_h) => {
286                            if self.cur != HandshakeOrder::ClientHello {
287                                return Err(CtxError::Rfc8446(Rfc8446Error::Unexpected));
288                            }
289
290                            let server_pk = match prc.server_hello.pk_x25519 {
291                                Some(pk) => pk,
292                                None => return Err(CtxError::Rfc8446(Rfc8446Error::Unexpected)),
293                            };
294
295                            let mut x25519: Option<Crypto::X25519> = None;
296                            core::mem::swap(&mut x25519, &mut self.x25519);
297
298                            let x25519 = match x25519 {
299                                Some(x) => x,
300                                None => return Err(CtxError::Rfc8446(Rfc8446Error::Unexpected)),
301                            };
302
303                            let shared_secret = x25519.x25519_shared_secret(&server_pk);
304
305                            self.transcript.sha256_update(rec.as_bytes());
306                            let hello_transcript = self.transcript.sha256_fork();
307                            let hello_hash = hello_transcript.sha256_finalize();
308
309                            let k = Tls13Keys::<Crypto>::no_psk_with_crypto_and_sha256();
310                            let hs_k = k.dh_x25519(&shared_secret, &hello_hash);
311                            let mut server_handshake_iv: [u8; 12] = [0; 12];
312                            let mut server_handshake_key: [u8; 32] = [0; 32];
313                            let mut server_handshake_finished_key: [u8; 32] = [0; 32];
314                            hs_k.handshake_server_iv(&mut server_handshake_iv);
315                            hs_k.handshake_server_key(&mut server_handshake_key);
316                            hs_k.handshake_server_finished_key(&mut server_handshake_finished_key);
317
318                            self.handshake_server_key = Some(server_handshake_key);
319                            self.handshake_server_iv =
320                                Some(Nonce12::from_ks_iv(&server_handshake_iv));
321                            self.handshake_finished_server_key =
322                                Some(server_handshake_finished_key);
323
324                            let mut client_handshake_iv: [u8; 12] = [0; 12];
325                            let mut client_handshake_key: [u8; 32] = [0; 32];
326                            let mut client_handshake_finished_key: [u8; 32] = [0; 32];
327                            hs_k.handshake_client_iv(&mut client_handshake_iv);
328                            hs_k.handshake_client_key(&mut client_handshake_key);
329                            hs_k.handshake_client_finished_key(&mut client_handshake_finished_key);
330                            self.handshake_client_key = Some(client_handshake_key);
331                            self.handshake_client_iv =
332                                Some(Nonce12::from_ks_iv(&client_handshake_iv));
333                            self.handshake_finished_client_key =
334                                Some(client_handshake_finished_key);
335
336                            self.key_schedule = Some(hs_k.into_secrets());
337
338                            self.cur = HandshakeOrder::ServerHello;
339                        }
340                        _ => {
341                            return Err(CtxError::Rfc8446(Rfc8446Error::Unexpected));
342                        }
343                    }
344                }
345                Content::Alert(_alert) => {
346                    // do nothing with it for now
347                }
348            }
349
350            if remaining.len() == 0 {
351                break;
352            }
353
354            data = remaining;
355        }
356
357        li.left_buf_mark_discard_in(consumed);
358
359        if self.is_complete {
360            return Ok(Some(HandshakeComplete));
361        }
362
363        Ok(None)
364    }
365}