rustls/crypto/ring/
tls12.rs

1use alloc::boxed::Box;
2
3use super::ring_like::aead;
4use crate::crypto::KeyExchangeAlgorithm;
5use crate::crypto::cipher::{
6    AeadKey, InboundOpaqueMessage, Iv, KeyBlockShape, MessageDecrypter, MessageEncrypter,
7    NONCE_LEN, Nonce, Tls12AeadAlgorithm, UnsupportedOperationError, make_tls12_aad,
8};
9use crate::crypto::tls12::PrfUsingHmac;
10use crate::enums::{CipherSuite, SignatureScheme};
11use crate::error::Error;
12use crate::msgs::fragmenter::MAX_FRAGMENT_LEN;
13use crate::msgs::message::{
14    InboundPlainMessage, OutboundOpaqueMessage, OutboundPlainMessage, PrefixedPayload,
15};
16use crate::suites::{CipherSuiteCommon, ConnectionTrafficSecrets, SupportedCipherSuite};
17use crate::tls12::Tls12CipherSuite;
18
19/// The TLS1.2 ciphersuite TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256.
20pub static TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: SupportedCipherSuite =
21    SupportedCipherSuite::Tls12(&Tls12CipherSuite {
22        common: CipherSuiteCommon {
23            suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
24            hash_provider: &super::hash::SHA256,
25            confidentiality_limit: u64::MAX,
26        },
27        kx: KeyExchangeAlgorithm::ECDHE,
28        sign: TLS12_ECDSA_SCHEMES,
29        aead_alg: &ChaCha20Poly1305,
30        prf_provider: &PrfUsingHmac(&super::hmac::HMAC_SHA256),
31    });
32
33/// The TLS1.2 ciphersuite TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
34pub static TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: SupportedCipherSuite =
35    SupportedCipherSuite::Tls12(&Tls12CipherSuite {
36        common: CipherSuiteCommon {
37            suite: CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
38            hash_provider: &super::hash::SHA256,
39            confidentiality_limit: u64::MAX,
40        },
41        kx: KeyExchangeAlgorithm::ECDHE,
42        sign: TLS12_RSA_SCHEMES,
43        aead_alg: &ChaCha20Poly1305,
44        prf_provider: &PrfUsingHmac(&super::hmac::HMAC_SHA256),
45    });
46
47/// The TLS1.2 ciphersuite TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
48pub static TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite =
49    SupportedCipherSuite::Tls12(&Tls12CipherSuite {
50        common: CipherSuiteCommon {
51            suite: CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
52            hash_provider: &super::hash::SHA256,
53            confidentiality_limit: 1 << 24,
54        },
55        kx: KeyExchangeAlgorithm::ECDHE,
56        sign: TLS12_RSA_SCHEMES,
57        aead_alg: &AES128_GCM,
58        prf_provider: &PrfUsingHmac(&super::hmac::HMAC_SHA256),
59    });
60
61/// The TLS1.2 ciphersuite TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
62pub static TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite =
63    SupportedCipherSuite::Tls12(&Tls12CipherSuite {
64        common: CipherSuiteCommon {
65            suite: CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
66            hash_provider: &super::hash::SHA384,
67            confidentiality_limit: 1 << 24,
68        },
69        kx: KeyExchangeAlgorithm::ECDHE,
70        sign: TLS12_RSA_SCHEMES,
71        aead_alg: &AES256_GCM,
72        prf_provider: &PrfUsingHmac(&super::hmac::HMAC_SHA384),
73    });
74
75/// The TLS1.2 ciphersuite TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
76pub static TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite =
77    SupportedCipherSuite::Tls12(&Tls12CipherSuite {
78        common: CipherSuiteCommon {
79            suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
80            hash_provider: &super::hash::SHA256,
81            confidentiality_limit: 1 << 24,
82        },
83        kx: KeyExchangeAlgorithm::ECDHE,
84        sign: TLS12_ECDSA_SCHEMES,
85        aead_alg: &AES128_GCM,
86        prf_provider: &PrfUsingHmac(&super::hmac::HMAC_SHA256),
87    });
88
89/// The TLS1.2 ciphersuite TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
90pub static TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite =
91    SupportedCipherSuite::Tls12(&Tls12CipherSuite {
92        common: CipherSuiteCommon {
93            suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
94            hash_provider: &super::hash::SHA384,
95            confidentiality_limit: 1 << 24,
96        },
97        kx: KeyExchangeAlgorithm::ECDHE,
98        sign: TLS12_ECDSA_SCHEMES,
99        aead_alg: &AES256_GCM,
100        prf_provider: &PrfUsingHmac(&super::hmac::HMAC_SHA384),
101    });
102
103static TLS12_ECDSA_SCHEMES: &[SignatureScheme] = &[
104    SignatureScheme::ED25519,
105    SignatureScheme::ECDSA_NISTP521_SHA512,
106    SignatureScheme::ECDSA_NISTP384_SHA384,
107    SignatureScheme::ECDSA_NISTP256_SHA256,
108];
109
110static TLS12_RSA_SCHEMES: &[SignatureScheme] = &[
111    SignatureScheme::RSA_PSS_SHA512,
112    SignatureScheme::RSA_PSS_SHA384,
113    SignatureScheme::RSA_PSS_SHA256,
114    SignatureScheme::RSA_PKCS1_SHA512,
115    SignatureScheme::RSA_PKCS1_SHA384,
116    SignatureScheme::RSA_PKCS1_SHA256,
117];
118
119pub(crate) static AES128_GCM: GcmAlgorithm = GcmAlgorithm(&aead::AES_128_GCM);
120pub(crate) static AES256_GCM: GcmAlgorithm = GcmAlgorithm(&aead::AES_256_GCM);
121
122pub(crate) struct GcmAlgorithm(&'static aead::Algorithm);
123
124impl Tls12AeadAlgorithm for GcmAlgorithm {
125    fn decrypter(&self, dec_key: AeadKey, dec_iv: &[u8]) -> Box<dyn MessageDecrypter> {
126        let dec_key =
127            aead::LessSafeKey::new(aead::UnboundKey::new(self.0, dec_key.as_ref()).unwrap());
128
129        let mut ret = GcmMessageDecrypter {
130            dec_key,
131            dec_salt: [0u8; 4],
132        };
133
134        debug_assert_eq!(dec_iv.len(), 4);
135        ret.dec_salt.copy_from_slice(dec_iv);
136        Box::new(ret)
137    }
138
139    fn encrypter(
140        &self,
141        enc_key: AeadKey,
142        write_iv: &[u8],
143        explicit: &[u8],
144    ) -> Box<dyn MessageEncrypter> {
145        let enc_key =
146            aead::LessSafeKey::new(aead::UnboundKey::new(self.0, enc_key.as_ref()).unwrap());
147        let iv = gcm_iv(write_iv, explicit);
148        Box::new(GcmMessageEncrypter { enc_key, iv })
149    }
150
151    fn key_block_shape(&self) -> KeyBlockShape {
152        KeyBlockShape {
153            enc_key_len: self.0.key_len(),
154            fixed_iv_len: 4,
155            explicit_nonce_len: 8,
156        }
157    }
158
159    fn extract_keys(
160        &self,
161        key: AeadKey,
162        write_iv: &[u8],
163        explicit: &[u8],
164    ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError> {
165        let iv = gcm_iv(write_iv, explicit);
166        Ok(match self.0.key_len() {
167            16 => ConnectionTrafficSecrets::Aes128Gcm { key, iv },
168            32 => ConnectionTrafficSecrets::Aes256Gcm { key, iv },
169            _ => unreachable!(),
170        })
171    }
172
173    fn fips(&self) -> bool {
174        super::fips()
175    }
176}
177
178pub(crate) struct ChaCha20Poly1305;
179
180impl Tls12AeadAlgorithm for ChaCha20Poly1305 {
181    fn decrypter(&self, dec_key: AeadKey, iv: &[u8]) -> Box<dyn MessageDecrypter> {
182        let dec_key = aead::LessSafeKey::new(
183            aead::UnboundKey::new(&aead::CHACHA20_POLY1305, dec_key.as_ref()).unwrap(),
184        );
185        Box::new(ChaCha20Poly1305MessageDecrypter {
186            dec_key,
187            dec_offset: Iv::copy(iv),
188        })
189    }
190
191    fn encrypter(&self, enc_key: AeadKey, enc_iv: &[u8], _: &[u8]) -> Box<dyn MessageEncrypter> {
192        let enc_key = aead::LessSafeKey::new(
193            aead::UnboundKey::new(&aead::CHACHA20_POLY1305, enc_key.as_ref()).unwrap(),
194        );
195        Box::new(ChaCha20Poly1305MessageEncrypter {
196            enc_key,
197            enc_offset: Iv::copy(enc_iv),
198        })
199    }
200
201    fn key_block_shape(&self) -> KeyBlockShape {
202        KeyBlockShape {
203            enc_key_len: 32,
204            fixed_iv_len: 12,
205            explicit_nonce_len: 0,
206        }
207    }
208
209    fn extract_keys(
210        &self,
211        key: AeadKey,
212        iv: &[u8],
213        _explicit: &[u8],
214    ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError> {
215        // This should always be true because KeyBlockShape and the Iv nonce len are in agreement.
216        debug_assert_eq!(aead::NONCE_LEN, iv.len());
217        Ok(ConnectionTrafficSecrets::Chacha20Poly1305 {
218            key,
219            iv: Iv::new(iv[..].try_into().unwrap()),
220        })
221    }
222
223    fn fips(&self) -> bool {
224        false // not fips approved
225    }
226}
227
228/// A `MessageEncrypter` for AES-GCM AEAD ciphersuites. TLS 1.2 only.
229struct GcmMessageEncrypter {
230    enc_key: aead::LessSafeKey,
231    iv: Iv,
232}
233
234/// A `MessageDecrypter` for AES-GCM AEAD ciphersuites.  TLS1.2 only.
235struct GcmMessageDecrypter {
236    dec_key: aead::LessSafeKey,
237    dec_salt: [u8; 4],
238}
239
240const GCM_EXPLICIT_NONCE_LEN: usize = 8;
241const GCM_OVERHEAD: usize = GCM_EXPLICIT_NONCE_LEN + 16;
242
243impl MessageDecrypter for GcmMessageDecrypter {
244    fn decrypt<'a>(
245        &mut self,
246        mut msg: InboundOpaqueMessage<'a>,
247        seq: u64,
248    ) -> Result<InboundPlainMessage<'a>, Error> {
249        let payload = &msg.payload;
250        if payload.len() < GCM_OVERHEAD {
251            return Err(Error::DecryptError);
252        }
253
254        let nonce = {
255            let mut nonce = [0u8; 12];
256            nonce[..4].copy_from_slice(&self.dec_salt);
257            nonce[4..].copy_from_slice(&payload[..8]);
258            aead::Nonce::assume_unique_for_key(nonce)
259        };
260
261        let aad = aead::Aad::from(make_tls12_aad(
262            seq,
263            msg.typ,
264            msg.version,
265            payload.len() - GCM_OVERHEAD,
266        ));
267
268        let payload = &mut msg.payload;
269        let plain_len = self
270            .dec_key
271            .open_within(nonce, aad, payload, GCM_EXPLICIT_NONCE_LEN..)
272            .map_err(|_| Error::DecryptError)?
273            .len();
274
275        if plain_len > MAX_FRAGMENT_LEN {
276            return Err(Error::PeerSentOversizedRecord);
277        }
278
279        payload.truncate(plain_len);
280        Ok(msg.into_plain_message())
281    }
282}
283
284impl MessageEncrypter for GcmMessageEncrypter {
285    fn encrypt(
286        &mut self,
287        msg: OutboundPlainMessage<'_>,
288        seq: u64,
289    ) -> Result<OutboundOpaqueMessage, Error> {
290        let total_len = self.encrypted_payload_len(msg.payload.len());
291        let mut payload = PrefixedPayload::with_capacity(total_len);
292
293        let nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.iv, seq).0);
294        let aad = aead::Aad::from(make_tls12_aad(seq, msg.typ, msg.version, msg.payload.len()));
295        payload.extend_from_slice(&nonce.as_ref()[4..]);
296        payload.extend_from_chunks(&msg.payload);
297
298        self.enc_key
299            .seal_in_place_separate_tag(nonce, aad, &mut payload.as_mut()[GCM_EXPLICIT_NONCE_LEN..])
300            .map(|tag| payload.extend_from_slice(tag.as_ref()))
301            .map_err(|_| Error::EncryptError)?;
302
303        Ok(OutboundOpaqueMessage::new(msg.typ, msg.version, payload))
304    }
305
306    fn encrypted_payload_len(&self, payload_len: usize) -> usize {
307        payload_len + GCM_EXPLICIT_NONCE_LEN + self.enc_key.algorithm().tag_len()
308    }
309}
310
311/// The RFC7905/RFC7539 ChaCha20Poly1305 construction.
312/// This implementation does the AAD construction required in TLS1.2.
313/// TLS1.3 uses `TLS13MessageEncrypter`.
314struct ChaCha20Poly1305MessageEncrypter {
315    enc_key: aead::LessSafeKey,
316    enc_offset: Iv,
317}
318
319/// The RFC7905/RFC7539 ChaCha20Poly1305 construction.
320/// This implementation does the AAD construction required in TLS1.2.
321/// TLS1.3 uses `TLS13MessageDecrypter`.
322struct ChaCha20Poly1305MessageDecrypter {
323    dec_key: aead::LessSafeKey,
324    dec_offset: Iv,
325}
326
327const CHACHAPOLY1305_OVERHEAD: usize = 16;
328
329impl MessageDecrypter for ChaCha20Poly1305MessageDecrypter {
330    fn decrypt<'a>(
331        &mut self,
332        mut msg: InboundOpaqueMessage<'a>,
333        seq: u64,
334    ) -> Result<InboundPlainMessage<'a>, Error> {
335        let payload = &msg.payload;
336
337        if payload.len() < CHACHAPOLY1305_OVERHEAD {
338            return Err(Error::DecryptError);
339        }
340
341        let nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.dec_offset, seq).0);
342        let aad = aead::Aad::from(make_tls12_aad(
343            seq,
344            msg.typ,
345            msg.version,
346            payload.len() - CHACHAPOLY1305_OVERHEAD,
347        ));
348
349        let payload = &mut msg.payload;
350        let plain_len = self
351            .dec_key
352            .open_in_place(nonce, aad, payload)
353            .map_err(|_| Error::DecryptError)?
354            .len();
355
356        if plain_len > MAX_FRAGMENT_LEN {
357            return Err(Error::PeerSentOversizedRecord);
358        }
359
360        payload.truncate(plain_len);
361        Ok(msg.into_plain_message())
362    }
363}
364
365impl MessageEncrypter for ChaCha20Poly1305MessageEncrypter {
366    fn encrypt(
367        &mut self,
368        msg: OutboundPlainMessage<'_>,
369        seq: u64,
370    ) -> Result<OutboundOpaqueMessage, Error> {
371        let total_len = self.encrypted_payload_len(msg.payload.len());
372        let mut payload = PrefixedPayload::with_capacity(total_len);
373
374        let nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.enc_offset, seq).0);
375        let aad = aead::Aad::from(make_tls12_aad(seq, msg.typ, msg.version, msg.payload.len()));
376        payload.extend_from_chunks(&msg.payload);
377
378        self.enc_key
379            .seal_in_place_append_tag(nonce, aad, &mut payload)
380            .map_err(|_| Error::EncryptError)?;
381
382        Ok(OutboundOpaqueMessage::new(msg.typ, msg.version, payload))
383    }
384
385    fn encrypted_payload_len(&self, payload_len: usize) -> usize {
386        payload_len + self.enc_key.algorithm().tag_len()
387    }
388}
389
390fn gcm_iv(write_iv: &[u8], explicit: &[u8]) -> Iv {
391    debug_assert_eq!(write_iv.len(), 4);
392    debug_assert_eq!(explicit.len(), 8);
393
394    // The GCM nonce is constructed from a 32-bit 'salt' derived
395    // from the master-secret, and a 64-bit explicit part,
396    // with no specified construction.  Thanks for that.
397    //
398    // We use the same construction as TLS1.3/ChaCha20Poly1305:
399    // a starting point extracted from the key block, xored with
400    // the sequence number.
401    let mut iv = [0; NONCE_LEN];
402    iv[..4].copy_from_slice(write_iv);
403    iv[4..].copy_from_slice(explicit);
404
405    Iv::new(iv)
406}