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