| 1 | use core::fmt; |
| 2 | |
| 3 | use crate::crypto; |
| 4 | use crate::crypto::hash; |
| 5 | use crate::suites::{CipherSuiteCommon, SupportedCipherSuite}; |
| 6 | |
| 7 | pub(crate) mod key_schedule; |
| 8 | |
| 9 | /// A TLS 1.3 cipher suite supported by rustls. |
| 10 | pub struct Tls13CipherSuite { |
| 11 | /// Common cipher suite fields. |
| 12 | pub common: CipherSuiteCommon, |
| 13 | |
| 14 | /// How to complete HKDF with the suite's hash function. |
| 15 | /// |
| 16 | /// If you have a HKDF implementation, you should directly implement the `crypto::tls13::Hkdf` |
| 17 | /// trait (and associated). |
| 18 | /// |
| 19 | /// If not, you can implement the [`crypto::hmac::Hmac`] trait (and associated), and then use |
| 20 | /// [`crypto::tls13::HkdfUsingHmac`]. |
| 21 | pub hkdf_provider: &'static dyn crypto::tls13::Hkdf, |
| 22 | |
| 23 | /// How to produce a [MessageDecrypter] or [MessageEncrypter] |
| 24 | /// from raw key material. |
| 25 | /// |
| 26 | /// [MessageDecrypter]: crate::crypto::cipher::MessageDecrypter |
| 27 | /// [MessageEncrypter]: crate::crypto::cipher::MessageEncrypter |
| 28 | pub aead_alg: &'static dyn crypto::cipher::Tls13AeadAlgorithm, |
| 29 | |
| 30 | /// How to create QUIC header and record protection algorithms |
| 31 | /// for this suite. |
| 32 | /// |
| 33 | /// Provide `None` to opt out of QUIC support for this suite. It will |
| 34 | /// not be offered in QUIC handshakes. |
| 35 | pub quic: Option<&'static dyn crate::quic::Algorithm>, |
| 36 | } |
| 37 | |
| 38 | impl Tls13CipherSuite { |
| 39 | /// Can a session using suite self resume from suite prev? |
| 40 | pub fn can_resume_from(&self, prev: &'static Self) -> Option<&'static Self> { |
| 41 | (prev.common.hash_provider.algorithm() == self.common.hash_provider.algorithm()) |
| 42 | .then_some(prev) |
| 43 | } |
| 44 | |
| 45 | /// Return `true` if this is backed by a FIPS-approved implementation. |
| 46 | /// |
| 47 | /// This means all the constituent parts that do cryptography return `true` for `fips()`. |
| 48 | pub fn fips(&self) -> bool { |
| 49 | let Self { |
| 50 | common, |
| 51 | hkdf_provider, |
| 52 | aead_alg, |
| 53 | quic, |
| 54 | } = self; |
| 55 | common.fips() |
| 56 | && hkdf_provider.fips() |
| 57 | && aead_alg.fips() |
| 58 | && quic.map(|q| q.fips()).unwrap_or(true) |
| 59 | } |
| 60 | |
| 61 | /// Returns a `quic::Suite` for the ciphersuite, if supported. |
| 62 | pub fn quic_suite(&'static self) -> Option<crate::quic::Suite> { |
| 63 | self.quic |
| 64 | .map(|quic| crate::quic::Suite { quic, suite: self }) |
| 65 | } |
| 66 | } |
| 67 | |
| 68 | impl From<&'static Tls13CipherSuite> for SupportedCipherSuite { |
| 69 | fn from(s: &'static Tls13CipherSuite) -> Self { |
| 70 | Self::Tls13(s) |
| 71 | } |
| 72 | } |
| 73 | |
| 74 | impl PartialEq for Tls13CipherSuite { |
| 75 | fn eq(&self, other: &Self) -> bool { |
| 76 | self.common.suite == other.common.suite |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | impl fmt::Debug for Tls13CipherSuite { |
| 81 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 82 | f&mut DebugStruct<'_, '_>.debug_struct("Tls13CipherSuite" ) |
| 83 | .field(name:"suite" , &self.common.suite) |
| 84 | .finish() |
| 85 | } |
| 86 | } |
| 87 | |
| 88 | /// Constructs the signature message specified in section 4.4.3 of RFC8446. |
| 89 | pub(crate) fn construct_client_verify_message(handshake_hash: &hash::Output) -> VerifyMessage { |
| 90 | VerifyMessage::new(handshake_hash, CLIENT_CONSTANT) |
| 91 | } |
| 92 | |
| 93 | /// Constructs the signature message specified in section 4.4.3 of RFC8446. |
| 94 | pub(crate) fn construct_server_verify_message(handshake_hash: &hash::Output) -> VerifyMessage { |
| 95 | VerifyMessage::new(handshake_hash, SERVER_CONSTANT) |
| 96 | } |
| 97 | |
| 98 | pub(crate) struct VerifyMessage { |
| 99 | buf: [u8; MAX_VERIFY_MSG], |
| 100 | used: usize, |
| 101 | } |
| 102 | |
| 103 | impl VerifyMessage { |
| 104 | fn new(handshake_hash: &hash::Output, context_string_with_0: &[u8; 34]) -> Self { |
| 105 | let used: usize = 64 + context_string_with_0.len() + handshake_hash.as_ref().len(); |
| 106 | let mut buf: [u8; 162] = [0x20u8; MAX_VERIFY_MSG]; |
| 107 | |
| 108 | let (_spaces: &mut [u8], context: &mut [u8]) = buf.split_at_mut(mid:64); |
| 109 | let (context: &mut [u8], hash: &mut [u8]) = context.split_at_mut(mid:34); |
| 110 | context.copy_from_slice(src:context_string_with_0); |
| 111 | hash[..handshake_hash.as_ref().len()].copy_from_slice(src:handshake_hash.as_ref()); |
| 112 | |
| 113 | Self { buf, used } |
| 114 | } |
| 115 | } |
| 116 | |
| 117 | impl AsRef<[u8]> for VerifyMessage { |
| 118 | fn as_ref(&self) -> &[u8] { |
| 119 | &self.buf[..self.used] |
| 120 | } |
| 121 | } |
| 122 | |
| 123 | const SERVER_CONSTANT: &[u8; 34] = b"TLS 1.3, server CertificateVerify \x00" ; |
| 124 | const CLIENT_CONSTANT: &[u8; 34] = b"TLS 1.3, client CertificateVerify \x00" ; |
| 125 | const MAX_VERIFY_MSG: usize = 64 + CLIENT_CONSTANT.len() + hash::Output::MAX_LEN; |
| 126 | |