rustls/crypto/aws_lc_rs/
tls12.rs

1use alloc::boxed::Box;
2
3use aws_lc_rs::{aead, tls_prf};
4use zeroize::Zeroizing;
5
6use crate::crypto::cipher::{
7    AeadKey, InboundOpaqueMessage, Iv, KeyBlockShape, MessageDecrypter, MessageEncrypter,
8    NONCE_LEN, Nonce, Tls12AeadAlgorithm, UnsupportedOperationError, make_tls12_aad,
9};
10use crate::crypto::tls12::{Prf, PrfSecret};
11use crate::crypto::{ActiveKeyExchange, KeyExchangeAlgorithm, SharedSecret};
12use crate::enums::{CipherSuite, SignatureScheme};
13use crate::error::Error;
14use crate::msgs::fragmenter::MAX_FRAGMENT_LEN;
15use crate::msgs::message::{
16    InboundPlainMessage, OutboundOpaqueMessage, OutboundPlainMessage, PrefixedPayload,
17};
18use crate::suites::{CipherSuiteCommon, ConnectionTrafficSecrets, SupportedCipherSuite};
19use crate::tls12::Tls12CipherSuite;
20use crate::version::{TLS12, TLS12_VERSION};
21
22/// The TLS1.2 ciphersuite TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256.
23pub static TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: SupportedCipherSuite =
24    SupportedCipherSuite::Tls12(&Tls12CipherSuite {
25        common: CipherSuiteCommon {
26            suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
27            hash_provider: &super::hash::SHA256,
28            confidentiality_limit: u64::MAX,
29        },
30        protocol_version: TLS12_VERSION,
31        kx: KeyExchangeAlgorithm::ECDHE,
32        sign: TLS12_ECDSA_SCHEMES,
33        aead_alg: &ChaCha20Poly1305,
34        prf_provider: &Tls12Prf(&tls_prf::P_SHA256),
35    });
36
37/// The TLS1.2 ciphersuite TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
38pub static TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: SupportedCipherSuite =
39    SupportedCipherSuite::Tls12(&Tls12CipherSuite {
40        common: CipherSuiteCommon {
41            suite: CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
42            hash_provider: &super::hash::SHA256,
43            confidentiality_limit: u64::MAX,
44        },
45        protocol_version: TLS12_VERSION,
46        kx: KeyExchangeAlgorithm::ECDHE,
47        sign: TLS12_RSA_SCHEMES,
48        aead_alg: &ChaCha20Poly1305,
49        prf_provider: &Tls12Prf(&tls_prf::P_SHA256),
50    });
51
52/// The TLS1.2 ciphersuite TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
53pub static TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite =
54    SupportedCipherSuite::Tls12(&Tls12CipherSuite {
55        common: CipherSuiteCommon {
56            suite: CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
57            hash_provider: &super::hash::SHA256,
58            confidentiality_limit: 1 << 24,
59        },
60        protocol_version: TLS12_VERSION,
61        kx: KeyExchangeAlgorithm::ECDHE,
62        sign: TLS12_RSA_SCHEMES,
63        aead_alg: &AES128_GCM,
64        prf_provider: &Tls12Prf(&tls_prf::P_SHA256),
65    });
66
67/// The TLS1.2 ciphersuite TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
68pub static TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite =
69    SupportedCipherSuite::Tls12(&Tls12CipherSuite {
70        common: CipherSuiteCommon {
71            suite: CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
72            hash_provider: &super::hash::SHA384,
73            confidentiality_limit: 1 << 24,
74        },
75        protocol_version: TLS12_VERSION,
76        kx: KeyExchangeAlgorithm::ECDHE,
77        sign: TLS12_RSA_SCHEMES,
78        aead_alg: &AES256_GCM,
79        prf_provider: &Tls12Prf(&tls_prf::P_SHA384),
80    });
81
82/// The TLS1.2 ciphersuite TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
83pub static TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite =
84    SupportedCipherSuite::Tls12(&Tls12CipherSuite {
85        common: CipherSuiteCommon {
86            suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
87            hash_provider: &super::hash::SHA256,
88            confidentiality_limit: 1 << 24,
89        },
90        protocol_version: TLS12_VERSION,
91        kx: KeyExchangeAlgorithm::ECDHE,
92        sign: TLS12_ECDSA_SCHEMES,
93        aead_alg: &AES128_GCM,
94        prf_provider: &Tls12Prf(&tls_prf::P_SHA256),
95    });
96
97/// The TLS1.2 ciphersuite TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
98pub static TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite =
99    SupportedCipherSuite::Tls12(&Tls12CipherSuite {
100        common: CipherSuiteCommon {
101            suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
102            hash_provider: &super::hash::SHA384,
103            confidentiality_limit: 1 << 24,
104        },
105        protocol_version: TLS12_VERSION,
106        kx: KeyExchangeAlgorithm::ECDHE,
107        sign: TLS12_ECDSA_SCHEMES,
108        aead_alg: &AES256_GCM,
109        prf_provider: &Tls12Prf(&tls_prf::P_SHA384),
110    });
111
112static TLS12_ECDSA_SCHEMES: &[SignatureScheme] = &[
113    SignatureScheme::ED25519,
114    SignatureScheme::ECDSA_NISTP521_SHA512,
115    SignatureScheme::ECDSA_NISTP384_SHA384,
116    SignatureScheme::ECDSA_NISTP256_SHA256,
117];
118
119static TLS12_RSA_SCHEMES: &[SignatureScheme] = &[
120    SignatureScheme::RSA_PSS_SHA512,
121    SignatureScheme::RSA_PSS_SHA384,
122    SignatureScheme::RSA_PSS_SHA256,
123    SignatureScheme::RSA_PKCS1_SHA512,
124    SignatureScheme::RSA_PKCS1_SHA384,
125    SignatureScheme::RSA_PKCS1_SHA256,
126];
127
128pub(crate) static AES128_GCM: GcmAlgorithm = GcmAlgorithm(&aead::AES_128_GCM);
129pub(crate) static AES256_GCM: GcmAlgorithm = GcmAlgorithm(&aead::AES_256_GCM);
130
131pub(crate) struct GcmAlgorithm(&'static aead::Algorithm);
132
133impl Tls12AeadAlgorithm for GcmAlgorithm {
134    fn decrypter(&self, dec_key: AeadKey, dec_iv: &[u8]) -> Box<dyn MessageDecrypter> {
135        // safety: see `encrypter()`.
136        let dec_key =
137            aead::TlsRecordOpeningKey::new(self.0, aead::TlsProtocolId::TLS12, dec_key.as_ref())
138                .unwrap();
139
140        let mut ret = GcmMessageDecrypter {
141            dec_key,
142            dec_salt: [0u8; 4],
143        };
144
145        debug_assert_eq!(dec_iv.len(), 4);
146        ret.dec_salt.copy_from_slice(dec_iv);
147        Box::new(ret)
148    }
149
150    fn encrypter(
151        &self,
152        enc_key: AeadKey,
153        write_iv: &[u8],
154        explicit: &[u8],
155    ) -> Box<dyn MessageEncrypter> {
156        // safety: `TlsRecordSealingKey::new` fails if
157        // - `enc_key`'s length is wrong for `algorithm`.  But the length is defined by
158        //   `algorithm.key_len()` in `key_block_shape()`, below.
159        // - `algorithm` is not supported: but `AES_128_GCM` and `AES_256_GCM` is.
160        // thus, this `unwrap()` is unreachable.
161        //
162        // `TlsProtocolId::TLS13` is deliberate: we reuse the nonce construction from
163        // RFC7905 and TLS13: a random starting point, XOR'd with the sequence number.  This means
164        // `TlsProtocolId::TLS12` (which wants to see a plain sequence number) is unsuitable.
165        //
166        // The most important property is that nonce is unique per key, which is satisfied by
167        // this construction, even if the nonce is not monotonically increasing.
168        let enc_key =
169            aead::TlsRecordSealingKey::new(self.0, aead::TlsProtocolId::TLS13, enc_key.as_ref())
170                .unwrap();
171        let iv = gcm_iv(write_iv, explicit);
172        Box::new(GcmMessageEncrypter { enc_key, iv })
173    }
174
175    fn key_block_shape(&self) -> KeyBlockShape {
176        KeyBlockShape {
177            enc_key_len: self.0.key_len(),
178            fixed_iv_len: 4,
179            explicit_nonce_len: 8,
180        }
181    }
182
183    fn extract_keys(
184        &self,
185        key: AeadKey,
186        write_iv: &[u8],
187        explicit: &[u8],
188    ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError> {
189        let iv = gcm_iv(write_iv, explicit);
190        Ok(match self.0.key_len() {
191            16 => ConnectionTrafficSecrets::Aes128Gcm { key, iv },
192            32 => ConnectionTrafficSecrets::Aes256Gcm { key, iv },
193            _ => unreachable!(),
194        })
195    }
196
197    fn fips(&self) -> bool {
198        super::fips()
199    }
200}
201
202pub(crate) struct ChaCha20Poly1305;
203
204impl Tls12AeadAlgorithm for ChaCha20Poly1305 {
205    fn decrypter(&self, dec_key: AeadKey, iv: &[u8]) -> Box<dyn MessageDecrypter> {
206        let dec_key = aead::LessSafeKey::new(
207            aead::UnboundKey::new(&aead::CHACHA20_POLY1305, dec_key.as_ref()).unwrap(),
208        );
209        Box::new(ChaCha20Poly1305MessageDecrypter {
210            dec_key,
211            dec_offset: Iv::copy(iv),
212        })
213    }
214
215    fn encrypter(&self, enc_key: AeadKey, enc_iv: &[u8], _: &[u8]) -> Box<dyn MessageEncrypter> {
216        let enc_key = aead::LessSafeKey::new(
217            aead::UnboundKey::new(&aead::CHACHA20_POLY1305, enc_key.as_ref()).unwrap(),
218        );
219        Box::new(ChaCha20Poly1305MessageEncrypter {
220            enc_key,
221            enc_offset: Iv::copy(enc_iv),
222        })
223    }
224
225    fn key_block_shape(&self) -> KeyBlockShape {
226        KeyBlockShape {
227            enc_key_len: 32,
228            fixed_iv_len: 12,
229            explicit_nonce_len: 0,
230        }
231    }
232
233    fn extract_keys(
234        &self,
235        key: AeadKey,
236        iv: &[u8],
237        _explicit: &[u8],
238    ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError> {
239        // This should always be true because KeyBlockShape and the Iv nonce len are in agreement.
240        debug_assert_eq!(aead::NONCE_LEN, iv.len());
241        Ok(ConnectionTrafficSecrets::Chacha20Poly1305 {
242            key,
243            iv: Iv::new(iv[..].try_into().unwrap()),
244        })
245    }
246
247    fn fips(&self) -> bool {
248        false // not FIPS approved
249    }
250}
251
252/// A `MessageEncrypter` for AES-GCM AEAD ciphersuites. TLS 1.2 only.
253struct GcmMessageEncrypter {
254    enc_key: aead::TlsRecordSealingKey,
255    iv: Iv,
256}
257
258/// A `MessageDecrypter` for AES-GCM AEAD ciphersuites.  TLS1.2 only.
259struct GcmMessageDecrypter {
260    dec_key: aead::TlsRecordOpeningKey,
261    dec_salt: [u8; 4],
262}
263
264const GCM_EXPLICIT_NONCE_LEN: usize = 8;
265const GCM_OVERHEAD: usize = GCM_EXPLICIT_NONCE_LEN + 16;
266
267impl MessageDecrypter for GcmMessageDecrypter {
268    fn decrypt<'a>(
269        &mut self,
270        mut msg: InboundOpaqueMessage<'a>,
271        seq: u64,
272    ) -> Result<InboundPlainMessage<'a>, Error> {
273        let payload = &msg.payload;
274        if payload.len() < GCM_OVERHEAD {
275            return Err(Error::DecryptError);
276        }
277
278        let nonce = {
279            let mut nonce = [0u8; 12];
280            nonce[..4].copy_from_slice(&self.dec_salt);
281            nonce[4..].copy_from_slice(&payload[..8]);
282            aead::Nonce::assume_unique_for_key(nonce)
283        };
284
285        let aad = aead::Aad::from(make_tls12_aad(
286            seq,
287            msg.typ,
288            msg.version,
289            payload.len() - GCM_OVERHEAD,
290        ));
291
292        let payload = &mut msg.payload;
293        let plain_len = self
294            .dec_key
295            .open_in_place(nonce, aad, &mut payload[GCM_EXPLICIT_NONCE_LEN..])
296            .map_err(|_| Error::DecryptError)?
297            .len();
298
299        if plain_len > MAX_FRAGMENT_LEN {
300            return Err(Error::PeerSentOversizedRecord);
301        }
302
303        Ok(
304            msg.into_plain_message_range(
305                GCM_EXPLICIT_NONCE_LEN..GCM_EXPLICIT_NONCE_LEN + plain_len,
306            ),
307        )
308    }
309}
310
311impl MessageEncrypter for GcmMessageEncrypter {
312    fn encrypt(
313        &mut self,
314        msg: OutboundPlainMessage<'_>,
315        seq: u64,
316    ) -> Result<OutboundOpaqueMessage, Error> {
317        let total_len = self.encrypted_payload_len(msg.payload.len());
318        let mut payload = PrefixedPayload::with_capacity(total_len);
319
320        let nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.iv, seq).0);
321        let aad = aead::Aad::from(make_tls12_aad(seq, msg.typ, msg.version, msg.payload.len()));
322        payload.extend_from_slice(&nonce.as_ref()[4..]);
323        payload.extend_from_chunks(&msg.payload);
324
325        self.enc_key
326            .seal_in_place_separate_tag(nonce, aad, &mut payload.as_mut()[GCM_EXPLICIT_NONCE_LEN..])
327            .map(|tag| payload.extend_from_slice(tag.as_ref()))
328            .map_err(|_| Error::EncryptError)?;
329
330        Ok(OutboundOpaqueMessage::new(msg.typ, msg.version, payload))
331    }
332
333    fn encrypted_payload_len(&self, payload_len: usize) -> usize {
334        payload_len + GCM_EXPLICIT_NONCE_LEN + self.enc_key.algorithm().tag_len()
335    }
336}
337
338/// The RFC7905/RFC7539 ChaCha20Poly1305 construction.
339/// This implementation does the AAD construction required in TLS1.2.
340/// TLS1.3 uses `TLS13MessageEncrypter`.
341struct ChaCha20Poly1305MessageEncrypter {
342    enc_key: aead::LessSafeKey,
343    enc_offset: Iv,
344}
345
346/// The RFC7905/RFC7539 ChaCha20Poly1305 construction.
347/// This implementation does the AAD construction required in TLS1.2.
348/// TLS1.3 uses `TLS13MessageDecrypter`.
349struct ChaCha20Poly1305MessageDecrypter {
350    dec_key: aead::LessSafeKey,
351    dec_offset: Iv,
352}
353
354const CHACHAPOLY1305_OVERHEAD: usize = 16;
355
356impl MessageDecrypter for ChaCha20Poly1305MessageDecrypter {
357    fn decrypt<'a>(
358        &mut self,
359        mut msg: InboundOpaqueMessage<'a>,
360        seq: u64,
361    ) -> Result<InboundPlainMessage<'a>, Error> {
362        let payload = &msg.payload;
363
364        if payload.len() < CHACHAPOLY1305_OVERHEAD {
365            return Err(Error::DecryptError);
366        }
367
368        let nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.dec_offset, seq).0);
369        let aad = aead::Aad::from(make_tls12_aad(
370            seq,
371            msg.typ,
372            msg.version,
373            payload.len() - CHACHAPOLY1305_OVERHEAD,
374        ));
375
376        let payload = &mut msg.payload;
377        let plain_len = self
378            .dec_key
379            .open_in_place(nonce, aad, payload)
380            .map_err(|_| Error::DecryptError)?
381            .len();
382
383        if plain_len > MAX_FRAGMENT_LEN {
384            return Err(Error::PeerSentOversizedRecord);
385        }
386
387        payload.truncate(plain_len);
388        Ok(msg.into_plain_message())
389    }
390}
391
392impl MessageEncrypter for ChaCha20Poly1305MessageEncrypter {
393    fn encrypt(
394        &mut self,
395        msg: OutboundPlainMessage<'_>,
396        seq: u64,
397    ) -> Result<OutboundOpaqueMessage, Error> {
398        let total_len = self.encrypted_payload_len(msg.payload.len());
399        let mut payload = PrefixedPayload::with_capacity(total_len);
400
401        let nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.enc_offset, seq).0);
402        let aad = aead::Aad::from(make_tls12_aad(seq, msg.typ, msg.version, msg.payload.len()));
403        payload.extend_from_chunks(&msg.payload);
404
405        self.enc_key
406            .seal_in_place_append_tag(nonce, aad, &mut payload)
407            .map_err(|_| Error::EncryptError)?;
408
409        Ok(OutboundOpaqueMessage::new(msg.typ, msg.version, payload))
410    }
411
412    fn encrypted_payload_len(&self, payload_len: usize) -> usize {
413        payload_len + self.enc_key.algorithm().tag_len()
414    }
415}
416
417fn gcm_iv(write_iv: &[u8], explicit: &[u8]) -> Iv {
418    debug_assert_eq!(write_iv.len(), 4);
419    debug_assert_eq!(explicit.len(), 8);
420
421    // The GCM nonce is constructed from a 32-bit 'salt' derived
422    // from the master-secret, and a 64-bit explicit part,
423    // with no specified construction.  Thanks for that.
424    //
425    // We use the same construction as TLS1.3/ChaCha20Poly1305:
426    // a starting point extracted from the key block, xored with
427    // the sequence number.
428    let mut iv = [0; NONCE_LEN];
429    iv[..4].copy_from_slice(write_iv);
430    iv[4..].copy_from_slice(explicit);
431
432    Iv::new(iv)
433}
434
435struct Tls12Prf(&'static tls_prf::Algorithm);
436
437impl Prf for Tls12Prf {
438    fn for_key_exchange(
439        &self,
440        output: &mut [u8; 48],
441        kx: Box<dyn ActiveKeyExchange>,
442        peer_pub_key: &[u8],
443        label: &[u8],
444        seed: &[u8],
445    ) -> Result<(), Error> {
446        Tls12PrfSecret {
447            alg: self.0,
448            secret: Secret::KeyExchange(kx.complete_for_tls_version(peer_pub_key, &TLS12)?),
449        }
450        .prf(output, label, seed);
451        Ok(())
452    }
453
454    fn new_secret(&self, secret: &[u8; 48]) -> Box<dyn PrfSecret> {
455        Box::new(Tls12PrfSecret {
456            alg: self.0,
457            secret: Secret::Master(Zeroizing::new(*secret)),
458        })
459    }
460
461    fn fips(&self) -> bool {
462        super::fips()
463    }
464}
465
466// nb: we can't put a `tls_prf::Secret` in here because it is
467// consumed by `tls_prf::Secret::derive()`
468struct Tls12PrfSecret {
469    alg: &'static tls_prf::Algorithm,
470    secret: Secret,
471}
472
473impl PrfSecret for Tls12PrfSecret {
474    fn prf(&self, output: &mut [u8], label: &[u8], seed: &[u8]) {
475        // safety:
476        // - [1] is safe because our caller guarantees `secret` is non-empty; this is
477        //   the only documented error case.
478        // - [2] is safe in practice because the only failure from `derive()` is due
479        //   to zero `output.len()`; this is outlawed at higher levels
480        let derived = tls_prf::Secret::new(self.alg, self.secret.as_ref())
481            .unwrap() // [1]
482            .derive(label, seed, output.len())
483            .unwrap(); // [2]
484        output.copy_from_slice(derived.as_ref());
485    }
486}
487
488enum Secret {
489    Master(Zeroizing<[u8; 48]>),
490    KeyExchange(SharedSecret),
491}
492
493impl AsRef<[u8]> for Secret {
494    fn as_ref(&self) -> &[u8] {
495        match self {
496            Self::Master(ms) => ms.as_ref(),
497            Self::KeyExchange(kx) => kx.secret_bytes(),
498        }
499    }
500}