Skip to main content

rustls/tls13/
mod.rs

1use core::fmt;
2
3use pki_types::FipsStatus;
4
5use crate::common_state::Protocol;
6use crate::crypto::{self, SignatureScheme, hash};
7use crate::enums::ProtocolVersion;
8use crate::quic;
9use crate::suites::{CipherSuiteCommon, Suite, SupportedCipherSuite};
10use crate::version::Tls13Version;
11
12pub(crate) mod key_schedule;
13
14#[derive(Clone, Copy, Debug)]
15pub(crate) enum Tls13ProtocolSuite {
16    Tcp(&'static Tls13CipherSuite),
17    Quic(quic::Suite),
18}
19
20impl Tls13ProtocolSuite {
21    pub(crate) fn suite(&self) -> &'static Tls13CipherSuite {
22        match self {
23            Self::Tcp(suite) => suite,
24            Self::Quic(quic) => quic.inner,
25        }
26    }
27
28    pub(crate) fn is_quic(&self) -> bool {
29        matches!(self, Self::Quic(_))
30    }
31}
32
33/// A TLS 1.3 cipher suite supported by rustls.
34#[expect(clippy::exhaustive_structs)]
35pub struct Tls13CipherSuite {
36    /// Common cipher suite fields.
37    pub common: CipherSuiteCommon,
38
39    /// The associated protocol version.
40    ///
41    /// This field should have the value [`rustls::version::TLS13_VERSION`].
42    ///
43    /// This value contains references to the TLS1.3 protocol handling code.
44    /// This means that a program that does not contain any `Tls13CipherSuite`
45    /// values also does not contain any reference to the TLS1.3 protocol handling
46    /// code, and the linker can remove it.
47    ///
48    /// [`rustls::version::TLS13_VERSION`]: crate::version::TLS13_VERSION
49    pub protocol_version: &'static Tls13Version,
50
51    /// How to complete HKDF with the suite's hash function.
52    ///
53    /// If you have a HKDF implementation, you should directly implement the `crypto::tls13::Hkdf`
54    /// trait (and associated).
55    ///
56    /// If not, you can implement the [`crypto::hmac::Hmac`] trait (and associated), and then use
57    /// [`crypto::tls13::HkdfUsingHmac`].
58    pub hkdf_provider: &'static dyn crypto::tls13::Hkdf,
59
60    /// How to produce a [MessageDecrypter] or [MessageEncrypter]
61    /// from raw key material.
62    ///
63    /// [MessageDecrypter]: crate::crypto::cipher::MessageDecrypter
64    /// [MessageEncrypter]: crate::crypto::cipher::MessageEncrypter
65    pub aead_alg: &'static dyn crypto::cipher::Tls13AeadAlgorithm,
66
67    /// How to create QUIC header and record protection algorithms
68    /// for this suite.
69    ///
70    /// Provide `None` to opt out of QUIC support for this suite.  It will
71    /// not be offered in QUIC handshakes.
72    pub quic: Option<&'static dyn quic::Algorithm>,
73}
74
75impl Tls13CipherSuite {
76    /// Can a session using suite self resume from suite prev?
77    pub fn can_resume_from(&self, prev: &'static Self) -> Option<&'static Self> {
78        (prev.common.hash_provider.algorithm() == self.common.hash_provider.algorithm())
79            .then_some(prev)
80    }
81
82    /// Return the FIPS validation status of this implementation.
83    ///
84    /// This is the combination of the constituent parts of the cipher suite.
85    pub fn fips(&self) -> FipsStatus {
86        let Self {
87            common,
88            protocol_version: _,
89            hkdf_provider,
90            aead_alg,
91            quic,
92        } = self;
93
94        let mut status = Ord::min(common.fips(), hkdf_provider.fips());
95        status = Ord::min(status, aead_alg.fips());
96        match quic {
97            Some(quic) => Ord::min(status, quic.fips()),
98            None => status,
99        }
100    }
101}
102
103impl Suite for Tls13CipherSuite {
104    fn client_handler(&self) -> &'static dyn crate::client::ClientHandler<Self> {
105        self.protocol_version.client
106    }
107
108    fn server_handler(&self) -> &'static dyn crate::server::ServerHandler<Self> {
109        self.protocol_version.server
110    }
111
112    /// Does this suite support the `proto` protocol?
113    ///
114    /// All TLS1.3 suites support TCP-TLS. QUIC support is conditional on `quic` slot.
115    fn usable_for_protocol(&self, proto: Protocol) -> bool {
116        match proto {
117            Protocol::Tcp => true,
118            Protocol::Quic(_) => self.quic.is_some(),
119        }
120    }
121
122    fn usable_for_signature_scheme(&self, scheme: SignatureScheme) -> bool {
123        scheme.supported_in_tls13()
124    }
125
126    fn common(&self) -> &CipherSuiteCommon {
127        &self.common
128    }
129
130    const VERSION: ProtocolVersion = ProtocolVersion::TLSv1_3;
131}
132
133impl From<&'static Tls13CipherSuite> for SupportedCipherSuite {
134    fn from(s: &'static Tls13CipherSuite) -> Self {
135        Self::Tls13(s)
136    }
137}
138
139impl PartialEq for Tls13CipherSuite {
140    fn eq(&self, other: &Self) -> bool {
141        self.common.suite == other.common.suite
142    }
143}
144
145impl fmt::Debug for Tls13CipherSuite {
146    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147        f.debug_struct("Tls13CipherSuite")
148            .field("suite", &self.common.suite)
149            .finish_non_exhaustive()
150    }
151}
152
153/// Constructs the signature message specified in section 4.5.2 of RFC 9846.
154pub(crate) fn construct_client_verify_message(handshake_hash: &hash::Output) -> VerifyMessage {
155    VerifyMessage::new(handshake_hash, CLIENT_CONSTANT)
156}
157
158/// Constructs the signature message specified in section 4.5.2 of RFC 9846.
159pub(crate) fn construct_server_verify_message(handshake_hash: &hash::Output) -> VerifyMessage {
160    VerifyMessage::new(handshake_hash, SERVER_CONSTANT)
161}
162
163pub(crate) struct VerifyMessage {
164    buf: [u8; MAX_VERIFY_MSG],
165    used: usize,
166}
167
168impl VerifyMessage {
169    fn new(handshake_hash: &hash::Output, context_string_with_0: &[u8; 34]) -> Self {
170        let used = 64 + context_string_with_0.len() + handshake_hash.as_ref().len();
171        let mut buf = [0x20u8; MAX_VERIFY_MSG];
172
173        let (_spaces, context) = buf.split_at_mut(64);
174        let (context, hash) = context.split_at_mut(34);
175        context.copy_from_slice(context_string_with_0);
176        hash[..handshake_hash.as_ref().len()].copy_from_slice(handshake_hash.as_ref());
177
178        Self { buf, used }
179    }
180}
181
182impl AsRef<[u8]> for VerifyMessage {
183    fn as_ref(&self) -> &[u8] {
184        &self.buf[..self.used]
185    }
186}
187
188const SERVER_CONSTANT: &[u8; 34] = b"TLS 1.3, server CertificateVerify\x00";
189const CLIENT_CONSTANT: &[u8; 34] = b"TLS 1.3, client CertificateVerify\x00";
190const MAX_VERIFY_MSG: usize = 64 + CLIENT_CONSTANT.len() + hash::Output::MAX_LEN;
191
192#[cfg(test)]
193mod tests {
194    use std::boxed::Box;
195
196    use crate::crypto::test_provider::FAKE_HASH;
197    use crate::crypto::{HashAlgorithm, TLS13_TEST_SUITE, hash};
198    use crate::{CipherSuiteCommon, Tls13CipherSuite};
199
200    #[test]
201    fn test_can_resume_to() {
202        let other_tls13_suite = Tls13CipherSuite {
203            common: CipherSuiteCommon {
204                hash_provider: &OtherHash,
205                ..TLS13_TEST_SUITE.common
206            },
207            ..*TLS13_TEST_SUITE
208        };
209
210        assert!(
211            TLS13_TEST_SUITE
212                .can_resume_from(TLS13_TEST_SUITE)
213                .is_some()
214        );
215
216        assert!(
217            other_tls13_suite
218                .can_resume_from(TLS13_TEST_SUITE)
219                .is_none()
220        );
221    }
222
223    struct OtherHash;
224
225    impl hash::Hash for OtherHash {
226        #[cfg_attr(coverage_nightly, coverage(off))]
227        fn start(&self) -> Box<dyn hash::Context> {
228            FAKE_HASH.start()
229        }
230
231        #[cfg_attr(coverage_nightly, coverage(off))]
232        fn hash(&self, data: &[u8]) -> hash::Output {
233            FAKE_HASH.hash(data)
234        }
235
236        #[cfg_attr(coverage_nightly, coverage(off))]
237        fn output_len(&self) -> usize {
238            FAKE_HASH.output_len()
239        }
240
241        fn algorithm(&self) -> HashAlgorithm {
242            HashAlgorithm(123)
243        }
244    }
245}