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