use super::super::tls_wire::TLS_RECORD_HEADER_LEN;
use super::*;
impl Connection {
fn noxtls_build_tls13_server_certificate_handshake_message(
&self,
leaf_cert: &[u8],
) -> Result<Vec<u8>> {
if self.tls13_negotiated_server_certificate_type == TLS_CERTIFICATE_TYPE_RAW_PUBLIC_KEY {
return Self::noxtls_build_certificate_message(leaf_cert);
}
if self
.tls13_client_certificate_compression_algorithms
.contains(&TLS13_CERT_COMPRESSION_ZLIB)
{
#[cfg(feature = "std")]
{
return Self::noxtls_build_zlib_compressed_certificate_message(leaf_cert);
}
}
Self::noxtls_build_certificate_message(leaf_cert)
}
#[must_use]
pub fn noxtls_new_tls13_server() -> Self {
let mut conn = Self::noxtls_new(TlsVersion::Tls13);
conn.tls_role = TlsRole::Server;
conn.tls13_server_preferred_cipher_suites = vec![
CipherSuite::TlsAes128GcmSha256,
CipherSuite::TlsAes256GcmSha384,
CipherSuite::TlsChacha20Poly1305Sha256,
];
conn.tls13_server_alpn_protocols = vec![b"http/1.1".to_vec()];
conn
}
pub fn noxtls_set_tls13_server_cipher_suites(&mut self, suites: &[CipherSuite]) -> Result<()> {
if suites.is_empty() {
return Err(Error::InvalidLength(
"server cipher suite preference list must not be empty",
));
}
self.tls13_server_preferred_cipher_suites = suites.to_vec();
Ok(())
}
pub fn noxtls_set_tls13_server_alpn_protocols(&mut self, protocols: &[&[u8]]) -> Result<()> {
let mut stored = Vec::with_capacity(protocols.len());
for protocol in protocols {
if protocol.is_empty() {
return Err(Error::InvalidLength("alpn protocol must not be empty"));
}
if protocol.len() > u8::MAX as usize {
return Err(Error::InvalidLength(
"alpn protocol length must not exceed 255 bytes",
));
}
stored.push(protocol.to_vec());
}
self.tls13_server_alpn_protocols = stored;
Ok(())
}
pub fn noxtls_configure_tls13_server_identity(
&mut self,
certificate_chain_der: &[Vec<u8>],
signing_key: Tls13ServerIdentityKey,
) -> Result<()> {
if certificate_chain_der.is_empty() {
return Err(Error::InvalidLength(
"server certificate chain must contain at least one certificate",
));
}
let leaf = noxtls_parse_certificate(&certificate_chain_der[0])?;
self.tls13_server_certificate_chain_der = certificate_chain_der.to_vec();
self.tls13_server_signing_key = Some(signing_key);
self.tls13_server_leaf_public_key_der = Some(leaf.subject_public_key);
self.tls13_server_certificate_chain_validated = true;
self.tls13_server_identity_certificate_type = TLS_CERTIFICATE_TYPE_X509;
self.tls13_negotiated_server_certificate_type = TLS_CERTIFICATE_TYPE_X509;
Ok(())
}
pub fn noxtls_configure_tls13_server_identity_pkcs8_der(
&mut self,
certificate_chain_der: &[Vec<u8>],
private_key_pkcs8_der: &[u8],
) -> Result<()> {
let signing_key =
Self::noxtls_tls13_server_identity_key_from_pkcs8_der(private_key_pkcs8_der)?;
self.noxtls_configure_tls13_server_identity(certificate_chain_der, signing_key)
}
pub fn noxtls_configure_tls13_server_raw_public_key_identity(
&mut self,
subject_public_key_info_der: &[u8],
signing_key: Tls13ServerIdentityKey,
) -> Result<()> {
if subject_public_key_info_der.is_empty() {
return Err(Error::InvalidLength(
"server raw public key spki must not be empty",
));
}
let spki = noxtls_parse_spki_public_key_info_der(subject_public_key_info_der)?;
self.tls13_server_certificate_chain_der = vec![subject_public_key_info_der.to_vec()];
self.tls13_server_signing_key = Some(signing_key);
self.tls13_server_leaf_public_key_der = Some(spki.subject_public_key);
self.tls13_server_certificate_chain_validated = true;
self.tls13_server_identity_certificate_type = TLS_CERTIFICATE_TYPE_RAW_PUBLIC_KEY;
self.tls13_negotiated_server_certificate_type = TLS_CERTIFICATE_TYPE_RAW_PUBLIC_KEY;
Ok(())
}
pub fn noxtls_accept_tls13_client_hello(
&mut self,
client_hello: &[u8],
server_random: &[u8],
) -> Result<Vec<u8>> {
if self.tls_role != TlsRole::Server {
return Err(Error::StateError(
"client hello acceptance requires server-role connection",
));
}
if self.state != HandshakeState::Idle {
return Err(Error::StateError(
"client hello can only be accepted from idle server state",
));
}
if server_random.len() != 32 {
return Err(Error::InvalidLength("server hello random must be 32 bytes"));
}
if self.tls13_server_certificate_chain_der.is_empty()
|| self.tls13_server_signing_key.is_none()
{
return Err(Error::StateError(
"server identity must be configured before accepting client hello",
));
}
let preferred = if self.tls13_server_preferred_cipher_suites.is_empty() {
noxtls_default_client_cipher_suites(self.version)
} else {
self.tls13_server_preferred_cipher_suites.clone()
};
let hello_info = Self::noxtls_parse_client_hello_info(client_hello)?;
if hello_info.legacy_version != 0x0303 {
return Err(Error::ParseFailure(
"tls13 client hello has invalid legacy_version",
));
}
let selected = Self::noxtls_select_cipher_suite_from_client_hello(
client_hello,
&preferred,
self.version,
)?;
if !self.noxtls_tls13_server_identity_signature_scheme_offered(
&hello_info.extensions.signature_algorithms,
) {
return Err(Error::ParseFailure(
"client hello has no signature scheme compatible with server identity",
));
}
if self.tls13_hrr_seen && self.noxtls_selected_cipher_suite != Some(selected) {
return Err(Error::ParseFailure(
"tls13 hrr retry changed negotiated cipher suite",
));
}
if let Some(first_order) = self.tls13_hrr_client_hello_extension_order.as_deref() {
let retry_order = noxtls_parse_client_hello_extension_order(client_hello)?;
let first_order_without_early_data = first_order
.iter()
.copied()
.filter(|extension_type| *extension_type != 0x002a)
.collect::<Vec<_>>();
if first_order != retry_order.as_slice()
&& first_order_without_early_data.as_slice() != retry_order.as_slice()
{
return Err(Error::ParseFailure(
"tls13 hrr retry changed client hello extension order",
));
}
}
self.tls13_client_server_name = hello_info.extensions.sni_server_name.clone();
self.tls13_client_alpn_protocols = hello_info.extensions.alpn_protocols.clone();
self.tls13_client_signature_algorithms = hello_info.extensions.signature_algorithms.clone();
self.tls13_client_certificate_compression_algorithms = hello_info
.extensions
.certificate_compression_algorithms
.clone();
self.tls13_client_offered_server_certificate_types =
hello_info.extensions.server_certificate_types.clone();
let selected_server_certificate_type =
if self.tls13_server_identity_certificate_type == TLS_CERTIFICATE_TYPE_RAW_PUBLIC_KEY {
if !hello_info
.extensions
.server_certificate_types
.contains(&TLS_CERTIFICATE_TYPE_RAW_PUBLIC_KEY)
{
return Err(Error::ParseFailure(
"client hello did not offer raw public key server certificates",
));
}
TLS_CERTIFICATE_TYPE_RAW_PUBLIC_KEY
} else {
if !hello_info.extensions.server_certificate_types.is_empty()
&& !hello_info
.extensions
.server_certificate_types
.contains(&TLS_CERTIFICATE_TYPE_X509)
{
return Err(Error::ParseFailure(
"client hello did not offer x509 server certificates",
));
}
TLS_CERTIFICATE_TYPE_X509
};
self.tls13_negotiated_server_certificate_type = selected_server_certificate_type;
if !self.tls13_hrr_seen {
self.noxtls_reset_transcript_for_new_handshake();
}
self.noxtls_append_transcript(client_hello);
if !self.tls13_hrr_seen {
self.noxtls_selected_cipher_suite = Some(selected);
self.noxtls_rebuild_transcript_hash_from_selected_suite();
}
let (group, shared_secret, server_key_exchange) =
self.noxtls_negotiate_tls13_server_key_share(client_hello, server_random)?;
if let Some(requested_group) = self.tls13_hrr_requested_group {
if group != requested_group {
return Err(Error::ParseFailure(
"tls13 hrr retry did not provide requested key_share group",
));
}
}
self.tls13_shared_secret = Some(shared_secret);
let (_, client_hello_body) = noxtls_parse_handshake_message(client_hello)?;
let legacy_session_id = noxtls_extract_client_hello_legacy_session_id(client_hello_body)?;
let server_hello = Self::noxtls_build_server_hello_with_key_share(
self.version,
selected,
server_random,
group,
&server_key_exchange,
Some(legacy_session_id),
)?;
self.noxtls_append_transcript(&server_hello);
self.tls13_hrr_seen = false;
self.tls13_hrr_requested_group = None;
self.tls13_hrr_client_hello_extension_order = None;
self.state = HandshakeState::ServerHelloSent;
Ok(server_hello)
}
pub fn noxtls_start_tls13_hello_retry_request(
&mut self,
client_hello: &[u8],
requested_group: u16,
) -> Result<Vec<u8>> {
if self.tls_role != TlsRole::Server {
return Err(Error::StateError(
"hello retry request requires server-role connection",
));
}
if self.state != HandshakeState::Idle {
return Err(Error::StateError(
"hello retry request can only start from idle server state",
));
}
let preferred = if self.tls13_server_preferred_cipher_suites.is_empty() {
noxtls_default_client_cipher_suites(self.version)
} else {
self.tls13_server_preferred_cipher_suites.clone()
};
let hello_info = Self::noxtls_parse_client_hello_info(client_hello)?;
if hello_info.legacy_version != 0x0303 {
return Err(Error::ParseFailure(
"tls13 client hello has invalid legacy_version",
));
}
if !hello_info
.extensions
.supported_groups
.contains(&requested_group)
{
return Err(Error::ParseFailure(
"hello retry request group was not offered in supported_groups",
));
}
let selected = preferred
.iter()
.copied()
.find(|suite| {
hello_info.offered_cipher_suites.contains(suite)
&& noxtls_suite_supported_by_version(*suite, self.version)
&& hello_info.extensions.supported_versions.contains(&0x0304)
&& !hello_info.extensions.signature_algorithms.is_empty()
&& self.noxtls_tls13_server_identity_signature_scheme_offered(
&hello_info.extensions.signature_algorithms,
)
})
.ok_or(Error::ParseFailure("no mutually supported cipher suite"))?;
let hrr = Self::noxtls_build_hello_retry_request(selected, requested_group)?;
self.noxtls_reset_transcript_for_new_handshake();
self.noxtls_append_transcript(client_hello);
self.noxtls_selected_cipher_suite = Some(selected);
self.noxtls_rebuild_transcript_hash_from_selected_suite();
self.noxtls_reset_transcript_for_hrr();
self.noxtls_append_transcript(&hrr);
self.tls13_hrr_seen = true;
self.tls13_hrr_requested_group = Some(requested_group);
self.tls13_hrr_client_hello_extension_order =
Some(noxtls_parse_client_hello_extension_order(client_hello)?);
Ok(hrr)
}
pub fn noxtls_build_tls13_server_handshake_flight(&mut self) -> Result<Vec<u8>> {
self.noxtls_build_tls13_server_handshake_flight_with_client_certificate_request(
self.tls13_require_client_certificate_auth,
)
}
pub fn noxtls_build_tls13_server_handshake_flight_with_client_certificate_request(
&mut self,
request_client_certificate: bool,
) -> Result<Vec<u8>> {
if self.tls_role != TlsRole::Server {
return Err(Error::StateError(
"server handshake flight requires server-role connection",
));
}
if self.state != HandshakeState::KeysDerived {
return Err(Error::StateError(
"server handshake flight requires keys derived state",
));
}
let selected_alpn = self.noxtls_pick_server_alpn_protocol();
let acknowledge_sni = self.tls13_client_server_name.is_some();
let encrypted_extensions =
Self::noxtls_build_encrypted_extensions_with_certificate_type_policy(
selected_alpn.as_deref(),
acknowledge_sni,
false,
if self.tls13_negotiated_server_certificate_type
== TLS_CERTIFICATE_TYPE_RAW_PUBLIC_KEY
{
Some(TLS_CERTIFICATE_TYPE_RAW_PUBLIC_KEY)
} else {
None
},
)?;
self.noxtls_append_transcript(&encrypted_extensions);
let certificate_request = if request_client_certificate {
self.tls13_server_requested_client_certificate = true;
let message = Self::noxtls_build_certificate_request_message();
self.noxtls_append_transcript(&message);
Some(message)
} else {
None
};
let leaf_cert = self
.tls13_server_certificate_chain_der
.first()
.ok_or(Error::StateError(
"server certificate chain is not configured",
))?
.clone();
let certificate =
self.noxtls_build_tls13_server_certificate_handshake_message(&leaf_cert)?;
self.noxtls_append_transcript(&certificate);
let certificate_verify = self.noxtls_build_server_certificate_verify_handshake_message()?;
self.noxtls_append_transcript(&certificate_verify);
let finished = self.noxtls_build_finished_message()?;
self.noxtls_append_transcript(&finished);
let mut handshake_payload = Vec::new();
handshake_payload.extend_from_slice(&encrypted_extensions);
if let Some(certificate_request) = certificate_request.as_deref() {
handshake_payload.extend_from_slice(certificate_request);
}
handshake_payload.extend_from_slice(&certificate);
handshake_payload.extend_from_slice(&certificate_verify);
handshake_payload.extend_from_slice(&finished);
let aad = self.noxtls_build_tls13_server_handshake_record_aad(handshake_payload.len())?;
let packet = self.noxtls_seal_server_tls13_record_packet(
&handshake_payload,
RecordContentType::Handshake.to_u8(),
&aad,
0,
)?;
self.noxtls_install_tls13_server_application_write_keys()?;
Ok(packet)
}
pub fn noxtls_recv_tls13_client_certificate_message(&mut self, msg: &[u8]) -> Result<()> {
if self.tls_role != TlsRole::Server {
return Err(Error::StateError(
"client certificate processing requires server-role connection",
));
}
if self.state != HandshakeState::KeysDerived {
return Err(Error::StateError(
"client certificate can only be processed before client Finished",
));
}
let (handshake_type, body) = noxtls_parse_handshake_message(msg)?;
if handshake_type != HANDSHAKE_CERTIFICATE {
return Err(Error::ParseFailure("invalid client certificate type"));
}
let parsed = match noxtls_parse_certificate_body(body, TLS_CERTIFICATE_TYPE_X509) {
Ok(parsed) => parsed,
Err(Error::ParseFailure("certificate list must not be empty")) => {
if self.tls13_require_client_certificate_auth {
return Err(Error::CryptoFailure("client certificate is required"));
}
self.noxtls_append_transcript(msg);
return Ok(());
}
Err(err) => return Err(err),
};
self.noxtls_validate_tls13_client_certificate_chain(&parsed.certificates)?;
self.noxtls_append_transcript(msg);
Ok(())
}
pub fn noxtls_recv_empty_tls13_client_certificate_message(&mut self, msg: &[u8]) -> Result<()> {
self.noxtls_recv_tls13_client_certificate_message(msg)
}
pub fn noxtls_recv_tls13_client_certificate_verify_message(
&mut self,
msg: &[u8],
) -> Result<()> {
if self.tls_role != TlsRole::Server {
return Err(Error::StateError(
"client certificate verify processing requires server-role connection",
));
}
if self.state != HandshakeState::KeysDerived {
return Err(Error::StateError(
"client certificate verify can only be processed before client Finished",
));
}
let (handshake_type, body) = noxtls_parse_handshake_message(msg)?;
if handshake_type != HANDSHAKE_CERTIFICATE_VERIFY {
return Err(Error::ParseFailure(
"invalid client certificate verify type",
));
}
let (signature_scheme, signature) = noxtls_parse_certificate_verify_fields(body)?;
if signature.is_empty() {
return Err(Error::ParseFailure(
"client certificate verify signature must not be empty",
));
}
if !noxtls_tls13_supported_certificate_verify_signature_scheme(signature_scheme) {
return Err(Error::UnsupportedFeature(
"unsupported tls13 client certificate verify signature scheme",
));
}
if !self.tls13_client_certificate_chain_validated {
return Err(Error::StateError(
"client certificate verify requires validated client certificate chain",
));
}
self.noxtls_verify_tls13_client_certificate_verify_signature(signature_scheme, signature)?;
self.noxtls_append_transcript(msg);
Ok(())
}
pub fn noxtls_recv_tls13_client_authentication_packet(&mut self, packet: &[u8]) -> Result<()> {
let aad = Self::noxtls_tls13_packet_header_aad(packet)?;
let (inner, content_type) = self.noxtls_open_client_tls13_record_packet(packet, &aad)?;
if content_type != RecordContentType::Handshake.to_u8() {
return Err(Error::ParseFailure(
"expected handshake content in client authentication record",
));
}
let messages = split_tls13_handshake_payload(&inner)?;
let mut index = 0_usize;
if self.tls13_server_requested_client_certificate {
if messages.len() < 3 {
return Err(Error::ParseFailure(
"client authentication flight missing certificate messages",
));
}
self.noxtls_recv_tls13_client_certificate_message(&messages[index])?;
index += 1;
self.noxtls_recv_tls13_client_certificate_verify_message(&messages[index])?;
index += 1;
}
if index >= messages.len() {
return Err(Error::ParseFailure(
"client authentication flight missing finished",
));
}
self.noxtls_recv_client_finished_message(&messages[index])?;
index += 1;
if index != messages.len() {
return Err(Error::ParseFailure(
"unexpected trailing client authentication messages",
));
}
Ok(())
}
fn noxtls_validate_tls13_client_certificate_chain(
&mut self,
certificates: &[Vec<u8>],
) -> Result<()> {
if certificates.is_empty() {
return Err(Error::ParseFailure(
"client certificate list must include leaf certificate",
));
}
if self.tls13_client_trust_anchors_der.is_empty() {
return Err(Error::StateError(
"tls13 client trust anchors are not configured",
));
}
let validation_time =
self.tls13_client_validation_time
.as_deref()
.ok_or(Error::StateError(
"tls13 client validation time is not configured",
))?;
let leaf = noxtls_parse_certificate(&certificates[0])?;
let mut parsed_intermediates = Vec::new();
for der in &certificates[1..] {
parsed_intermediates.push(noxtls_parse_certificate(der)?);
}
for der in &self.tls13_client_intermediates_der {
parsed_intermediates.push(noxtls_parse_certificate(der)?);
}
let mut parsed_anchors = Vec::new();
for der in &self.tls13_client_trust_anchors_der {
parsed_anchors.push(noxtls_parse_certificate(der)?);
}
noxtls_validate_certificate_chain(
&leaf,
&parsed_intermediates,
&parsed_anchors,
validation_time,
)
.map_err(noxtls_map_certificate_validation_error)?;
self.tls13_client_leaf_public_key_der = Some(leaf.subject_public_key.clone());
self.tls13_client_certificate_chain_validated = true;
Ok(())
}
fn noxtls_verify_tls13_client_certificate_verify_signature(
&self,
signature_scheme: u16,
signature: &[u8],
) -> Result<()> {
let leaf_spki =
self.tls13_client_leaf_public_key_der
.as_deref()
.ok_or(Error::StateError(
"client leaf public key is unavailable for certificate verify",
))?;
let signed_message =
noxtls_build_tls13_client_certificate_verify_message(&self.noxtls_transcript_hash());
match signature_scheme {
TLS13_SIGALG_ECDSA_SECP256R1_SHA256 => {
let public_key = P256PublicKey::from_uncompressed(leaf_spki)?;
let (r, s) = if signature.len() == 64 {
let mut r = [0_u8; 32];
let mut s = [0_u8; 32];
r.copy_from_slice(&signature[..32]);
s.copy_from_slice(&signature[32..]);
(r, s)
} else {
noxtls_parse_ecdsa_signature_der(signature)?
};
noxtls_p256_ecdsa_verify_sha256(&public_key, &signed_message, &r, &s).map_err(
|_| {
Error::CryptoFailure(
"tls13 client certificate verify signature validation failed",
)
},
)
}
_ => Err(Error::UnsupportedFeature(
"unsupported tls13 client certificate verify signature scheme",
)),
}
}
#[must_use]
pub fn noxtls_build_tls13_compatibility_change_cipher_spec() -> [u8; 6] {
[
RecordContentType::ChangeCipherSpec.to_u8(),
0x03,
0x03,
0x00,
0x01,
0x01,
]
}
pub fn noxtls_recv_client_finished_message(&mut self, msg: &[u8]) -> Result<()> {
if self.tls_role != TlsRole::Server {
return Err(Error::StateError(
"client finished processing requires server-role connection",
));
}
let (handshake_type, body) = noxtls_parse_handshake_message(msg)?;
if handshake_type != HANDSHAKE_FINISHED {
return Err(Error::ParseFailure("invalid finished type"));
}
if self.state != HandshakeState::KeysDerived {
return Err(Error::StateError(
"client finished can only be processed after server handshake flight",
));
}
let expected = self.noxtls_compute_expected_client_finished()?;
if body.len() != expected.len() {
return Err(Error::ParseFailure("finished verify_data length mismatch"));
}
if !noxtls_constant_time_eq(body, &expected) {
return Err(Error::CryptoFailure("client finished verify_data mismatch"));
}
self.noxtls_install_tls13_application_traffic_keys()?;
self.noxtls_append_transcript(msg);
self.state = HandshakeState::Finished;
Ok(())
}
pub fn noxtls_recv_client_finished_packet(&mut self, packet: &[u8]) -> Result<()> {
if self.tls13_server_requested_client_certificate {
return self.noxtls_recv_tls13_client_authentication_packet(packet);
}
let aad = Self::noxtls_tls13_packet_header_aad(packet)?;
let (inner, content_type) = self.noxtls_open_client_tls13_record_packet(packet, &aad)?;
if content_type != RecordContentType::Handshake.to_u8() {
return Err(Error::ParseFailure(
"expected handshake content in client finished record",
));
}
let messages = split_tls13_handshake_payload(&inner)?;
let finished = messages.last().ok_or(Error::ParseFailure(
"client finished record missing handshake message",
))?;
self.noxtls_recv_client_finished_message(finished)
}
#[must_use]
pub fn noxtls_cipher_suite_display_name(&self) -> Option<&'static str> {
self.noxtls_selected_cipher_suite.map(|suite| match suite {
CipherSuite::TlsAes128GcmSha256 => "TLS_AES_128_GCM_SHA256",
CipherSuite::TlsAes256GcmSha384 => "TLS_AES_256_GCM_SHA384",
CipherSuite::TlsChacha20Poly1305Sha256 => "TLS_CHACHA20_POLY1305_SHA256",
CipherSuite::TlsEcdheRsaWithAes128GcmSha256 => "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
CipherSuite::TlsEcdheRsaWithAes256GcmSha384 => "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
CipherSuite::TlsEcdheRsaWithAes128CbcSha => "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
CipherSuite::TlsEcdheRsaWithChacha20Poly1305Sha256 => {
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"
}
CipherSuite::TlsRsaWithAes128CbcSha => "TLS_RSA_WITH_AES_128_CBC_SHA",
CipherSuite::TlsEcdheEcdsaWithAes128GcmSha256 => {
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
}
CipherSuite::TlsEcdheEcdsaWithAes256GcmSha384 => {
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"
}
CipherSuite::TlsEcdheEcdsaWithAes128CcmSha256 => "TLS_ECDHE_ECDSA_WITH_AES_128_CCM",
CipherSuite::TlsEcdheEcdsaWithAes256CcmSha256 => "TLS_ECDHE_ECDSA_WITH_AES_256_CCM",
CipherSuite::TlsEcdheEcdsaWithAes128Ccm8Sha256 => "TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8",
CipherSuite::TlsEcdheEcdsaWithAes256Ccm8Sha256 => "TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8",
CipherSuite::TlsEcdheEcdsaWithChacha20Poly1305Sha256 => {
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256"
}
CipherSuite::TlsDheRsaWithChacha20Poly1305Sha256 => {
"TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256"
}
CipherSuite::TlsDheRsaWithAes128GcmSha256 => "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
CipherSuite::TlsDheRsaWithAes256GcmSha384 => "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",
CipherSuite::TlsRsaWithAes128GcmSha256 => "TLS_RSA_WITH_AES_128_GCM_SHA256",
CipherSuite::TlsRsaWithAes256GcmSha384 => "TLS_RSA_WITH_AES_256_GCM_SHA384",
CipherSuite::TlsRsaWithAes128CcmSha256 => "TLS_RSA_WITH_AES_128_CCM",
CipherSuite::TlsRsaWithAes256CcmSha256 => "TLS_RSA_WITH_AES_256_CCM",
CipherSuite::TlsRsaWithAes128Ccm8Sha256 => "TLS_RSA_WITH_AES_128_CCM_8",
CipherSuite::TlsRsaWithAes256Ccm8Sha256 => "TLS_RSA_WITH_AES_256_CCM_8",
CipherSuite::TlsDheRsaWithAes128CcmSha256 => "TLS_DHE_RSA_WITH_AES_128_CCM",
CipherSuite::TlsDheRsaWithAes256CcmSha256 => "TLS_DHE_RSA_WITH_AES_256_CCM",
CipherSuite::TlsDheRsaWithAes128Ccm8Sha256 => "TLS_DHE_RSA_WITH_AES_128_CCM_8",
CipherSuite::TlsDheRsaWithAes256Ccm8Sha256 => "TLS_DHE_RSA_WITH_AES_256_CCM_8",
CipherSuite::TlsPskWithAes128Ccm8Sha256 => "TLS_PSK_WITH_AES_128_CCM_8",
CipherSuite::TlsEcjpakeWithAes128Ccm8Sha256 => "TLS_ECJPAKE_WITH_AES_128_CCM_8",
})
}
fn noxtls_negotiate_tls13_server_key_share(
&mut self,
client_hello: &[u8],
server_random: &[u8],
) -> Result<(u16, Vec<u8>, Vec<u8>)> {
if let Some(peer_key) = noxtls_extract_tls13_client_hello_key_share(
client_hello,
TLS13_KEY_SHARE_GROUP_X25519_MLKEM768_HYBRID,
)? {
let (shared, key_exchange) =
noxtls_negotiate_tls13_server_x25519_mlkem768_key_share(server_random, &peer_key)?;
self.tls13_server_x25519_private = None;
self.tls13_server_p256_private = None;
return Ok((
TLS13_KEY_SHARE_GROUP_X25519_MLKEM768_HYBRID,
shared,
key_exchange,
));
}
if let Some(peer_key) = noxtls_extract_tls13_client_hello_key_share(
client_hello,
TLS13_KEY_SHARE_GROUP_SECP256R1_MLKEM768_HYBRID,
)? {
let (shared, key_exchange) =
noxtls_negotiate_tls13_server_secp256r1_mlkem768_key_share(
server_random,
&peer_key,
)?;
self.tls13_server_x25519_private = None;
self.tls13_server_p256_private = None;
return Ok((
TLS13_KEY_SHARE_GROUP_SECP256R1_MLKEM768_HYBRID,
shared,
key_exchange,
));
}
if let Some(peer_key) = noxtls_extract_tls13_client_hello_key_share(
client_hello,
TLS13_KEY_SHARE_GROUP_SECP384R1_MLKEM1024_HYBRID,
)? {
let (shared, key_exchange) =
noxtls_negotiate_tls13_server_secp384r1_mlkem1024_key_share(
server_random,
&peer_key,
)?;
self.tls13_server_x25519_private = None;
self.tls13_server_p256_private = None;
return Ok((
TLS13_KEY_SHARE_GROUP_SECP384R1_MLKEM1024_HYBRID,
shared,
key_exchange,
));
}
if let Some(peer_key) =
noxtls_extract_tls13_client_hello_key_share(client_hello, TLS13_KEY_SHARE_GROUP_X25519)?
{
let private =
noxtls_derive_deterministic_x25519_private(server_random, b"tls13 server x25519");
let public = private.public_key().bytes;
let shared = noxtls_derive_tls13_x25519_shared_secret(private, &peer_key)?.to_vec();
self.tls13_server_x25519_private = None;
self.tls13_server_p256_private = None;
return Ok((TLS13_KEY_SHARE_GROUP_X25519, shared, public.to_vec()));
}
#[cfg(feature = "hazardous-legacy-crypto")]
if let Some(peer_key) =
noxtls_extract_tls13_client_hello_key_share(client_hello, TLS13_KEY_SHARE_GROUP_X448)?
{
let private =
noxtls_derive_deterministic_x448_private(server_random, b"tls13 server x448");
let public = private.public_key().bytes;
let shared = noxtls_derive_tls13_x448_shared_secret(private, &peer_key)?.to_vec();
self.tls13_server_x25519_private = None;
self.tls13_server_p256_private = None;
return Ok((TLS13_KEY_SHARE_GROUP_X448, shared, public.to_vec()));
}
if let Some(peer_key) = noxtls_extract_tls13_client_hello_key_share(
client_hello,
TLS13_KEY_SHARE_GROUP_SECP256R1,
)? {
let private =
noxtls_derive_deterministic_p256_private(server_random, b"tls13 server secp256r1")?;
let public = private.public_key()?.to_uncompressed()?;
let shared = noxtls_derive_tls13_p256_shared_secret(&private, &peer_key)?.to_vec();
self.tls13_server_p256_private = Some(private);
self.tls13_server_x25519_private = None;
return Ok((TLS13_KEY_SHARE_GROUP_SECP256R1, shared, public.to_vec()));
}
if let Some(peer_key) = noxtls_extract_tls13_client_hello_key_share(
client_hello,
TLS13_KEY_SHARE_GROUP_SECP384R1,
)? {
let private =
noxtls_derive_deterministic_p384_private(server_random, b"tls13 server secp384r1")?;
let public = private.public_key()?.to_uncompressed()?;
let shared = noxtls_derive_tls13_p384_shared_secret(&private, &peer_key)?.to_vec();
self.tls13_server_p256_private = None;
self.tls13_server_x25519_private = None;
return Ok((TLS13_KEY_SHARE_GROUP_SECP384R1, shared, public.to_vec()));
}
if let Some(peer_key) = noxtls_extract_tls13_client_hello_key_share(
client_hello,
TLS13_KEY_SHARE_GROUP_SECP521R1,
)? {
let private =
noxtls_derive_deterministic_p521_private(server_random, b"tls13 server secp521r1")?;
let public = private.public_key()?.to_uncompressed()?;
let shared = noxtls_derive_tls13_p521_shared_secret(&private, &peer_key)?;
self.tls13_server_p256_private = None;
self.tls13_server_x25519_private = None;
return Ok((TLS13_KEY_SHARE_GROUP_SECP521R1, shared, public));
}
if let Some(peer_key) = noxtls_extract_tls13_client_hello_key_share(
client_hello,
TLS13_KEY_SHARE_GROUP_BRAINPOOLP256R1TLS13,
)? {
let private = noxtls_derive_deterministic_brainpoolp256r1_private(
server_random,
b"tls13 server brainpoolP256r1",
)?;
let public = private.public_key()?.to_uncompressed()?;
let shared = noxtls_derive_tls13_named_ec_shared_secret(
NamedCurve::BrainpoolP256R1,
&private,
&peer_key,
)?;
self.tls13_server_p256_private = None;
self.tls13_server_x25519_private = None;
return Ok((TLS13_KEY_SHARE_GROUP_BRAINPOOLP256R1TLS13, shared, public));
}
if let Some(peer_key) = noxtls_extract_tls13_client_hello_key_share(
client_hello,
TLS13_KEY_SHARE_GROUP_BRAINPOOLP384R1TLS13,
)? {
let private = noxtls_derive_deterministic_brainpoolp384r1_private(
server_random,
b"tls13 server brainpoolP384r1",
)?;
let public = private.public_key()?.to_uncompressed()?;
let shared = noxtls_derive_tls13_named_ec_shared_secret(
NamedCurve::BrainpoolP384R1,
&private,
&peer_key,
)?;
self.tls13_server_p256_private = None;
self.tls13_server_x25519_private = None;
return Ok((TLS13_KEY_SHARE_GROUP_BRAINPOOLP384R1TLS13, shared, public));
}
if let Some(peer_key) = noxtls_extract_tls13_client_hello_key_share(
client_hello,
TLS13_KEY_SHARE_GROUP_BRAINPOOLP512R1TLS13,
)? {
let private = noxtls_derive_deterministic_brainpoolp512r1_private(
server_random,
b"tls13 server brainpoolP512r1",
)?;
let public = private.public_key()?.to_uncompressed()?;
let shared = noxtls_derive_tls13_named_ec_shared_secret(
NamedCurve::BrainpoolP512R1,
&private,
&peer_key,
)?;
self.tls13_server_p256_private = None;
self.tls13_server_x25519_private = None;
return Ok((TLS13_KEY_SHARE_GROUP_BRAINPOOLP512R1TLS13, shared, public));
}
Err(Error::ParseFailure(
"client hello does not offer a supported hybrid pq, x25519, x448, secp256r1, secp384r1, secp521r1, or brainpool tls13 key share",
))
}
fn noxtls_pick_server_alpn_protocol(&mut self) -> Option<Vec<u8>> {
let preferred: Vec<&[u8]> = self
.tls13_server_alpn_protocols
.iter()
.map(Vec::as_slice)
.collect();
if let Ok(Some(selected)) = Self::noxtls_select_server_alpn_protocol_from_offers(
&self.tls13_client_alpn_protocols,
&preferred,
) {
self.noxtls_tls13_selected_alpn_protocol = Some(selected.clone());
return Some(selected);
}
None
}
fn noxtls_build_server_certificate_verify_handshake_message(&self) -> Result<Vec<u8>> {
let signing_key = self
.tls13_server_signing_key
.as_ref()
.ok_or(Error::StateError("server signing key is not configured"))?;
let signed_message =
noxtls_build_tls13_server_certificate_verify_message(&self.noxtls_transcript_hash());
let (signature_scheme, signature) = match signing_key {
Tls13ServerIdentityKey::P256(private_key) => {
let (r, s) = noxtls_p256_ecdsa_sign_sha256(private_key, &signed_message)?;
let signature = noxtls_encode_ecdsa_signature_der(&r, &s)?;
(TLS13_SIGALG_ECDSA_SECP256R1_SHA256, signature)
}
Tls13ServerIdentityKey::P384(private_key) => {
if !self
.tls13_client_signature_algorithms
.contains(&TLS13_SIGALG_ECDSA_SECP384R1_SHA384)
{
return Err(Error::UnsupportedFeature(
"client did not offer ECDSA P-384/SHA-384 for the configured server identity",
));
}
let (r, s) = noxtls_p384_ecdsa_sign_sha384(private_key, &signed_message)?;
let signature = noxtls_encode_ecdsa_signature_der(&r, &s)?;
(TLS13_SIGALG_ECDSA_SECP384R1_SHA384, signature)
}
Tls13ServerIdentityKey::P521(private_key) => {
if !self
.tls13_client_signature_algorithms
.contains(&TLS13_SIGALG_ECDSA_SECP521R1_SHA512)
{
return Err(Error::UnsupportedFeature(
"client did not offer ECDSA P-521/SHA-512 for the configured server identity",
));
}
let (r, s) = noxtls_secp521r1_ecdsa_sign_sha512(private_key, &signed_message)?;
let signature = noxtls_encode_ecdsa_signature_der(&r, &s)?;
(TLS13_SIGALG_ECDSA_SECP521R1_SHA512, signature)
}
Tls13ServerIdentityKey::Rsa(private_key) => {
if self
.tls13_client_signature_algorithms
.contains(&TLS13_SIGALG_RSA_PSS_RSAE_SHA256)
{
let hash = self.noxtls_transcript_hash();
let mut salt = [0_u8; 32];
let copy_len = hash.len().min(32);
salt[..copy_len].copy_from_slice(&hash[..copy_len]);
let signature =
noxtls_rsassa_pss_sha256_sign(private_key, &signed_message, &salt)?;
(TLS13_SIGALG_RSA_PSS_RSAE_SHA256, signature)
} else if self
.tls13_client_signature_algorithms
.contains(&TLS13_SIGALG_RSA_PSS_RSAE_SHA384)
{
let hash = self.noxtls_transcript_hash();
let mut salt = [0_u8; 48];
let copy_len = hash.len().min(48);
salt[..copy_len].copy_from_slice(&hash[..copy_len]);
let signature = noxtls_rsassa_pss_sign(
private_key,
&signed_message,
&salt,
RsaPssHashAlgorithm::Sha384,
RsaPssHashAlgorithm::Sha384,
)?;
(TLS13_SIGALG_RSA_PSS_RSAE_SHA384, signature)
} else if self
.tls13_client_signature_algorithms
.contains(&TLS13_SIGALG_RSA_PSS_RSAE_SHA512)
{
let hash = self.noxtls_transcript_hash();
let mut salt = [0_u8; 64];
let copy_len = hash.len().min(64);
salt[..copy_len].copy_from_slice(&hash[..copy_len]);
let signature = noxtls_rsassa_pss_sign(
private_key,
&signed_message,
&salt,
RsaPssHashAlgorithm::Sha512,
RsaPssHashAlgorithm::Sha512,
)?;
(TLS13_SIGALG_RSA_PSS_RSAE_SHA512, signature)
} else {
return Err(Error::UnsupportedFeature(
"client did not offer an RSA-PSS-RSAE signature scheme supported by this server",
));
}
}
Tls13ServerIdentityKey::RsaPss(private_key) => {
if self
.tls13_client_signature_algorithms
.contains(&TLS13_SIGALG_RSA_PSS_PSS_SHA256)
{
let hash = self.noxtls_transcript_hash();
let mut salt = [0_u8; 32];
let copy_len = hash.len().min(32);
salt[..copy_len].copy_from_slice(&hash[..copy_len]);
let signature =
noxtls_rsassa_pss_sha256_sign(private_key, &signed_message, &salt)?;
(TLS13_SIGALG_RSA_PSS_PSS_SHA256, signature)
} else if self
.tls13_client_signature_algorithms
.contains(&TLS13_SIGALG_RSA_PSS_PSS_SHA384)
{
let hash = self.noxtls_transcript_hash();
let mut salt = [0_u8; 48];
let copy_len = hash.len().min(48);
salt[..copy_len].copy_from_slice(&hash[..copy_len]);
let signature = noxtls_rsassa_pss_sign(
private_key,
&signed_message,
&salt,
RsaPssHashAlgorithm::Sha384,
RsaPssHashAlgorithm::Sha384,
)?;
(TLS13_SIGALG_RSA_PSS_PSS_SHA384, signature)
} else if self
.tls13_client_signature_algorithms
.contains(&TLS13_SIGALG_RSA_PSS_PSS_SHA512)
{
let hash = self.noxtls_transcript_hash();
let mut salt = [0_u8; 64];
let copy_len = hash.len().min(64);
salt[..copy_len].copy_from_slice(&hash[..copy_len]);
let signature = noxtls_rsassa_pss_sign(
private_key,
&signed_message,
&salt,
RsaPssHashAlgorithm::Sha512,
RsaPssHashAlgorithm::Sha512,
)?;
(TLS13_SIGALG_RSA_PSS_PSS_SHA512, signature)
} else {
return Err(Error::UnsupportedFeature(
"client did not offer an RSA-PSS-PSS signature scheme supported by this server",
));
}
}
};
Self::noxtls_build_certificate_verify_message(signature_scheme, &signature)
}
fn noxtls_tls13_server_identity_signature_scheme_offered(&self, offered: &[u16]) -> bool {
match self.tls13_server_signing_key.as_ref() {
Some(Tls13ServerIdentityKey::P256(_)) => {
offered.contains(&TLS13_SIGALG_ECDSA_SECP256R1_SHA256)
}
Some(Tls13ServerIdentityKey::P384(_)) => {
offered.contains(&TLS13_SIGALG_ECDSA_SECP384R1_SHA384)
}
Some(Tls13ServerIdentityKey::P521(_)) => {
offered.contains(&TLS13_SIGALG_ECDSA_SECP521R1_SHA512)
}
Some(Tls13ServerIdentityKey::Rsa(_)) => {
offered.contains(&TLS13_SIGALG_RSA_PSS_RSAE_SHA256)
|| offered.contains(&TLS13_SIGALG_RSA_PSS_RSAE_SHA384)
|| offered.contains(&TLS13_SIGALG_RSA_PSS_RSAE_SHA512)
}
Some(Tls13ServerIdentityKey::RsaPss(_)) => {
offered.contains(&TLS13_SIGALG_RSA_PSS_PSS_SHA256)
|| offered.contains(&TLS13_SIGALG_RSA_PSS_PSS_SHA384)
|| offered.contains(&TLS13_SIGALG_RSA_PSS_PSS_SHA512)
}
None => false,
}
}
fn noxtls_build_tls13_server_handshake_record_aad(
&self,
inner_plaintext_len: usize,
) -> Result<[u8; TLS_RECORD_HEADER_LEN]> {
let payload_len = inner_plaintext_len
.checked_add(1)
.and_then(|v| v.checked_add(TLS13_RECORD_TAG_LEN))
.ok_or(Error::InvalidLength(
"tls13 server handshake payload length overflow",
))?;
let payload_len_u16 = u16::try_from(payload_len).map_err(|_| {
Error::InvalidLength("tls13 server handshake payload exceeds u16 length")
})?;
let mut aad = [0_u8; TLS_RECORD_HEADER_LEN];
aad[0] = RecordContentType::ApplicationData.to_u8();
aad[1] = 0x03;
aad[2] = 0x03;
aad[3..5].copy_from_slice(&payload_len_u16.to_be_bytes());
Ok(aad)
}
pub fn noxtls_tls13_packet_header_aad(packet: &[u8]) -> Result<[u8; TLS_RECORD_HEADER_LEN]> {
if packet.len() < TLS_RECORD_HEADER_LEN {
return Err(Error::ParseFailure("tls13 packet too short for header"));
}
let mut aad = [0_u8; TLS_RECORD_HEADER_LEN];
aad.copy_from_slice(&packet[..TLS_RECORD_HEADER_LEN]);
let payload_len = u16::from_be_bytes([aad[3], aad[4]]) as usize;
if packet.len() != TLS_RECORD_HEADER_LEN.saturating_add(payload_len) {
return Err(Error::ParseFailure("tls13 packet length mismatch"));
}
Ok(aad)
}
}
fn noxtls_tls13_mlkem_encapsulation_drbg(
server_random: &[u8],
label: &'static [u8],
) -> Result<HmacDrbgSha256> {
HmacDrbgSha256::noxtls_new(server_random, label, b"tls13 server mlkem encapsulation")
}
fn noxtls_negotiate_tls13_server_x25519_mlkem768_key_share(
server_random: &[u8],
peer_key_exchange: &[u8],
) -> Result<(Vec<u8>, Vec<u8>)> {
if peer_key_exchange.len() != MLKEM_PUBLIC_KEY_LEN + 32 {
return Err(Error::ParseFailure(
"x25519mlkem768 client key_share has invalid length",
));
}
let peer_mlkem = MlKemPublicKey::from_bytes_for_parameter_set(
MlKemParameterSet::MlKem768,
&peer_key_exchange[..MLKEM_PUBLIC_KEY_LEN],
)?;
let peer_x25519 = &peer_key_exchange[MLKEM_PUBLIC_KEY_LEN..];
let x25519_private =
noxtls_derive_deterministic_x25519_private(server_random, b"tls13 server x25519mlkem768");
let x25519_public = x25519_private.public_key().bytes;
let x25519_shared = noxtls_derive_tls13_x25519_shared_secret(x25519_private, peer_x25519)?;
let mut drbg =
noxtls_tls13_mlkem_encapsulation_drbg(server_random, b"x25519mlkem768 encapsulation")?;
let (mlkem_ciphertext, mlkem_shared) = noxtls_mlkem_encapsulate_auto(&peer_mlkem, &mut drbg)?;
let mut shared = Vec::with_capacity(mlkem_shared.len() + x25519_shared.len());
shared.extend_from_slice(&mlkem_shared);
shared.extend_from_slice(&x25519_shared);
let mut key_exchange = Vec::with_capacity(mlkem_ciphertext.len() + x25519_public.len());
key_exchange.extend_from_slice(&mlkem_ciphertext);
key_exchange.extend_from_slice(&x25519_public);
Ok((shared, key_exchange))
}
fn noxtls_negotiate_tls13_server_secp256r1_mlkem768_key_share(
server_random: &[u8],
peer_key_exchange: &[u8],
) -> Result<(Vec<u8>, Vec<u8>)> {
if peer_key_exchange.len() != 65 + MLKEM_PUBLIC_KEY_LEN {
return Err(Error::ParseFailure(
"secp256r1mlkem768 client key_share has invalid length",
));
}
let peer_p256 = &peer_key_exchange[..65];
let peer_mlkem = MlKemPublicKey::from_bytes_for_parameter_set(
MlKemParameterSet::MlKem768,
&peer_key_exchange[65..],
)?;
let p256_private =
noxtls_derive_deterministic_p256_private(server_random, b"tls13 server secp256r1mlkem768")?;
let p256_public = p256_private.public_key()?.to_uncompressed()?;
let p256_shared = noxtls_derive_tls13_p256_shared_secret(&p256_private, peer_p256)?;
let mut drbg =
noxtls_tls13_mlkem_encapsulation_drbg(server_random, b"secp256r1mlkem768 encapsulation")?;
let (mlkem_ciphertext, mlkem_shared) = noxtls_mlkem_encapsulate_auto(&peer_mlkem, &mut drbg)?;
let mut shared = Vec::with_capacity(p256_shared.len() + mlkem_shared.len());
shared.extend_from_slice(&p256_shared);
shared.extend_from_slice(&mlkem_shared);
let mut key_exchange = Vec::with_capacity(p256_public.len() + mlkem_ciphertext.len());
key_exchange.extend_from_slice(&p256_public);
key_exchange.extend_from_slice(&mlkem_ciphertext);
Ok((shared, key_exchange))
}
fn noxtls_negotiate_tls13_server_secp384r1_mlkem1024_key_share(
server_random: &[u8],
peer_key_exchange: &[u8],
) -> Result<(Vec<u8>, Vec<u8>)> {
if peer_key_exchange.len() != 97 + MLKEM1024_PUBLIC_KEY_LEN {
return Err(Error::ParseFailure(
"secp384r1mlkem1024 client key_share has invalid length",
));
}
let peer_p384 = &peer_key_exchange[..97];
let peer_mlkem = MlKemPublicKey::from_bytes_for_parameter_set(
MlKemParameterSet::MlKem1024,
&peer_key_exchange[97..],
)?;
let p384_private = noxtls_derive_deterministic_p384_private(
server_random,
b"tls13 server secp384r1mlkem1024",
)?;
let p384_public = p384_private.public_key()?.to_uncompressed()?;
let p384_shared = noxtls_derive_tls13_p384_shared_secret(&p384_private, peer_p384)?;
let mut drbg =
noxtls_tls13_mlkem_encapsulation_drbg(server_random, b"secp384r1mlkem1024 encapsulation")?;
let (mlkem_ciphertext, mlkem_shared) = noxtls_mlkem_encapsulate_auto(&peer_mlkem, &mut drbg)?;
let mut shared = Vec::with_capacity(p384_shared.len() + mlkem_shared.len());
shared.extend_from_slice(&p384_shared);
shared.extend_from_slice(&mlkem_shared);
let mut key_exchange = Vec::with_capacity(p384_public.len() + mlkem_ciphertext.len());
key_exchange.extend_from_slice(&p384_public);
key_exchange.extend_from_slice(&mlkem_ciphertext);
Ok((shared, key_exchange))
}
fn noxtls_extract_tls13_client_hello_key_share(
message: &[u8],
group: u16,
) -> Result<Option<Vec<u8>>> {
let (handshake_type, body) = noxtls_parse_handshake_message(message)?;
if handshake_type != HANDSHAKE_CLIENT_HELLO {
return Err(Error::ParseFailure(
"expected client hello while extracting key share",
));
}
if body.len() < 39 {
return Err(Error::ParseFailure("client hello body too short"));
}
let mut offset = 0_usize;
offset = offset.saturating_add(2);
offset = offset.saturating_add(32);
let session_id_len = body.get(offset).copied().ok_or(Error::ParseFailure(
"client hello missing session_id length",
))? as usize;
offset = offset.saturating_add(1 + session_id_len);
if body.len().saturating_sub(offset) < 2 {
return Err(Error::ParseFailure(
"client hello missing cipher_suites length",
));
}
let suites_len = u16::from_be_bytes([body[offset], body[offset + 1]]) as usize;
offset = offset.saturating_add(2 + suites_len);
if body.len().saturating_sub(offset) < 1 {
return Err(Error::ParseFailure(
"client hello missing compression_methods length",
));
}
let compression_len = body[offset] as usize;
offset = offset.saturating_add(1 + compression_len);
if body.len().saturating_sub(offset) < 2 {
return Err(Error::ParseFailure(
"client hello missing extensions length",
));
}
let extensions_len = u16::from_be_bytes([body[offset], body[offset + 1]]) as usize;
offset = offset.saturating_add(2);
if body.len().saturating_sub(offset) < extensions_len {
return Err(Error::ParseFailure("client hello extensions truncated"));
}
let mut cursor = &body[offset..offset + extensions_len];
while !cursor.is_empty() {
if cursor.len() < 4 {
return Err(Error::ParseFailure(
"client hello extension header truncated",
));
}
let extension_type = u16::from_be_bytes([cursor[0], cursor[1]]);
let extension_len = u16::from_be_bytes([cursor[2], cursor[3]]) as usize;
cursor = &cursor[4..];
if cursor.len() < extension_len {
return Err(Error::ParseFailure("client hello extension truncated"));
}
let extension_data = &cursor[..extension_len];
if extension_type == EXT_KEY_SHARE {
if extension_data.len() < 2 {
return Err(Error::ParseFailure(
"client hello key_share extension missing vector length",
));
}
let key_share_list_len =
u16::from_be_bytes([extension_data[0], extension_data[1]]) as usize;
if extension_data.len() != key_share_list_len + 2 {
return Err(Error::ParseFailure(
"client hello key_share extension length mismatch",
));
}
let mut shares = &extension_data[2..];
while !shares.is_empty() {
if shares.len() < 4 {
return Err(Error::ParseFailure(
"client hello key_share entry truncated",
));
}
let entry_group = u16::from_be_bytes([shares[0], shares[1]]);
let key_exchange_len = u16::from_be_bytes([shares[2], shares[3]]) as usize;
shares = &shares[4..];
if shares.len() < key_exchange_len {
return Err(Error::ParseFailure(
"client hello key_share key_exchange truncated",
));
}
if entry_group == group {
return Ok(Some(shares[..key_exchange_len].to_vec()));
}
shares = &shares[key_exchange_len..];
}
return Ok(None);
}
cursor = &cursor[extension_len..];
}
Ok(None)
}
fn noxtls_parse_client_hello_extension_order(message: &[u8]) -> Result<Vec<u16>> {
let (handshake_type, body) = noxtls_parse_handshake_message(message)?;
if handshake_type != HANDSHAKE_CLIENT_HELLO {
return Err(Error::ParseFailure(
"expected client hello while parsing extension order",
));
}
if body.len() < 39 {
return Err(Error::ParseFailure("client hello body too short"));
}
let mut offset = 0_usize;
offset = offset.saturating_add(2);
offset = offset.saturating_add(32);
let session_id_len = body.get(offset).copied().ok_or(Error::ParseFailure(
"client hello missing session_id length",
))? as usize;
offset = offset.saturating_add(1 + session_id_len);
if body.len().saturating_sub(offset) < 2 {
return Err(Error::ParseFailure(
"client hello missing cipher_suites length",
));
}
let suites_len = u16::from_be_bytes([body[offset], body[offset + 1]]) as usize;
offset = offset.saturating_add(2 + suites_len);
if body.len().saturating_sub(offset) < 1 {
return Err(Error::ParseFailure(
"client hello missing compression_methods length",
));
}
let compression_len = body[offset] as usize;
offset = offset.saturating_add(1 + compression_len);
if body.len().saturating_sub(offset) < 2 {
return Err(Error::ParseFailure(
"client hello missing extensions length",
));
}
let extensions_len = u16::from_be_bytes([body[offset], body[offset + 1]]) as usize;
offset = offset.saturating_add(2);
if body.len().saturating_sub(offset) < extensions_len {
return Err(Error::ParseFailure("client hello extensions truncated"));
}
let mut order = Vec::new();
let mut cursor = &body[offset..offset + extensions_len];
while !cursor.is_empty() {
if cursor.len() < 4 {
return Err(Error::ParseFailure(
"client hello extension header truncated",
));
}
let extension_type = u16::from_be_bytes([cursor[0], cursor[1]]);
let extension_len = u16::from_be_bytes([cursor[2], cursor[3]]) as usize;
cursor = &cursor[4..];
if cursor.len() < extension_len {
return Err(Error::ParseFailure("client hello extension truncated"));
}
order.push(extension_type);
cursor = &cursor[extension_len..];
}
Ok(order)
}
const TLS13_RECORD_TAG_LEN: usize = 16;