rustls/tls13/
mod.rs

1use core::fmt;
2
3use crate::common_state::Protocol;
4use crate::crypto::{self, hash};
5use crate::enums::{ProtocolVersion, SignatureScheme};
6use crate::suites::{CipherSuiteCommon, Suite, SupportedCipherSuite};
7use crate::version::Tls13Version;
8
9pub(crate) mod key_schedule;
10
11/// A TLS 1.3 cipher suite supported by rustls.
12#[expect(clippy::exhaustive_structs)]
13pub struct Tls13CipherSuite {
14    /// Common cipher suite fields.
15    pub common: CipherSuiteCommon,
16
17    /// The associated protocol version.
18    ///
19    /// This field should have the value [`rustls::version::TLS13_VERSION`].
20    ///
21    /// This value contains references to the TLS1.3 protocol handling code.
22    /// This means that a program that does not contain any `Tls13CipherSuite`
23    /// values also does not contain any reference to the TLS1.3 protocol handling
24    /// code, and the linker can remove it.
25    ///
26    /// [`rustls::version::TLS13_VERSION`]: crate::version::TLS13_VERSION
27    pub protocol_version: &'static Tls13Version,
28
29    /// How to complete HKDF with the suite's hash function.
30    ///
31    /// If you have a HKDF implementation, you should directly implement the `crypto::tls13::Hkdf`
32    /// trait (and associated).
33    ///
34    /// If not, you can implement the [`crypto::hmac::Hmac`] trait (and associated), and then use
35    /// [`crypto::tls13::HkdfUsingHmac`].
36    pub hkdf_provider: &'static dyn crypto::tls13::Hkdf,
37
38    /// How to produce a [MessageDecrypter] or [MessageEncrypter]
39    /// from raw key material.
40    ///
41    /// [MessageDecrypter]: crate::crypto::cipher::MessageDecrypter
42    /// [MessageEncrypter]: crate::crypto::cipher::MessageEncrypter
43    pub aead_alg: &'static dyn crypto::cipher::Tls13AeadAlgorithm,
44
45    /// How to create QUIC header and record protection algorithms
46    /// for this suite.
47    ///
48    /// Provide `None` to opt out of QUIC support for this suite.  It will
49    /// not be offered in QUIC handshakes.
50    pub quic: Option<&'static dyn crate::quic::Algorithm>,
51}
52
53impl Tls13CipherSuite {
54    /// Can a session using suite self resume from suite prev?
55    pub fn can_resume_from(&self, prev: &'static Self) -> Option<&'static Self> {
56        (prev.common.hash_provider.algorithm() == self.common.hash_provider.algorithm())
57            .then_some(prev)
58    }
59
60    /// Return `true` if this is backed by a FIPS-approved implementation.
61    ///
62    /// This means all the constituent parts that do cryptography return `true` for `fips()`.
63    pub fn fips(&self) -> bool {
64        let Self {
65            common,
66            protocol_version: _,
67            hkdf_provider,
68            aead_alg,
69            quic,
70        } = self;
71        common.fips()
72            && hkdf_provider.fips()
73            && aead_alg.fips()
74            && quic.map(|q| q.fips()).unwrap_or(true)
75    }
76
77    /// Returns a `quic::Suite` for the ciphersuite, if supported.
78    pub fn quic_suite(&'static self) -> Option<crate::quic::Suite> {
79        self.quic
80            .map(|quic| crate::quic::Suite { quic, suite: self })
81    }
82}
83
84impl Suite for Tls13CipherSuite {
85    fn client_handler(&self) -> &'static dyn crate::client::ClientHandler<Self> {
86        self.protocol_version.client
87    }
88
89    fn server_handler(&self) -> &'static dyn crate::server::ServerHandler<Self> {
90        self.protocol_version.server
91    }
92
93    /// Does this suite support the `proto` protocol?
94    ///
95    /// All TLS1.3 suites support TCP-TLS. QUIC support is conditional on `quic` slot.
96    fn usable_for_protocol(&self, proto: Protocol) -> bool {
97        match proto {
98            Protocol::Tcp => true,
99            Protocol::Quic => self.quic.is_some(),
100        }
101    }
102
103    fn usable_for_signature_scheme(&self, scheme: SignatureScheme) -> bool {
104        scheme.supported_in_tls13()
105    }
106
107    fn common(&self) -> &CipherSuiteCommon {
108        &self.common
109    }
110
111    const VERSION: ProtocolVersion = ProtocolVersion::TLSv1_3;
112}
113
114impl From<&'static Tls13CipherSuite> for SupportedCipherSuite {
115    fn from(s: &'static Tls13CipherSuite) -> Self {
116        Self::Tls13(s)
117    }
118}
119
120impl PartialEq for Tls13CipherSuite {
121    fn eq(&self, other: &Self) -> bool {
122        self.common.suite == other.common.suite
123    }
124}
125
126impl fmt::Debug for Tls13CipherSuite {
127    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
128        f.debug_struct("Tls13CipherSuite")
129            .field("suite", &self.common.suite)
130            .finish()
131    }
132}
133
134/// Constructs the signature message specified in section 4.4.3 of RFC8446.
135pub(crate) fn construct_client_verify_message(handshake_hash: &hash::Output) -> VerifyMessage {
136    VerifyMessage::new(handshake_hash, CLIENT_CONSTANT)
137}
138
139/// Constructs the signature message specified in section 4.4.3 of RFC8446.
140pub(crate) fn construct_server_verify_message(handshake_hash: &hash::Output) -> VerifyMessage {
141    VerifyMessage::new(handshake_hash, SERVER_CONSTANT)
142}
143
144pub(crate) struct VerifyMessage {
145    buf: [u8; MAX_VERIFY_MSG],
146    used: usize,
147}
148
149impl VerifyMessage {
150    fn new(handshake_hash: &hash::Output, context_string_with_0: &[u8; 34]) -> Self {
151        let used = 64 + context_string_with_0.len() + handshake_hash.as_ref().len();
152        let mut buf = [0x20u8; MAX_VERIFY_MSG];
153
154        let (_spaces, context) = buf.split_at_mut(64);
155        let (context, hash) = context.split_at_mut(34);
156        context.copy_from_slice(context_string_with_0);
157        hash[..handshake_hash.as_ref().len()].copy_from_slice(handshake_hash.as_ref());
158
159        Self { buf, used }
160    }
161}
162
163impl AsRef<[u8]> for VerifyMessage {
164    fn as_ref(&self) -> &[u8] {
165        &self.buf[..self.used]
166    }
167}
168
169const SERVER_CONSTANT: &[u8; 34] = b"TLS 1.3, server CertificateVerify\x00";
170const CLIENT_CONSTANT: &[u8; 34] = b"TLS 1.3, client CertificateVerify\x00";
171const MAX_VERIFY_MSG: usize = 64 + CLIENT_CONSTANT.len() + hash::Output::MAX_LEN;