lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README

client.rs (48371B)


      1 use crate::error::RadrootsSimplexSmpTransportError;
      2 use crate::executor::{
      3     RadrootsSimplexSmpCommandTransport, RadrootsSimplexSmpSubscriptionReceiveRequest,
      4     RadrootsSimplexSmpSubscriptionTransport, RadrootsSimplexSmpTransportRequest,
      5     RadrootsSimplexSmpTransportResponse,
      6 };
      7 use crate::frame::{RADROOTS_SIMPLEX_SMP_TRANSPORT_BLOCK_SIZE, RadrootsSimplexSmpTransportBlock};
      8 use crate::handshake::{
      9     RADROOTS_SIMPLEX_SMP_TLS_ALPN_V1, RadrootsSimplexSmpClientHello, RadrootsSimplexSmpServerHello,
     10     RadrootsSimplexSmpTlsHandshakeEvidence, RadrootsSimplexSmpTlsPolicy,
     11     RadrootsSimplexSmpTransportServerProof, validate_tls_handshake,
     12 };
     13 use base64::Engine as _;
     14 use base64::engine::general_purpose::{URL_SAFE, URL_SAFE_NO_PAD};
     15 use radroots_simplex_smp_crypto::prelude::{
     16     RadrootsSimplexSmpQueueAuthorizationMaterial, RadrootsSimplexSmpQueueAuthorizationScope,
     17     RadrootsSimplexSmpSecretBoxChainKey, RadrootsSimplexSmpX25519Keypair, advance_secretbox_chain,
     18     decode_x25519_public_key_x509, derive_shared_secret, encode_x25519_public_key_x509,
     19     encrypt_padded, init_secretbox_chain, verify_signature,
     20 };
     21 use radroots_simplex_smp_proto::prelude::{
     22     RADROOTS_SIMPLEX_SMP_AUTH_COMMANDS_TRANSPORT_VERSION,
     23     RADROOTS_SIMPLEX_SMP_ENCRYPTED_BLOCK_TRANSPORT_VERSION, RadrootsSimplexSmpBrokerMessage,
     24     RadrootsSimplexSmpCommandTransmission, RadrootsSimplexSmpCorrelationId,
     25     RadrootsSimplexSmpServerAddress,
     26 };
     27 use rustls::client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier};
     28 use rustls::pki_types::{CertificateDer, ServerName, UnixTime};
     29 use rustls::{
     30     ClientConfig, ClientConnection, DigitallySignedStruct, Error as RustlsError, SignatureScheme,
     31     StreamOwned,
     32 };
     33 use sha2::{Digest, Sha256};
     34 use std::collections::{BTreeMap, VecDeque};
     35 use std::io::{ErrorKind, Read, Write};
     36 use std::net::{IpAddr, TcpStream, ToSocketAddrs};
     37 use std::sync::Arc;
     38 use std::time::Duration;
     39 use x509_parser::prelude::FromDer;
     40 
     41 #[derive(Default)]
     42 pub struct RadrootsSimplexSmpTlsCommandTransport {
     43     sessions: BTreeMap<String, RadrootsSimplexSmpLiveSession>,
     44 }
     45 
     46 const LIVE_SESSION_TIMEOUT: Duration = Duration::from_secs(5);
     47 const LIVE_EMPTY_SUBSCRIPTION_TIMEOUT: Duration = Duration::from_millis(150);
     48 
     49 struct RadrootsSimplexSmpLiveSession {
     50     stream: StreamOwned<ClientConnection, TcpStream>,
     51     transport_version: u16,
     52     session_identifier: Vec<u8>,
     53     send_chain_key: Option<RadrootsSimplexSmpSecretBoxChainKey>,
     54     receive_chain_key: Option<RadrootsSimplexSmpSecretBoxChainKey>,
     55     debug_shared_secret: Option<Vec<u8>>,
     56     pending_broker_responses: VecDeque<RadrootsSimplexSmpTransportResponse>,
     57 }
     58 
     59 impl RadrootsSimplexSmpTlsCommandTransport {
     60     pub fn new() -> Self {
     61         Self::default()
     62     }
     63 
     64     fn session_key(server: &RadrootsSimplexSmpServerAddress, kind: &str) -> String {
     65         let mut key = server.server_identity.clone();
     66         key.push('@');
     67         key.push_str(&server.hosts.join(","));
     68         key.push(':');
     69         key.push_str(&server.port.unwrap_or(5223).to_string());
     70         key.push('#');
     71         key.push_str(kind);
     72         key
     73     }
     74 
     75     fn session_for(
     76         &mut self,
     77         server: &RadrootsSimplexSmpServerAddress,
     78         kind: &str,
     79     ) -> Result<&mut RadrootsSimplexSmpLiveSession, RadrootsSimplexSmpTransportError> {
     80         let key = Self::session_key(server, kind);
     81         if !self.sessions.contains_key(&key) {
     82             let session = connect_live_session(server)?;
     83             self.sessions.insert(key.clone(), session);
     84         }
     85         self.sessions.get_mut(&key).ok_or_else(|| {
     86             RadrootsSimplexSmpTransportError::InvalidServerAddress(format!(
     87                 "missing live SMP session for `{}`",
     88                 server.server_identity
     89             ))
     90         })
     91     }
     92 }
     93 
     94 impl RadrootsSimplexSmpCommandTransport for RadrootsSimplexSmpTlsCommandTransport {
     95     type Error = RadrootsSimplexSmpTransportError;
     96 
     97     fn execute(
     98         &mut self,
     99         request: RadrootsSimplexSmpTransportRequest,
    100     ) -> Result<RadrootsSimplexSmpTransportResponse, Self::Error> {
    101         let session_kind = session_kind_for_command(&request.command);
    102         let key = Self::session_key(&request.server, session_kind);
    103         let accepts_uncorrelated_subscription_response =
    104             accepts_uncorrelated_subscription_response(&request.command);
    105         match execute_live_request(
    106             self.session_for(&request.server, session_kind)?,
    107             &request,
    108             accepts_uncorrelated_subscription_response,
    109         ) {
    110             Ok(response) => Ok(response),
    111             Err(RadrootsSimplexSmpTransportError::LiveTransportIo(error)) => {
    112                 self.sessions.remove(&key);
    113                 let response = execute_live_request(
    114                     self.session_for(&request.server, session_kind)?,
    115                     &request,
    116                     accepts_uncorrelated_subscription_response,
    117                 );
    118                 match response {
    119                     Ok(response) => Ok(response),
    120                     Err(RadrootsSimplexSmpTransportError::LiveTransportIo(_)) => {
    121                         Err(RadrootsSimplexSmpTransportError::LiveTransportIo(error))
    122                     }
    123                     Err(error) => Err(error),
    124                 }
    125             }
    126             Err(error) => Err(error),
    127         }
    128     }
    129 }
    130 
    131 impl RadrootsSimplexSmpSubscriptionTransport for RadrootsSimplexSmpTlsCommandTransport {
    132     fn receive_subscription(
    133         &mut self,
    134         request: RadrootsSimplexSmpSubscriptionReceiveRequest,
    135     ) -> Result<Option<RadrootsSimplexSmpTransportResponse>, Self::Error> {
    136         let key = Self::session_key(&request.server, "subscription");
    137         match read_live_response(
    138             self.session_for(&request.server, "subscription")?,
    139             &request.server,
    140             None,
    141             true,
    142             None,
    143         ) {
    144             Ok(response) => Ok(response),
    145             Err(RadrootsSimplexSmpTransportError::LiveTransportIo(error)) => {
    146                 self.sessions.remove(&key);
    147                 Err(RadrootsSimplexSmpTransportError::LiveTransportIo(error))
    148             }
    149             Err(error) => Err(error),
    150         }
    151     }
    152 }
    153 
    154 fn session_kind_for_command(
    155     command: &radroots_simplex_smp_proto::prelude::RadrootsSimplexSmpCommand,
    156 ) -> &'static str {
    157     match command {
    158         radroots_simplex_smp_proto::prelude::RadrootsSimplexSmpCommand::Sub
    159         | radroots_simplex_smp_proto::prelude::RadrootsSimplexSmpCommand::Subs
    160         | radroots_simplex_smp_proto::prelude::RadrootsSimplexSmpCommand::NSub
    161         | radroots_simplex_smp_proto::prelude::RadrootsSimplexSmpCommand::NSubs
    162         | radroots_simplex_smp_proto::prelude::RadrootsSimplexSmpCommand::Ack(_) => "subscription",
    163         radroots_simplex_smp_proto::prelude::RadrootsSimplexSmpCommand::Get
    164         | radroots_simplex_smp_proto::prelude::RadrootsSimplexSmpCommand::LGet => "poll",
    165         _ => "command",
    166     }
    167 }
    168 
    169 fn accepts_uncorrelated_subscription_response(
    170     command: &radroots_simplex_smp_proto::prelude::RadrootsSimplexSmpCommand,
    171 ) -> bool {
    172     matches!(
    173         command,
    174         radroots_simplex_smp_proto::prelude::RadrootsSimplexSmpCommand::Sub
    175             | radroots_simplex_smp_proto::prelude::RadrootsSimplexSmpCommand::Subs
    176             | radroots_simplex_smp_proto::prelude::RadrootsSimplexSmpCommand::NSub
    177             | radroots_simplex_smp_proto::prelude::RadrootsSimplexSmpCommand::NSubs
    178             | radroots_simplex_smp_proto::prelude::RadrootsSimplexSmpCommand::Ack(_)
    179     )
    180 }
    181 
    182 fn execute_live_request(
    183     session: &mut RadrootsSimplexSmpLiveSession,
    184     request: &RadrootsSimplexSmpTransportRequest,
    185     accept_uncorrelated_subscription_response: bool,
    186 ) -> Result<RadrootsSimplexSmpTransportResponse, RadrootsSimplexSmpTransportError> {
    187     let correlation_id = request
    188         .correlation_id
    189         .ok_or(RadrootsSimplexSmpTransportError::MissingCorrelationId)?;
    190     let scope = RadrootsSimplexSmpQueueAuthorizationScope::new(
    191         session.session_identifier.clone(),
    192         correlation_id,
    193         request.entity_id.clone(),
    194     )?;
    195     let material = RadrootsSimplexSmpQueueAuthorizationMaterial::for_command(
    196         &scope,
    197         &request.command,
    198         session.transport_version,
    199         &request.authorization,
    200     )?;
    201     let transmission = RadrootsSimplexSmpCommandTransmission {
    202         authorization: material.authorization,
    203         correlation_id: Some(correlation_id),
    204         entity_id: request.entity_id.clone(),
    205         command: request.command.clone(),
    206     };
    207     let block = RadrootsSimplexSmpTransportBlock::from_command_transmissions(
    208         &[transmission],
    209         session.transport_version,
    210     )?;
    211     let encoded = encode_live_transport_block(session, &block)?;
    212     session
    213         .stream
    214         .write_all(&encoded)
    215         .map_err(|error| RadrootsSimplexSmpTransportError::LiveTransportIo(error.to_string()))?;
    216     session
    217         .stream
    218         .flush()
    219         .map_err(|error| RadrootsSimplexSmpTransportError::LiveTransportIo(error.to_string()))?;
    220 
    221     let accepted_entity_id =
    222         accept_uncorrelated_subscription_response.then_some(request.entity_id.as_slice());
    223     read_live_response(
    224         session,
    225         &request.server,
    226         Some(correlation_id),
    227         false,
    228         accepted_entity_id,
    229     )?
    230     .ok_or_else(|| {
    231         RadrootsSimplexSmpTransportError::LiveTransportIo(
    232             "SMP command response was not available before the read timeout".into(),
    233         )
    234     })
    235 }
    236 
    237 fn read_live_response(
    238     session: &mut RadrootsSimplexSmpLiveSession,
    239     server: &RadrootsSimplexSmpServerAddress,
    240     expected_correlation_id: Option<RadrootsSimplexSmpCorrelationId>,
    241     timeout_is_empty: bool,
    242     accepted_subscription_entity_id: Option<&[u8]>,
    243 ) -> Result<Option<RadrootsSimplexSmpTransportResponse>, RadrootsSimplexSmpTransportError> {
    244     if expected_correlation_id.is_none()
    245         && let Some(response) = session.pending_broker_responses.pop_front()
    246     {
    247         return Ok(Some(response));
    248     }
    249     if let Some(entity_id) = accepted_subscription_entity_id
    250         && let Some(position) = session
    251             .pending_broker_responses
    252             .iter()
    253             .position(|response| is_subscription_response_for_entity(response, entity_id))
    254     {
    255         return Ok(session.pending_broker_responses.remove(position));
    256     }
    257     let mut response_block = vec![0_u8; RADROOTS_SIMPLEX_SMP_TRANSPORT_BLOCK_SIZE];
    258     if timeout_is_empty {
    259         set_live_read_timeout(session, LIVE_EMPTY_SUBSCRIPTION_TIMEOUT)?;
    260     }
    261     let read_result = session.stream.read_exact(&mut response_block);
    262     if timeout_is_empty {
    263         set_live_read_timeout(session, LIVE_SESSION_TIMEOUT)?;
    264     }
    265     if let Err(error) = read_result {
    266         if timeout_is_empty && matches!(error.kind(), ErrorKind::WouldBlock | ErrorKind::TimedOut) {
    267             return Ok(None);
    268         }
    269         return Err(RadrootsSimplexSmpTransportError::LiveTransportIo(
    270             error.to_string(),
    271         ));
    272     }
    273     let response_hash = Sha256::digest(&response_block).to_vec();
    274     let decoded = decode_live_transport_block(session, &response_block)?;
    275     let transmissions = decoded.decode_broker_transmissions(session.transport_version)?;
    276     let responses = transmissions
    277         .into_iter()
    278         .map(|transmission| RadrootsSimplexSmpTransportResponse {
    279             server: server.clone(),
    280             transport_version: session.transport_version,
    281             transmission,
    282             transport_hash: response_hash.clone(),
    283         })
    284         .collect::<Vec<_>>();
    285     select_live_response(
    286         &mut session.pending_broker_responses,
    287         responses,
    288         expected_correlation_id,
    289         accepted_subscription_entity_id,
    290     )
    291 }
    292 
    293 fn select_live_response(
    294     pending_broker_responses: &mut VecDeque<RadrootsSimplexSmpTransportResponse>,
    295     mut responses: Vec<RadrootsSimplexSmpTransportResponse>,
    296     expected_correlation_id: Option<RadrootsSimplexSmpCorrelationId>,
    297     accepted_subscription_entity_id: Option<&[u8]>,
    298 ) -> Result<Option<RadrootsSimplexSmpTransportResponse>, RadrootsSimplexSmpTransportError> {
    299     if let Some(expected_correlation_id) = expected_correlation_id {
    300         if let Some(position) = responses.iter().position(|response| {
    301             response.transmission.correlation_id == Some(expected_correlation_id)
    302         }) {
    303             let matched_response = responses.remove(position);
    304             pending_broker_responses.extend(responses);
    305             return Ok(Some(matched_response));
    306         }
    307         if let Some(entity_id) = accepted_subscription_entity_id
    308             && let Some(position) = responses
    309                 .iter()
    310                 .position(|response| is_subscription_response_for_entity(response, entity_id))
    311         {
    312             let matched_response = responses.remove(position);
    313             pending_broker_responses.extend(responses);
    314             return Ok(Some(matched_response));
    315         }
    316         pending_broker_responses.extend(responses);
    317         return Err(RadrootsSimplexSmpTransportError::CorrelationIdMismatch);
    318     }
    319     pending_broker_responses.extend(responses);
    320     Ok(pending_broker_responses.pop_front())
    321 }
    322 
    323 fn is_subscription_response_for_entity(
    324     response: &RadrootsSimplexSmpTransportResponse,
    325     entity_id: &[u8],
    326 ) -> bool {
    327     response.transmission.entity_id == entity_id
    328         && matches!(
    329             response.transmission.message,
    330             RadrootsSimplexSmpBrokerMessage::Msg(_)
    331                 | RadrootsSimplexSmpBrokerMessage::NMsg { .. }
    332                 | RadrootsSimplexSmpBrokerMessage::Sok(_)
    333                 | RadrootsSimplexSmpBrokerMessage::Soks(_)
    334                 | RadrootsSimplexSmpBrokerMessage::Ok
    335                 | RadrootsSimplexSmpBrokerMessage::Err(_)
    336         )
    337 }
    338 
    339 fn set_live_read_timeout(
    340     session: &mut RadrootsSimplexSmpLiveSession,
    341     timeout: Duration,
    342 ) -> Result<(), RadrootsSimplexSmpTransportError> {
    343     session
    344         .stream
    345         .sock
    346         .set_read_timeout(Some(timeout))
    347         .map_err(|error| RadrootsSimplexSmpTransportError::LiveTransportIo(error.to_string()))
    348 }
    349 
    350 fn transport_debug_enabled() -> bool {
    351     std::env::var_os("RADROOTS_SIMPLEX_DEBUG_TRANSPORT").is_some()
    352 }
    353 
    354 fn debug_sha256_label(label: &str, value: &[u8]) {
    355     if transport_debug_enabled() {
    356         eprintln!(
    357             "[simplex-smp-transport] {label}: len={} sha256={}",
    358             value.len(),
    359             URL_SAFE_NO_PAD.encode(Sha256::digest(value)),
    360         );
    361     }
    362 }
    363 
    364 fn encode_live_transport_block(
    365     session: &mut RadrootsSimplexSmpLiveSession,
    366     block: &RadrootsSimplexSmpTransportBlock,
    367 ) -> Result<Vec<u8>, RadrootsSimplexSmpTransportError> {
    368     if session.transport_version >= RADROOTS_SIMPLEX_SMP_ENCRYPTED_BLOCK_TRANSPORT_VERSION
    369         && let Some(chain_key) = session.send_chain_key.as_mut()
    370     {
    371         return encode_encrypted_transport_payload(chain_key, &block.encode_payload()?);
    372     }
    373     block.encode()
    374 }
    375 
    376 fn encode_encrypted_transport_payload(
    377     chain_key: &mut RadrootsSimplexSmpSecretBoxChainKey,
    378     payload: &[u8],
    379 ) -> Result<Vec<u8>, RadrootsSimplexSmpTransportError> {
    380     let ((secretbox_key, nonce), next_chain_key) = advance_secretbox_chain(chain_key)?;
    381     *chain_key = next_chain_key;
    382     encrypt_padded(
    383         &secretbox_key,
    384         &nonce,
    385         payload,
    386         RADROOTS_SIMPLEX_SMP_TRANSPORT_BLOCK_SIZE - 16,
    387     )
    388     .map_err(Into::into)
    389 }
    390 
    391 fn decode_live_transport_block(
    392     session: &mut RadrootsSimplexSmpLiveSession,
    393     bytes: &[u8],
    394 ) -> Result<RadrootsSimplexSmpTransportBlock, RadrootsSimplexSmpTransportError> {
    395     if session.transport_version >= RADROOTS_SIMPLEX_SMP_ENCRYPTED_BLOCK_TRANSPORT_VERSION
    396         && let Some(chain_key) = session.receive_chain_key.as_mut()
    397     {
    398         match decode_encrypted_transport_block(chain_key, bytes) {
    399             Ok(block) => {
    400                 let payload = block.encode_payload()?;
    401                 debug_sha256_label("live-response-payload", &payload);
    402                 return Ok(block);
    403             }
    404             Err(error) => {
    405                 if transport_debug_enabled() {
    406                     eprintln!("[simplex-smp-transport] live response decrypt failed: {error}");
    407                     debug_sha256_label("live-response-ciphertext", bytes);
    408                 }
    409                 if let Some(send_chain_key) = session.send_chain_key.as_ref() {
    410                     let mut alternate_chain_key = send_chain_key.clone();
    411                     if decode_encrypted_transport_block(&mut alternate_chain_key, bytes).is_ok() {
    412                         return Err(RadrootsSimplexSmpTransportError::InvalidServerAddress(
    413                             "server response decrypted with the outbound chain key; live SMP block direction is assigned incorrectly".into(),
    414                         ));
    415                     }
    416                 }
    417                 debug_probe_transport_candidates(session, bytes);
    418                 if let Ok(block) = RadrootsSimplexSmpTransportBlock::decode(bytes) {
    419                     return Err(RadrootsSimplexSmpTransportError::InvalidServerAddress(
    420                         format!(
    421                             "server returned plaintext SMP block while encrypted transport was expected: {:?}",
    422                             block.transmissions.first().map(|t| &t[..t.len().min(8)])
    423                         ),
    424                     ));
    425                 }
    426                 return Err(error);
    427             }
    428         }
    429     }
    430     RadrootsSimplexSmpTransportBlock::decode(bytes)
    431 }
    432 
    433 fn decode_encrypted_transport_block(
    434     chain_key: &mut RadrootsSimplexSmpSecretBoxChainKey,
    435     bytes: &[u8],
    436 ) -> Result<RadrootsSimplexSmpTransportBlock, RadrootsSimplexSmpTransportError> {
    437     let ((secretbox_key, nonce), next_chain_key) = advance_secretbox_chain(chain_key)?;
    438     let payload =
    439         radroots_simplex_smp_crypto::prelude::decrypt_padded(&secretbox_key, &nonce, bytes)?;
    440     let block = RadrootsSimplexSmpTransportBlock::from_payload(&payload)?;
    441     *chain_key = next_chain_key;
    442     Ok(block)
    443 }
    444 
    445 fn debug_probe_transport_candidates(session: &mut RadrootsSimplexSmpLiveSession, bytes: &[u8]) {
    446     if !transport_debug_enabled() {
    447         return;
    448     }
    449     let Some(shared_secret) = session.debug_shared_secret.as_ref() else {
    450         return;
    451     };
    452     let Ok((first_chain_key, second_chain_key)) =
    453         init_secretbox_chain(&session.session_identifier, shared_secret)
    454     else {
    455         return;
    456     };
    457     for (label, chain_key) in [
    458         ("initial-first", first_chain_key),
    459         ("initial-second", second_chain_key),
    460     ] {
    461         let Ok(((secretbox_key, nonce), _)) = advance_secretbox_chain(&chain_key) else {
    462             continue;
    463         };
    464         let result =
    465             radroots_simplex_smp_crypto::prelude::decrypt_padded(&secretbox_key, &nonce, bytes);
    466         match result {
    467             Ok(payload) => {
    468                 eprintln!("[simplex-smp-transport] debug candidate {label} decrypted live block");
    469                 debug_sha256_label("debug-candidate-payload", &payload);
    470             }
    471             Err(error) => {
    472                 eprintln!("[simplex-smp-transport] debug candidate {label} failed: {error}");
    473             }
    474         }
    475     }
    476 }
    477 
    478 fn connect_live_session(
    479     server: &RadrootsSimplexSmpServerAddress,
    480 ) -> Result<RadrootsSimplexSmpLiveSession, RadrootsSimplexSmpTransportError> {
    481     let mut last_error = None;
    482     for host in &server.hosts {
    483         match connect_live_session_host(server, host) {
    484             Ok(session) => return Ok(session),
    485             Err(error) => last_error = Some(error),
    486         }
    487     }
    488 
    489     Err(last_error.unwrap_or_else(|| {
    490         RadrootsSimplexSmpTransportError::InvalidServerAddress(format!(
    491             "SMP server `{}` has no usable hosts",
    492             server.server_identity
    493         ))
    494     }))
    495 }
    496 
    497 fn connect_live_session_host(
    498     server: &RadrootsSimplexSmpServerAddress,
    499     host: &str,
    500 ) -> Result<RadrootsSimplexSmpLiveSession, RadrootsSimplexSmpTransportError> {
    501     let port = server.port.unwrap_or(5223);
    502     let mut addresses = (host, port).to_socket_addrs().map_err(|error| {
    503         RadrootsSimplexSmpTransportError::InvalidServerAddress(format!(
    504             "failed to resolve SMP server host `{host}:{port}`: {error}"
    505         ))
    506     })?;
    507     let socket_addr = addresses.next().ok_or_else(|| {
    508         RadrootsSimplexSmpTransportError::InvalidServerAddress(format!(
    509             "failed to resolve SMP server host `{host}:{port}`"
    510         ))
    511     })?;
    512     let tcp = TcpStream::connect_timeout(&socket_addr, LIVE_SESSION_TIMEOUT).map_err(|error| {
    513         RadrootsSimplexSmpTransportError::LiveTransportIo(format!(
    514             "failed to connect to SMP server `{host}:{port}`: {error}"
    515         ))
    516     })?;
    517     tcp.set_nodelay(true)
    518         .map_err(|error| RadrootsSimplexSmpTransportError::LiveTransportIo(error.to_string()))?;
    519     tcp.set_read_timeout(Some(LIVE_SESSION_TIMEOUT))
    520         .map_err(|error| RadrootsSimplexSmpTransportError::LiveTransportIo(error.to_string()))?;
    521     tcp.set_write_timeout(Some(LIVE_SESSION_TIMEOUT))
    522         .map_err(|error| RadrootsSimplexSmpTransportError::LiveTransportIo(error.to_string()))?;
    523 
    524     let server_name = match host.parse::<IpAddr>() {
    525         Ok(address) => ServerName::IpAddress(address.into()),
    526         Err(_) => ServerName::try_from(host.to_owned()).map_err(|_| {
    527             RadrootsSimplexSmpTransportError::InvalidServerAddress(format!(
    528                 "invalid SMP server name `{host}`"
    529             ))
    530         })?,
    531     };
    532     let verifier = Arc::new(PermissiveSimplexServerVerifier);
    533     let mut config = ClientConfig::builder()
    534         .dangerous()
    535         .with_custom_certificate_verifier(verifier)
    536         .with_no_client_auth();
    537     config.alpn_protocols = vec![RADROOTS_SIMPLEX_SMP_TLS_ALPN_V1.as_bytes().to_vec()];
    538 
    539     let mut stream = StreamOwned::new(
    540         ClientConnection::new(Arc::new(config), server_name).map_err(|error| {
    541             RadrootsSimplexSmpTransportError::LiveTransportIo(error.to_string())
    542         })?,
    543         tcp,
    544     );
    545     while stream.conn.is_handshaking() {
    546         stream.conn.complete_io(&mut stream.sock).map_err(|error| {
    547             RadrootsSimplexSmpTransportError::LiveTransportIo(error.to_string())
    548         })?;
    549     }
    550 
    551     let peer_certs = stream
    552         .conn
    553         .peer_certificates()
    554         .ok_or(RadrootsSimplexSmpTransportError::MissingPeerCertificates)?
    555         .to_vec();
    556     let server_hello = read_server_hello(&mut stream)?;
    557     let actual_identity = matching_server_identity(&peer_certs, &server.server_identity)?;
    558     let expected_identity = canonical_server_identity(&server.server_identity)?;
    559     let mut policy = RadrootsSimplexSmpTlsPolicy::modern(expected_identity.clone());
    560     policy.require_tls_unique_binding = false;
    561     let transport_version = validate_tls_handshake(
    562         &policy,
    563         &server_hello,
    564         &RadrootsSimplexSmpTlsHandshakeEvidence {
    565             confirmed_alpn: stream
    566                 .conn
    567                 .alpn_protocol()
    568                 .map(|value| String::from_utf8_lossy(value).into_owned()),
    569             session_resumed: false,
    570             certificate_chain_length: peer_certs.len(),
    571             online_certificate_fingerprint: actual_identity,
    572             tls_unique_channel_binding: None,
    573         },
    574     )?;
    575     let transport_keypair =
    576         if transport_version >= RADROOTS_SIMPLEX_SMP_AUTH_COMMANDS_TRANSPORT_VERSION {
    577             Some(RadrootsSimplexSmpX25519Keypair::generate()?)
    578         } else {
    579             None
    580         };
    581     let client_hello = RadrootsSimplexSmpClientHello {
    582         chosen_version: transport_version,
    583         server_key_hash: decode_server_identity(&expected_identity)?,
    584         client_key: transport_keypair
    585             .as_ref()
    586             .map(|keypair| encode_x25519_public_key_x509(&keypair.public_key))
    587             .transpose()?,
    588         proxy_server: false,
    589         ignored_part: Vec::new(),
    590     };
    591     let encoded_client_hello = client_hello.encode()?;
    592     if transport_debug_enabled() {
    593         debug_sha256_label("client-hello", &encoded_client_hello);
    594         debug_sha256_label("server-session-id", &server_hello.session_identifier);
    595     }
    596     stream
    597         .write_all(&encoded_client_hello)
    598         .map_err(|error| RadrootsSimplexSmpTransportError::LiveTransportIo(error.to_string()))?;
    599     stream
    600         .flush()
    601         .map_err(|error| RadrootsSimplexSmpTransportError::LiveTransportIo(error.to_string()))?;
    602 
    603     let mut debug_shared_secret = None;
    604     let (receive_chain_key, send_chain_key) =
    605         if transport_version >= RADROOTS_SIMPLEX_SMP_ENCRYPTED_BLOCK_TRANSPORT_VERSION {
    606             let server_key = decode_server_transport_public_key(
    607                 server_hello
    608                     .server_proof
    609                     .as_ref()
    610                     .ok_or(RadrootsSimplexSmpTransportError::MissingServerProof)?,
    611             )?;
    612             let shared_secret = derive_shared_secret(
    613                 &transport_keypair
    614                     .as_ref()
    615                     .ok_or(RadrootsSimplexSmpTransportError::MissingServerProof)?
    616                     .private_key,
    617                 &server_key,
    618             )?;
    619             if transport_debug_enabled() {
    620                 if let Some(keypair) = transport_keypair.as_ref() {
    621                     debug_sha256_label("client-transport-public-key", &keypair.public_key);
    622                 }
    623                 debug_sha256_label("server-transport-public-key", &server_key);
    624             }
    625             debug_shared_secret = transport_debug_enabled().then_some(shared_secret.clone());
    626             let (receive_chain_key, send_chain_key) =
    627                 init_secretbox_chain(&server_hello.session_identifier, &shared_secret)?;
    628             (Some(receive_chain_key), Some(send_chain_key))
    629         } else {
    630             (None, None)
    631         };
    632 
    633     Ok(RadrootsSimplexSmpLiveSession {
    634         stream,
    635         transport_version,
    636         session_identifier: server_hello.session_identifier,
    637         send_chain_key,
    638         receive_chain_key,
    639         debug_shared_secret,
    640         pending_broker_responses: VecDeque::new(),
    641     })
    642 }
    643 
    644 fn decode_server_transport_public_key(
    645     proof: &RadrootsSimplexSmpTransportServerProof,
    646 ) -> Result<Vec<u8>, RadrootsSimplexSmpTransportError> {
    647     let (signed_object, signature) = decode_signed_server_key_parts(&proof.signed_server_key)?;
    648     if transport_debug_enabled() {
    649         eprintln!(
    650             "[simplex-smp-transport] signed-server-key: proof_len={} signed_object_len={} signature_len={}",
    651             proof.signed_server_key.len(),
    652             signed_object.len(),
    653             signature.len()
    654         );
    655     }
    656     if !proof.certificate_payload.is_empty() {
    657         let verify_key = decode_server_certificate_verify_key(&proof.certificate_payload)?;
    658         verify_signature(signed_object, &verify_key, signature).map_err(|error| {
    659             RadrootsSimplexSmpTransportError::InvalidServerAddress(format!(
    660                 "failed to verify SMP server transport key signature: {error}"
    661             ))
    662         })?;
    663     }
    664 
    665     decode_x25519_public_key_x509(signed_object)
    666         .or_else(|_| {
    667             first_der_sequence_element(signed_object)
    668                 .and_then(|candidate| decode_x25519_public_key_x509(candidate).map_err(Into::into))
    669         })
    670         .map_err(|error: RadrootsSimplexSmpTransportError| {
    671             RadrootsSimplexSmpTransportError::InvalidServerAddress(format!(
    672                 "failed to decode verified SMP server transport key: {error}"
    673             ))
    674         })
    675 }
    676 
    677 fn first_der_sequence_element(bytes: &[u8]) -> Result<&[u8], RadrootsSimplexSmpTransportError> {
    678     let (sequence_tag, _, sequence_header_end, sequence_content_end) = parse_der_element(bytes, 0)?;
    679     if sequence_tag != 0x30 {
    680         return Err(RadrootsSimplexSmpTransportError::InvalidServerAddress(
    681             "invalid SMP server proof: expected DER sequence".into(),
    682         ));
    683     }
    684     let (_, element_start, _, element_end) = parse_der_element(bytes, sequence_header_end)?;
    685     if element_end > sequence_content_end {
    686         return Err(RadrootsSimplexSmpTransportError::InvalidServerAddress(
    687             "invalid SMP server proof: first element exceeds sequence bounds".into(),
    688         ));
    689     }
    690     Ok(&bytes[element_start..element_end])
    691 }
    692 
    693 fn decode_signed_server_key_parts(
    694     bytes: &[u8],
    695 ) -> Result<(&[u8], &[u8]), RadrootsSimplexSmpTransportError> {
    696     let (sequence_tag, _, sequence_header_end, sequence_content_end) = parse_der_element(bytes, 0)?;
    697     if sequence_tag != 0x30 {
    698         return Err(RadrootsSimplexSmpTransportError::InvalidServerAddress(
    699             "invalid SMP server proof: signed key is not a DER sequence".into(),
    700         ));
    701     }
    702 
    703     let (_, signed_object_start, _, signed_object_end) =
    704         parse_der_element(bytes, sequence_header_end)?;
    705     let (_, _, _, algorithm_end) = parse_der_element(bytes, signed_object_end)?;
    706     if algorithm_end > sequence_content_end {
    707         return Err(RadrootsSimplexSmpTransportError::InvalidServerAddress(
    708             "invalid SMP server proof: signature algorithm exceeds sequence bounds".into(),
    709         ));
    710     }
    711     let (signature_tag, _, signature_value_start, signature_end) =
    712         parse_der_element(bytes, algorithm_end)?;
    713     if signature_tag != 0x03 {
    714         return Err(RadrootsSimplexSmpTransportError::InvalidServerAddress(
    715             "invalid SMP server proof: expected DER bit string signature".into(),
    716         ));
    717     }
    718     if signature_end > sequence_content_end {
    719         return Err(RadrootsSimplexSmpTransportError::InvalidServerAddress(
    720             "invalid SMP server proof: signature exceeds sequence bounds".into(),
    721         ));
    722     }
    723     let signature_value = bytes
    724         .get(signature_value_start..signature_end)
    725         .ok_or_else(|| {
    726             RadrootsSimplexSmpTransportError::InvalidServerAddress(
    727                 "invalid SMP server proof: truncated signature".into(),
    728             )
    729         })?;
    730     let (unused_bits, signature) = signature_value.split_first().ok_or_else(|| {
    731         RadrootsSimplexSmpTransportError::InvalidServerAddress(
    732             "invalid SMP server proof: missing signature payload".into(),
    733         )
    734     })?;
    735     if *unused_bits != 0 {
    736         return Err(RadrootsSimplexSmpTransportError::InvalidServerAddress(
    737             "invalid SMP server proof: unsupported signature bit padding".into(),
    738         ));
    739     }
    740     Ok((&bytes[signed_object_start..signed_object_end], signature))
    741 }
    742 
    743 fn decode_server_certificate_verify_key(
    744     certificate_payload: &[u8],
    745 ) -> Result<Vec<u8>, RadrootsSimplexSmpTransportError> {
    746     let Some(&cert_count) = certificate_payload.first() else {
    747         return Err(RadrootsSimplexSmpTransportError::InvalidServerAddress(
    748             "invalid SMP server proof: missing certificate chain".into(),
    749         ));
    750     };
    751     if cert_count == 0 {
    752         return Err(RadrootsSimplexSmpTransportError::InvalidServerAddress(
    753             "invalid SMP server proof: empty certificate chain".into(),
    754         ));
    755     }
    756     let (certificate_der, _) = read_large_handshake_field(certificate_payload, 1)?;
    757     let (_, certificate) = x509_parser::certificate::X509Certificate::from_der(&certificate_der)
    758         .map_err(|error| {
    759             RadrootsSimplexSmpTransportError::InvalidServerAddress(format!(
    760                 "failed to parse SMP proof certificate: {error}"
    761             ))
    762         })?;
    763     Ok(certificate
    764         .tbs_certificate
    765         .subject_pki
    766         .subject_public_key
    767         .data
    768         .to_vec())
    769 }
    770 
    771 fn read_large_handshake_field(
    772     bytes: &[u8],
    773     offset: usize,
    774 ) -> Result<(Vec<u8>, usize), RadrootsSimplexSmpTransportError> {
    775     let Some(length_bytes) = bytes.get(offset..offset + 2) else {
    776         return Err(RadrootsSimplexSmpTransportError::InvalidServerAddress(
    777             "invalid SMP server proof: truncated certificate length".into(),
    778         ));
    779     };
    780     let length = u16::from_be_bytes([length_bytes[0], length_bytes[1]]) as usize;
    781     let start = offset + 2;
    782     let end = start + length;
    783     let value = bytes.get(start..end).ok_or_else(|| {
    784         RadrootsSimplexSmpTransportError::InvalidServerAddress(
    785             "invalid SMP server proof: certificate exceeds payload".into(),
    786         )
    787     })?;
    788     Ok((value.to_vec(), end))
    789 }
    790 
    791 fn parse_der_element(
    792     bytes: &[u8],
    793     offset: usize,
    794 ) -> Result<(u8, usize, usize, usize), RadrootsSimplexSmpTransportError> {
    795     let tag = *bytes.get(offset).ok_or_else(|| {
    796         RadrootsSimplexSmpTransportError::InvalidServerAddress(
    797             "invalid SMP server proof: truncated DER element".into(),
    798         )
    799     })?;
    800     let length_offset = offset + 1;
    801     let length_tag = *bytes.get(length_offset).ok_or_else(|| {
    802         RadrootsSimplexSmpTransportError::InvalidServerAddress(
    803             "invalid SMP server proof: missing DER length".into(),
    804         )
    805     })?;
    806     let (value_len, header_len) = if length_tag & 0x80 == 0 {
    807         (length_tag as usize, 2)
    808     } else {
    809         let length_bytes = (length_tag & 0x7f) as usize;
    810         if length_bytes == 0 || length_bytes > 4 {
    811             return Err(RadrootsSimplexSmpTransportError::InvalidServerAddress(
    812                 "invalid SMP server proof: unsupported DER length encoding".into(),
    813             ));
    814         }
    815         let length_start = length_offset + 1;
    816         let length_end = length_start + length_bytes;
    817         let encoded_length = bytes.get(length_start..length_end).ok_or_else(|| {
    818             RadrootsSimplexSmpTransportError::InvalidServerAddress(
    819                 "invalid SMP server proof: truncated DER length".into(),
    820             )
    821         })?;
    822         let value_len = encoded_length
    823             .iter()
    824             .fold(0_usize, |acc, byte| (acc << 8) | (*byte as usize));
    825         (value_len, 2 + length_bytes)
    826     };
    827     let value_start = offset + header_len;
    828     let value_end = value_start + value_len;
    829     if value_end > bytes.len() {
    830         return Err(RadrootsSimplexSmpTransportError::InvalidServerAddress(
    831             "invalid SMP server proof: DER element exceeds input".into(),
    832         ));
    833     }
    834     Ok((tag, offset, value_start, value_end))
    835 }
    836 
    837 fn read_server_hello(
    838     stream: &mut StreamOwned<ClientConnection, TcpStream>,
    839 ) -> Result<RadrootsSimplexSmpServerHello, RadrootsSimplexSmpTransportError> {
    840     let mut block = vec![0_u8; RADROOTS_SIMPLEX_SMP_TRANSPORT_BLOCK_SIZE];
    841     stream
    842         .read_exact(&mut block)
    843         .map_err(|error| RadrootsSimplexSmpTransportError::LiveTransportIo(error.to_string()))?;
    844     RadrootsSimplexSmpServerHello::decode(&block)
    845 }
    846 
    847 fn matching_server_identity(
    848     chain: &[CertificateDer<'static>],
    849     expected_identity: &str,
    850 ) -> Result<String, RadrootsSimplexSmpTransportError> {
    851     let expected_identity = canonical_server_identity(expected_identity)?;
    852     for certificate in chain {
    853         let identity = server_identity_from_certificate(certificate.as_ref())?;
    854         if identity == expected_identity {
    855             return Ok(identity);
    856         }
    857     }
    858     Err(RadrootsSimplexSmpTransportError::ServerIdentityMismatch {
    859         expected: expected_identity,
    860         actual: chain
    861             .first()
    862             .map(|certificate| server_identity_from_certificate(certificate.as_ref()))
    863             .transpose()?
    864             .unwrap_or_default(),
    865     })
    866 }
    867 
    868 fn server_identity_from_certificate(
    869     der: &[u8],
    870 ) -> Result<String, RadrootsSimplexSmpTransportError> {
    871     x509_parser::certificate::X509Certificate::from_der(der).map_err(|error| {
    872         RadrootsSimplexSmpTransportError::InvalidServerAddress(format!(
    873             "failed to parse SMP certificate: {error}"
    874         ))
    875     })?;
    876     let digest = Sha256::digest(der);
    877     Ok(URL_SAFE_NO_PAD.encode(digest))
    878 }
    879 
    880 fn canonical_server_identity(value: &str) -> Result<String, RadrootsSimplexSmpTransportError> {
    881     URL_SAFE_NO_PAD
    882         .decode(value)
    883         .or_else(|_| URL_SAFE.decode(value))
    884         .map(|decoded| URL_SAFE_NO_PAD.encode(decoded))
    885         .map_err(|_| {
    886             RadrootsSimplexSmpTransportError::InvalidServerAddress(format!(
    887                 "invalid base64url server identity `{value}`"
    888             ))
    889         })
    890 }
    891 
    892 fn decode_server_identity(value: &str) -> Result<Vec<u8>, RadrootsSimplexSmpTransportError> {
    893     URL_SAFE_NO_PAD
    894         .decode(value)
    895         .or_else(|_| URL_SAFE.decode(value))
    896         .map_err(|_| {
    897             RadrootsSimplexSmpTransportError::InvalidServerAddress(format!(
    898                 "invalid base64url server identity `{value}`"
    899             ))
    900         })
    901 }
    902 
    903 #[derive(Debug)]
    904 struct PermissiveSimplexServerVerifier;
    905 
    906 impl ServerCertVerifier for PermissiveSimplexServerVerifier {
    907     fn verify_server_cert(
    908         &self,
    909         _end_entity: &CertificateDer<'_>,
    910         _intermediates: &[CertificateDer<'_>],
    911         _server_name: &ServerName<'_>,
    912         _ocsp_response: &[u8],
    913         _now: UnixTime,
    914     ) -> Result<ServerCertVerified, RustlsError> {
    915         Ok(ServerCertVerified::assertion())
    916     }
    917 
    918     fn verify_tls12_signature(
    919         &self,
    920         _message: &[u8],
    921         _cert: &CertificateDer<'_>,
    922         _dss: &DigitallySignedStruct,
    923     ) -> Result<HandshakeSignatureValid, RustlsError> {
    924         Ok(HandshakeSignatureValid::assertion())
    925     }
    926 
    927     fn verify_tls13_signature(
    928         &self,
    929         _message: &[u8],
    930         _cert: &CertificateDer<'_>,
    931         _dss: &DigitallySignedStruct,
    932     ) -> Result<HandshakeSignatureValid, RustlsError> {
    933         Ok(HandshakeSignatureValid::assertion())
    934     }
    935 
    936     fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
    937         vec![
    938             SignatureScheme::ED25519,
    939             SignatureScheme::ECDSA_NISTP256_SHA256,
    940             SignatureScheme::ECDSA_NISTP384_SHA384,
    941             SignatureScheme::RSA_PSS_SHA256,
    942             SignatureScheme::RSA_PSS_SHA384,
    943             SignatureScheme::RSA_PKCS1_SHA256,
    944             SignatureScheme::RSA_PKCS1_SHA384,
    945         ]
    946     }
    947 }
    948 
    949 #[cfg(test)]
    950 mod tests {
    951     use super::{
    952         canonical_server_identity, decode_encrypted_transport_block,
    953         decode_server_transport_public_key, encode_encrypted_transport_payload,
    954         select_live_response,
    955     };
    956     use crate::handshake::RadrootsSimplexSmpTransportServerProof;
    957     use crate::prelude::{RadrootsSimplexSmpTransportBlock, RadrootsSimplexSmpTransportResponse};
    958     use radroots_simplex_smp_crypto::prelude::{
    959         RadrootsSimplexSmpX25519Keypair, encode_x25519_public_key_x509, init_secretbox_chain,
    960     };
    961     use radroots_simplex_smp_proto::prelude::{
    962         RADROOTS_SIMPLEX_SMP_CURRENT_TRANSPORT_VERSION, RadrootsSimplexSmpBrokerMessage,
    963         RadrootsSimplexSmpBrokerTransmission, RadrootsSimplexSmpCommand,
    964         RadrootsSimplexSmpCommandTransmission, RadrootsSimplexSmpCorrelationId,
    965         RadrootsSimplexSmpReceivedMessage, RadrootsSimplexSmpServerAddress,
    966     };
    967     use std::collections::VecDeque;
    968 
    969     #[test]
    970     fn canonicalizes_padded_and_unpadded_server_identity() {
    971         assert_eq!(canonical_server_identity("YWJjZA").unwrap(), "YWJjZA");
    972         assert_eq!(canonical_server_identity("YWJjZA==").unwrap(), "YWJjZA");
    973     }
    974 
    975     #[test]
    976     fn extracts_spki_from_signed_server_key_sequence() {
    977         let keypair = RadrootsSimplexSmpX25519Keypair::from_seed(b"transport-proof");
    978         let spki = encode_x25519_public_key_x509(&keypair.public_key).unwrap();
    979         let empty_sequence = der_sequence(core::iter::once(&[][..]));
    980         let signature = [0x03, 0x01, 0x00];
    981         let signed_object = der_sequence([
    982             spki.as_slice(),
    983             empty_sequence.as_slice(),
    984             signature.as_slice(),
    985         ]);
    986         let proof = RadrootsSimplexSmpTransportServerProof {
    987             certificate_payload: Vec::new(),
    988             signed_server_key: signed_object,
    989         };
    990         assert_eq!(
    991             decode_server_transport_public_key(&proof).unwrap(),
    992             keypair.public_key
    993         );
    994     }
    995 
    996     #[test]
    997     fn encrypted_transport_blocks_use_upstream_client_chain_direction() {
    998         let session_identifier = b"rr-synth-session-id";
    999         let shared_secret = b"rr-synth-shared-secret";
   1000         let (mut server_send_chain, mut server_receive_chain) =
   1001             init_secretbox_chain(session_identifier, shared_secret).unwrap();
   1002         let (client_receive_chain, client_send_chain) =
   1003             init_secretbox_chain(session_identifier, shared_secret).unwrap();
   1004         let mut client_receive_chain_for_response = client_receive_chain.clone();
   1005         let mut client_send_chain_for_request = client_send_chain.clone();
   1006 
   1007         let command_transmission = RadrootsSimplexSmpCommandTransmission {
   1008             authorization: Vec::new(),
   1009             correlation_id: Some(RadrootsSimplexSmpCorrelationId::new([3_u8; 24])),
   1010             entity_id: b"rr-synth-queue".to_vec(),
   1011             command: RadrootsSimplexSmpCommand::Ping,
   1012         };
   1013         let command_block = RadrootsSimplexSmpTransportBlock::from_command_transmissions(
   1014             std::slice::from_ref(&command_transmission),
   1015             RADROOTS_SIMPLEX_SMP_CURRENT_TRANSPORT_VERSION,
   1016         )
   1017         .unwrap();
   1018         let encrypted_command = encode_encrypted_transport_payload(
   1019             &mut client_send_chain_for_request,
   1020             &command_block.encode_payload().unwrap(),
   1021         )
   1022         .unwrap();
   1023         assert_eq!(
   1024             decode_encrypted_transport_block(&mut server_receive_chain, &encrypted_command)
   1025                 .unwrap()
   1026                 .decode_command_transmissions(RADROOTS_SIMPLEX_SMP_CURRENT_TRANSPORT_VERSION)
   1027                 .unwrap(),
   1028             vec![command_transmission]
   1029         );
   1030 
   1031         let broker_transmission = RadrootsSimplexSmpBrokerTransmission {
   1032             authorization: Vec::new(),
   1033             correlation_id: Some(RadrootsSimplexSmpCorrelationId::new([3_u8; 24])),
   1034             entity_id: b"rr-synth-queue".to_vec(),
   1035             message: RadrootsSimplexSmpBrokerMessage::Ok,
   1036         };
   1037         let broker_block = RadrootsSimplexSmpTransportBlock::from_broker_transmissions(
   1038             std::slice::from_ref(&broker_transmission),
   1039             RADROOTS_SIMPLEX_SMP_CURRENT_TRANSPORT_VERSION,
   1040         )
   1041         .unwrap();
   1042         let encrypted_broker = encode_encrypted_transport_payload(
   1043             &mut server_send_chain,
   1044             &broker_block.encode_payload().unwrap(),
   1045         )
   1046         .unwrap();
   1047         assert_eq!(
   1048             decode_encrypted_transport_block(
   1049                 &mut client_receive_chain_for_response,
   1050                 &encrypted_broker,
   1051             )
   1052             .unwrap()
   1053             .decode_broker_transmissions(RADROOTS_SIMPLEX_SMP_CURRENT_TRANSPORT_VERSION)
   1054             .unwrap(),
   1055             vec![broker_transmission]
   1056         );
   1057 
   1058         let mut wrong_response_chain = client_send_chain;
   1059         let wrong_direction_broker = encode_encrypted_transport_payload(
   1060             &mut wrong_response_chain,
   1061             &broker_block.encode_payload().unwrap(),
   1062         )
   1063         .unwrap();
   1064         let mut fresh_client_receive_chain = client_receive_chain;
   1065         assert!(
   1066             decode_encrypted_transport_block(
   1067                 &mut fresh_client_receive_chain,
   1068                 &wrong_direction_broker
   1069             )
   1070             .is_err()
   1071         );
   1072     }
   1073 
   1074     #[test]
   1075     fn ack_uses_subscription_session_state() {
   1076         assert_eq!(
   1077             super::session_kind_for_command(&RadrootsSimplexSmpCommand::Ack(b"message".to_vec())),
   1078             "subscription"
   1079         );
   1080         assert!(super::accepts_uncorrelated_subscription_response(
   1081             &RadrootsSimplexSmpCommand::Ack(b"message".to_vec())
   1082         ));
   1083         assert!(super::accepts_uncorrelated_subscription_response(
   1084             &RadrootsSimplexSmpCommand::Sub
   1085         ));
   1086     }
   1087 
   1088     #[test]
   1089     fn strict_command_selection_buffers_unmatched_response_and_errors() {
   1090         let mut pending = VecDeque::new();
   1091         let expected = RadrootsSimplexSmpCorrelationId::new([1_u8; 24]);
   1092         let unmatched = response(
   1093             Some(RadrootsSimplexSmpCorrelationId::new([2_u8; 24])),
   1094             b"rr-synth-entity",
   1095             RadrootsSimplexSmpBrokerMessage::Ok,
   1096         );
   1097 
   1098         assert_eq!(
   1099             select_live_response(&mut pending, vec![unmatched.clone()], Some(expected), None)
   1100                 .unwrap_err(),
   1101             crate::prelude::RadrootsSimplexSmpTransportError::CorrelationIdMismatch
   1102         );
   1103         assert_eq!(pending.into_iter().collect::<Vec<_>>(), vec![unmatched]);
   1104     }
   1105 
   1106     #[test]
   1107     fn matched_response_wins_and_buffers_subscription_message() {
   1108         let mut pending = VecDeque::new();
   1109         let expected = RadrootsSimplexSmpCorrelationId::new([1_u8; 24]);
   1110         let message = response(
   1111             None,
   1112             b"rr-synth-entity",
   1113             RadrootsSimplexSmpBrokerMessage::Msg(RadrootsSimplexSmpReceivedMessage {
   1114                 message_id: b"message-1".to_vec(),
   1115                 encrypted_body: b"body".to_vec(),
   1116             }),
   1117         );
   1118         let matched = response(
   1119             Some(expected),
   1120             b"rr-synth-entity",
   1121             RadrootsSimplexSmpBrokerMessage::Sok(None),
   1122         );
   1123 
   1124         let selected = select_live_response(
   1125             &mut pending,
   1126             vec![message.clone(), matched.clone()],
   1127             Some(expected),
   1128             Some(b"rr-synth-entity"),
   1129         )
   1130         .unwrap();
   1131 
   1132         assert_eq!(selected, Some(matched));
   1133         assert_eq!(pending.into_iter().collect::<Vec<_>>(), vec![message]);
   1134     }
   1135 
   1136     #[test]
   1137     fn subscription_selection_accepts_uncorrelated_message_for_entity() {
   1138         let mut pending = VecDeque::new();
   1139         let expected = RadrootsSimplexSmpCorrelationId::new([1_u8; 24]);
   1140         let message = response(
   1141             None,
   1142             b"rr-synth-entity",
   1143             RadrootsSimplexSmpBrokerMessage::Msg(RadrootsSimplexSmpReceivedMessage {
   1144                 message_id: b"message-1".to_vec(),
   1145                 encrypted_body: b"body".to_vec(),
   1146             }),
   1147         );
   1148         let other = response(
   1149             None,
   1150             b"rr-other-entity",
   1151             RadrootsSimplexSmpBrokerMessage::Msg(RadrootsSimplexSmpReceivedMessage {
   1152                 message_id: b"message-2".to_vec(),
   1153                 encrypted_body: b"other".to_vec(),
   1154             }),
   1155         );
   1156 
   1157         let selected = select_live_response(
   1158             &mut pending,
   1159             vec![other.clone(), message.clone()],
   1160             Some(expected),
   1161             Some(b"rr-synth-entity"),
   1162         )
   1163         .unwrap();
   1164 
   1165         assert_eq!(selected, Some(message));
   1166         assert_eq!(pending.into_iter().collect::<Vec<_>>(), vec![other]);
   1167     }
   1168 
   1169     fn der_sequence<'a, I>(elements: I) -> Vec<u8>
   1170     where
   1171         I: IntoIterator<Item = &'a [u8]>,
   1172     {
   1173         let mut body = Vec::new();
   1174         for element in elements {
   1175             if element.is_empty() {
   1176                 body.extend_from_slice(&[0x30, 0x00]);
   1177             } else {
   1178                 body.extend_from_slice(element);
   1179             }
   1180         }
   1181         let mut sequence = vec![0x30];
   1182         push_der_length(&mut sequence, body.len());
   1183         sequence.extend_from_slice(&body);
   1184         sequence
   1185     }
   1186 
   1187     fn push_der_length(buffer: &mut Vec<u8>, len: usize) {
   1188         if len < 0x80 {
   1189             buffer.push(len as u8);
   1190             return;
   1191         }
   1192         let mut bytes = Vec::new();
   1193         let mut remaining = len;
   1194         while remaining > 0 {
   1195             bytes.push((remaining & 0xff) as u8);
   1196             remaining >>= 8;
   1197         }
   1198         bytes.reverse();
   1199         buffer.push(0x80 | (bytes.len() as u8));
   1200         buffer.extend_from_slice(&bytes);
   1201     }
   1202 
   1203     fn response(
   1204         correlation_id: Option<RadrootsSimplexSmpCorrelationId>,
   1205         entity_id: &[u8],
   1206         message: RadrootsSimplexSmpBrokerMessage,
   1207     ) -> RadrootsSimplexSmpTransportResponse {
   1208         RadrootsSimplexSmpTransportResponse {
   1209             server: RadrootsSimplexSmpServerAddress {
   1210                 server_identity: "cnItc3ludGgtc2VydmVy".to_owned(),
   1211                 hosts: vec!["127.0.0.1".to_owned()],
   1212                 port: Some(5223),
   1213             },
   1214             transport_version: RADROOTS_SIMPLEX_SMP_CURRENT_TRANSPORT_VERSION,
   1215             transmission: RadrootsSimplexSmpBrokerTransmission {
   1216                 authorization: Vec::new(),
   1217                 correlation_id,
   1218                 entity_id: entity_id.to_vec(),
   1219                 message,
   1220             },
   1221             transport_hash: vec![9_u8; 32],
   1222         }
   1223     }
   1224 }