#![cfg(all(feature = "std", feature = "async-io"))]
use core::pin::pin;
use embassy_futures::select::{select, Either};
use embassy_time::{Duration, Timer};
use log::info;
use rs_matter::cert::gen::VALID_FOREVER;
use rs_matter::cert::MAX_CERT_TLV_AND_ASN1_LEN;
use rs_matter::crypto::{
test_only_crypto, CanonAeadKey, CanonAeadKeyRef, CanonPkcSecretKey, Crypto, RngCore, SecretKey,
SigningSecretKey, AEAD_CANON_KEY_LEN,
};
use rs_matter::dm::devices::test::{TEST_DEV_ATT, TEST_DEV_COMM, TEST_DEV_DET};
use rs_matter::error::Error;
use rs_matter::onboard::cac::RcacGenerator;
use rs_matter::onboard::noc::NocGenerator;
use rs_matter::respond::Responder;
use rs_matter::sc::case::CaseInitiator;
use rs_matter::sc::SecureChannel;
use rs_matter::transport::exchange::Exchange;
use rs_matter::transport::network::{Address, NoNetwork};
use rs_matter::utils::select::Coalesce;
use rs_matter::Matter;
use crate::common::{create_localhost_socket_pair, init_env_logger, run_device_controller};
#[allow(dead_code)]
mod common;
const TEST_FABRIC_ID: u64 = 1;
const CONTROLLER_NODE_ID: u64 = 100;
const DEVICE_NODE_ID: u64 = 200;
#[test]
fn test_case_handshake() {
init_env_logger();
futures_lite::future::block_on(async {
let crypto = test_only_crypto();
let mut rcac_buf = [0u8; MAX_CERT_TLV_AND_ASN1_LEN];
let mut rcac_gen = RcacGenerator::new(&mut rcac_buf);
let (rcac_privkey, rcac) = rcac_gen
.generate(&crypto, TEST_FABRIC_ID, VALID_FOREVER)
.unwrap();
let mut noc_buf = [0u8; MAX_CERT_TLV_AND_ASN1_LEN];
let mut noc_generator =
NocGenerator::create(rcac_privkey.reference(), rcac, &[], &mut noc_buf).unwrap();
let mut ipk = CanonAeadKey::new();
let mut ipk_bytes = [0u8; AEAD_CANON_KEY_LEN];
crypto.rand().unwrap().fill_bytes(&mut ipk_bytes);
ipk.load_from_array(&ipk_bytes);
let ipk_ref: CanonAeadKeyRef<'_> = ipk.reference();
let controller_secret_key = crypto.generate_secret_key().unwrap();
let mut controller_csr_buf = [0u8; 256];
let controller_csr = controller_secret_key.csr(&mut controller_csr_buf).unwrap();
let mut controller_secret_key_canon = CanonPkcSecretKey::new();
controller_secret_key
.write_canon(&mut controller_secret_key_canon)
.unwrap();
let device_secret_key = crypto.generate_secret_key().unwrap();
let mut device_csr_buf = [0u8; 256];
let device_csr = device_secret_key.csr(&mut device_csr_buf).unwrap();
let mut device_secret_key_canon = CanonPkcSecretKey::new();
device_secret_key
.write_canon(&mut device_secret_key_canon)
.unwrap();
let device_matter = Matter::new(&TEST_DEV_DET, TEST_DEV_COMM, &TEST_DEV_ATT, 0);
let controller_matter = Matter::new(&TEST_DEV_DET, TEST_DEV_COMM, &TEST_DEV_ATT, 0);
let controller_noc = noc_generator
.generate(
&crypto,
controller_csr,
CONTROLLER_NODE_ID,
&[],
VALID_FOREVER,
)
.unwrap();
let controller_fab_idx = controller_matter.with_state(|state| {
state
.fabrics
.add(
&crypto,
controller_secret_key_canon.reference(),
rcac,
controller_noc,
&[], Some(ipk_ref),
0xFFF1,
CONTROLLER_NODE_ID,
)
.unwrap()
.fab_idx()
});
let device_noc = noc_generator
.generate(&crypto, device_csr, DEVICE_NODE_ID, &[], VALID_FOREVER)
.unwrap();
device_matter.with_state(|state| {
state
.fabrics
.add(
&crypto,
device_secret_key_canon.reference(),
rcac,
device_noc,
&[], Some(ipk_ref),
0xFFF1,
CONTROLLER_NODE_ID,
)
.unwrap();
});
let (device_socket, controller_socket) = create_localhost_socket_pair();
let peer_addr = Address::Udp(device_socket.get_ref().local_addr().unwrap());
let sc = SecureChannel::new(&crypto, &());
let responder = Responder::new("device", sc, &device_matter, 0);
let device_fut = async {
select(
device_matter.run(&crypto, &device_socket, &device_socket, NoNetwork),
responder.run::<4>(),
)
.coalesce()
.await
};
let controller_fut = async {
let mut transport = pin!(controller_matter.run(
&crypto,
&controller_socket,
&controller_socket,
NoNetwork,
));
let mut test = pin!(run_case_handshake(
&controller_matter,
&crypto,
peer_addr,
controller_fab_idx,
DEVICE_NODE_ID,
));
match select(&mut transport, &mut test).await {
Either::First(transport_result) => {
panic!("Controller transport exited prematurely: {transport_result:?}");
}
Either::Second(test_result) => {
let mut flush = pin!(Timer::after(Duration::from_millis(300)));
if let Either::First(transport_result) =
select(&mut transport, &mut flush).await
{
panic!("Controller transport error during flush: {transport_result:?}");
}
test_result
}
}
};
run_device_controller(device_fut, controller_fut)
.await
.unwrap();
});
}
async fn run_case_handshake<C: Crypto>(
matter: &Matter<'_>,
crypto: &C,
peer_addr: Address,
fab_idx: core::num::NonZeroU8,
peer_node_id: u64,
) -> Result<(), Error> {
info!("Creating unsecured session and initiating CASE handshake...");
let mut exchange = Exchange::initiate_unsecured(matter, crypto, peer_addr).await?;
info!("Exchange initiated: {}", exchange.id());
info!("Starting CASE handshake...");
let mut case_fut = pin!(CaseInitiator::initiate(
&mut exchange,
crypto,
fab_idx,
peer_node_id,
));
let mut timeout = pin!(Timer::after(Duration::from_secs(30)));
let result = match select(&mut case_fut, &mut timeout).await {
Either::First(result) => result,
Either::Second(_) => panic!("CASE handshake timed out after 30 seconds"),
};
result?;
info!("CASE handshake completed successfully - secure session established");
Ok(())
}