rustls_openssl/
tls13.rs

1use crate::aead;
2use crate::hash::{SHA256, SHA384};
3use crate::hkdf::Hkdf;
4use crate::quic;
5use rustls::crypto::CipherSuiteCommon;
6use rustls::crypto::cipher::{
7    AeadKey, InboundOpaqueMessage, InboundPlainMessage, Iv, MessageDecrypter, MessageEncrypter,
8    Nonce, OutboundOpaqueMessage, OutboundPlainMessage, PrefixedPayload, Tls13AeadAlgorithm,
9    UnsupportedOperationError, make_tls13_aad,
10};
11use rustls::{
12    CipherSuite, ConnectionTrafficSecrets, Error, SupportedCipherSuite, Tls13CipherSuite,
13};
14
15/// The TLS1.3 ciphersuite `TLS_CHACHA20_POLY1305_SHA256`
16#[cfg(all(chacha, not(feature = "fips")))]
17pub static TLS13_CHACHA20_POLY1305_SHA256: SupportedCipherSuite =
18    SupportedCipherSuite::Tls13(TLS13_CHACHA20_POLY1305_SHA256_INTERNAL);
19
20#[cfg(all(chacha, not(feature = "fips")))]
21pub static TLS13_CHACHA20_POLY1305_SHA256_INTERNAL: &Tls13CipherSuite = &Tls13CipherSuite {
22    common: CipherSuiteCommon {
23        suite: CipherSuite::TLS13_CHACHA20_POLY1305_SHA256,
24        hash_provider: &SHA256,
25        confidentiality_limit: u64::MAX,
26    },
27    hkdf_provider: &Hkdf(SHA256),
28    aead_alg: &aead::Algorithm::ChaCha20Poly1305,
29    quic: Some(&quic::KeyBuilder {
30        packet_algo: aead::Algorithm::ChaCha20Poly1305,
31        header_algo: quic::HeaderProtectionAlgorithm::ChaCha20,
32        // ref: <https://datatracker.ietf.org/doc/html/rfc9001#section-6.6>
33        confidentiality_limit: u64::MAX,
34        // ref: <https://datatracker.ietf.org/doc/html/rfc9001#section-6.6>
35        integrity_limit: 1 << 36,
36    }),
37};
38
39/// The TLS1.3 ciphersuite `TLS_AES_256_GCM_SHA384`
40pub static TLS13_AES_256_GCM_SHA384: SupportedCipherSuite =
41    SupportedCipherSuite::Tls13(&Tls13CipherSuite {
42        common: CipherSuiteCommon {
43            suite: CipherSuite::TLS13_AES_256_GCM_SHA384,
44            hash_provider: &SHA384,
45            confidentiality_limit: 1 << 23,
46        },
47        hkdf_provider: &Hkdf(SHA384),
48        aead_alg: &aead::Algorithm::Aes256Gcm,
49        quic: Some(&quic::KeyBuilder {
50            packet_algo: aead::Algorithm::Aes256Gcm,
51            header_algo: quic::HeaderProtectionAlgorithm::Aes256,
52            // ref: <https://datatracker.ietf.org/doc/html/rfc9001#section-b.1.1>
53            confidentiality_limit: 1 << 23,
54            // ref: <https://datatracker.ietf.org/doc/html/rfc9001#section-b.1.2>
55            integrity_limit: 1 << 52,
56        }),
57    });
58
59/// The TLS1.3 ciphersuite `TLS_AES_128_GCM_SHA256`
60pub static TLS13_AES_128_GCM_SHA256: SupportedCipherSuite =
61    SupportedCipherSuite::Tls13(TLS13_AES_128_GCM_SHA256_INTERNAL);
62
63pub static TLS13_AES_128_GCM_SHA256_INTERNAL: &Tls13CipherSuite = &Tls13CipherSuite {
64    common: CipherSuiteCommon {
65        suite: CipherSuite::TLS13_AES_128_GCM_SHA256,
66        hash_provider: &SHA256,
67        confidentiality_limit: 1 << 23,
68    },
69    hkdf_provider: &Hkdf(SHA256),
70    aead_alg: &aead::Algorithm::Aes128Gcm,
71    quic: Some(&quic::KeyBuilder {
72        packet_algo: aead::Algorithm::Aes128Gcm,
73        header_algo: quic::HeaderProtectionAlgorithm::Aes128,
74        // ref: <https://datatracker.ietf.org/doc/html/rfc9001#section-b.1.1>
75        confidentiality_limit: 1 << 23,
76        // ref: <https://datatracker.ietf.org/doc/html/rfc9001#section-b.1.2>
77        integrity_limit: 1 << 52,
78    }),
79};
80
81struct Tls13Crypter {
82    algo: aead::Algorithm,
83    key: AeadKey,
84    iv: Iv,
85}
86
87impl Tls13AeadAlgorithm for aead::Algorithm {
88    fn encrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageEncrypter> {
89        Box::new(Tls13Crypter {
90            algo: *self,
91            key,
92            iv,
93        })
94    }
95
96    fn decrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageDecrypter> {
97        Box::new(Tls13Crypter {
98            algo: *self,
99            key,
100            iv,
101        })
102    }
103
104    fn key_len(&self) -> usize {
105        self.key_size()
106    }
107
108    fn extract_keys(
109        &self,
110        key: AeadKey,
111        iv: Iv,
112    ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError> {
113        Ok(match self {
114            aead::Algorithm::Aes128Gcm => ConnectionTrafficSecrets::Aes128Gcm { key, iv },
115            aead::Algorithm::Aes256Gcm => ConnectionTrafficSecrets::Aes256Gcm { key, iv },
116            #[cfg(all(chacha, not(feature = "fips")))]
117            aead::Algorithm::ChaCha20Poly1305 => {
118                ConnectionTrafficSecrets::Chacha20Poly1305 { key, iv }
119            }
120        })
121    }
122
123    fn fips(&self) -> bool {
124        crate::fips::enabled()
125    }
126}
127
128impl MessageEncrypter for Tls13Crypter {
129    fn encrypt(
130        &mut self,
131        msg: OutboundPlainMessage,
132        seq: u64,
133    ) -> Result<OutboundOpaqueMessage, Error> {
134        let total_len = self.encrypted_payload_len(msg.payload.len());
135        let mut payload = PrefixedPayload::with_capacity(total_len);
136        let aad = make_tls13_aad(total_len);
137        payload.extend_from_chunks(&msg.payload);
138        payload.extend_from_slice(&msg.typ.to_array());
139        let tag = self.algo.encrypt_in_place(
140            self.key.as_ref(),
141            &Nonce::new(&self.iv, seq).0,
142            &aad,
143            payload.as_mut(),
144        )?;
145        payload.extend_from_slice(&tag);
146        Ok(OutboundOpaqueMessage::new(
147            rustls::ContentType::ApplicationData,
148            // Note: all TLS 1.3 application data records use TLSv1_2 (0x0303) as the legacy record
149            // protocol version, see https://www.rfc-editor.org/rfc/rfc8446#section-5.1
150            rustls::ProtocolVersion::TLSv1_2,
151            payload,
152        ))
153    }
154
155    fn encrypted_payload_len(&self, payload_len: usize) -> usize {
156        payload_len + 1 + aead::TAG_LEN
157    }
158}
159
160impl MessageDecrypter for Tls13Crypter {
161    fn decrypt<'a>(
162        &mut self,
163        mut msg: InboundOpaqueMessage<'a>,
164        seq: u64,
165    ) -> Result<InboundPlainMessage<'a>, Error> {
166        let payload = &mut msg.payload;
167        let aad = make_tls13_aad(payload.len());
168        let plaintext_len = self.algo.decrypt_in_place(
169            self.key.as_ref(),
170            &Nonce::new(&self.iv, seq).0,
171            &aad,
172            payload.as_mut(),
173        )?;
174        // Remove the tag from the end of the payload.
175        payload.truncate(plaintext_len);
176        msg.into_tls13_unpadded_message()
177    }
178}