1use core::fmt;
2
3use crate::crypto;
4use crate::crypto::hash;
5use crate::suites::{CipherSuiteCommon, SupportedCipherSuite};
6use crate::version::Tls13Version;
7
8pub(crate) mod key_schedule;
9
10#[allow(clippy::exhaustive_structs)]
12pub struct Tls13CipherSuite {
13 pub common: CipherSuiteCommon,
15
16 pub protocol_version: &'static Tls13Version,
27
28 pub hkdf_provider: &'static dyn crypto::tls13::Hkdf,
36
37 pub aead_alg: &'static dyn crypto::cipher::Tls13AeadAlgorithm,
43
44 pub quic: Option<&'static dyn crate::quic::Algorithm>,
50}
51
52impl Tls13CipherSuite {
53 pub fn can_resume_from(&self, prev: &'static Self) -> Option<&'static Self> {
55 (prev.common.hash_provider.algorithm() == self.common.hash_provider.algorithm())
56 .then_some(prev)
57 }
58
59 pub fn fips(&self) -> bool {
63 let Self {
64 common,
65 protocol_version: _,
66 hkdf_provider,
67 aead_alg,
68 quic,
69 } = self;
70 common.fips()
71 && hkdf_provider.fips()
72 && aead_alg.fips()
73 && quic.map(|q| q.fips()).unwrap_or(true)
74 }
75
76 pub fn quic_suite(&'static self) -> Option<crate::quic::Suite> {
78 self.quic
79 .map(|quic| crate::quic::Suite { quic, suite: self })
80 }
81}
82
83impl From<&'static Tls13CipherSuite> for SupportedCipherSuite {
84 fn from(s: &'static Tls13CipherSuite) -> Self {
85 Self::Tls13(s)
86 }
87}
88
89impl PartialEq for Tls13CipherSuite {
90 fn eq(&self, other: &Self) -> bool {
91 self.common.suite == other.common.suite
92 }
93}
94
95impl fmt::Debug for Tls13CipherSuite {
96 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
97 f.debug_struct("Tls13CipherSuite")
98 .field("suite", &self.common.suite)
99 .finish()
100 }
101}
102
103pub(crate) fn construct_client_verify_message(handshake_hash: &hash::Output) -> VerifyMessage {
105 VerifyMessage::new(handshake_hash, CLIENT_CONSTANT)
106}
107
108pub(crate) fn construct_server_verify_message(handshake_hash: &hash::Output) -> VerifyMessage {
110 VerifyMessage::new(handshake_hash, SERVER_CONSTANT)
111}
112
113pub(crate) struct VerifyMessage {
114 buf: [u8; MAX_VERIFY_MSG],
115 used: usize,
116}
117
118impl VerifyMessage {
119 fn new(handshake_hash: &hash::Output, context_string_with_0: &[u8; 34]) -> Self {
120 let used = 64 + context_string_with_0.len() + handshake_hash.as_ref().len();
121 let mut buf = [0x20u8; MAX_VERIFY_MSG];
122
123 let (_spaces, context) = buf.split_at_mut(64);
124 let (context, hash) = context.split_at_mut(34);
125 context.copy_from_slice(context_string_with_0);
126 hash[..handshake_hash.as_ref().len()].copy_from_slice(handshake_hash.as_ref());
127
128 Self { buf, used }
129 }
130}
131
132impl AsRef<[u8]> for VerifyMessage {
133 fn as_ref(&self) -> &[u8] {
134 &self.buf[..self.used]
135 }
136}
137
138const SERVER_CONSTANT: &[u8; 34] = b"TLS 1.3, server CertificateVerify\x00";
139const CLIENT_CONSTANT: &[u8; 34] = b"TLS 1.3, client CertificateVerify\x00";
140const MAX_VERIFY_MSG: usize = 64 + CLIENT_CONSTANT.len() + hash::Output::MAX_LEN;