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