Skip to main content

ytls_server/server_ctx/
s_application.rs

1//! yTLS Server Application Ctx
2
3use crate::{CtxError, Rfc8446Error};
4use ytls_traits::CtxApplicationProcessor;
5use ytls_traits::ShutdownComplete;
6use ytls_traits::{TlsLeftIn, TlsLeftOut, TlsRight};
7
8use ytls_traits::CryptoConfig;
9use ytls_traits::SecretStore;
10
11use ytls_record::Content;
12use ytls_record::Record;
13use ytls_util::Nonce12;
14
15#[cfg(feature = "zeroize")]
16use zeroize::{Zeroize, ZeroizeOnDrop};
17
18/// yTLS Server Application Ctx
19#[cfg_attr(feature = "zeroize", derive(Zeroize, ZeroizeOnDrop))]
20pub struct ServerApplicationCtx<Crypto> {
21    //crypto: Crypto,
22    application_server_key: [u8; 32],
23    application_client_key: [u8; 32],
24    application_server_iv: Nonce12,
25    application_client_iv: Nonce12,
26    _pt: core::marker::PhantomData<Crypto>,
27}
28
29impl<Crypto> ServerApplicationCtx<Crypto>
30where
31    Crypto: CryptoConfig,
32{
33    pub fn with_required<S: SecretStore>(_crypto: Crypto, s: &S) -> Self {
34        let mut application_server_key: [u8; 32] = [0; 32];
35        let mut application_client_key: [u8; 32] = [0; 32];
36        let mut application_server_iv_raw: [u8; 12] = [0; 12];
37        let mut application_client_iv_raw: [u8; 12] = [0; 12];
38
39        application_server_key.copy_from_slice(s.load_ap_server_key());
40        application_client_key.copy_from_slice(s.load_ap_client_key());
41        application_server_iv_raw.copy_from_slice(s.load_ap_server_iv());
42        application_client_iv_raw.copy_from_slice(s.load_ap_client_iv());
43
44        let application_server_iv = Nonce12::from_ks_iv(&application_server_iv_raw);
45        let application_client_iv = Nonce12::from_ks_iv(&application_client_iv_raw);
46
47        Self {
48            _pt: core::marker::PhantomData,
49            application_server_key,
50            application_client_key,
51            application_server_iv,
52            application_client_iv,
53        }
54    }
55}
56
57impl<Crypto> CtxApplicationProcessor for ServerApplicationCtx<Crypto>
58where
59    Crypto: CryptoConfig,
60{
61    type Error = CtxError;
62
63    fn spin_application<Li: TlsLeftIn, Lo: TlsLeftOut, R: TlsRight>(
64        &mut self,
65        li: &mut Li,
66        lo: &mut Lo,
67        right: &mut R,
68    ) -> Result<Option<ShutdownComplete>, Self::Error> {
69        let init_data = li.left_buf_in();
70        let init_len = init_data.len();
71        let mut data = init_data;
72
73        if init_len == 0 {
74            return Ok(None);
75        }
76
77        #[allow(unused_assignments)]
78        let mut consumed = 0;
79
80        loop {
81            let (rec, remaining) =
82                Record::parse_client_appdata(data).map_err(|e| CtxError::Record(e))?;
83
84            consumed = init_len - remaining.len();
85
86            if let Content::ApplicationData = rec.content() {
87                let key = self.application_client_key;
88                let nonce: [u8; 12] = match self.application_client_iv.use_and_incr() {
89                    Some(cur) => cur,
90                    None => return Err(CtxError::ExhaustedIv),
91                };
92
93                let cipher = Crypto::aead_chaha20poly1305(&key);
94                let full_payload = rec.as_bytes();
95                let full_payload_len = full_payload.len();
96                let mut tag: [u8; 16] = [0; 16];
97
98                let body_len = full_payload_len - 16;
99                let mut body: [u8; 8192] = [0; 8192];
100                body[0..body_len].copy_from_slice(&full_payload[0..body_len]);
101                tag.copy_from_slice(&full_payload[body_len..body_len + 16]);
102                let additional_data = rec.header_as_bytes();
103                use ytls_traits::CryptoChaCha20Poly1305Processor;
104                cipher
105                    .decrypt_in_place(&nonce, &additional_data, &mut body[0..body_len], &tag)
106                    .map_err(|_| CtxError::Rfc8446(Rfc8446Error::Decrypt))?;
107
108                right.on_decrypted(&body[0..body_len - 1]);
109
110                let d = right.on_encrypt();
111
112                if d.len() > 0 {
113                    let server_key = self.application_server_key;
114                    let server_nonce: [u8; 12] = match self.application_server_iv.use_and_incr() {
115                        Some(cur) => cur,
116                        None => return Err(CtxError::ExhaustedIv),
117                    };
118
119                    use ytls_record::WrappedAppStaticRecordBuilder;
120                    use ytls_traits::WrappedApplicationBuilder;
121
122                    let mut record_encrypt =
123                        WrappedAppStaticRecordBuilder::<8192>::application_data(d)
124                            .map_err(CtxError::Builder)?;
125
126                    let cipher = Crypto::aead_chaha20poly1305(&server_key);
127
128                    // TODO: transcript
129                    let tag = if let Ok([additional_data, encrypt_payload]) =
130                        record_encrypt.as_disjoint_mut_for_aead()
131                    {
132                        cipher
133                            .encrypt_in_place(
134                                &server_nonce,
135                                &additional_data,
136                                encrypt_payload.as_mut(),
137                            )
138                            .map_err(|_| CtxError::Bug("Encrypt failure."))?
139                    } else {
140                        return Err(CtxError::Bug(
141                            "Disjoint for AEAD failed at Application data.",
142                        ));
143                    };
144                    record_encrypt.set_auth_tag(&tag);
145
146                    lo.send_record_out(record_encrypt.as_encoded_bytes());
147                }
148            }
149
150            if remaining.len() == 0 {
151                break;
152            }
153
154            data = remaining;
155        }
156        li.left_buf_mark_discard_in(consumed);
157
158        Ok(None)
159    }
160}