use std::collections::VecDeque;
use std::sync::Arc;
use std::time::Instant;
use dimpl::{Config, Dtls, Output};
use crate::ossl_helper::{DtlsCertOptions, DtlsEvent, OsslDtlsCert};
#[test]
fn dtls12_ossl_client_handshake() {
env_logger::try_init().ok();
let client_cert_options = DtlsCertOptions::default();
let client_cert = OsslDtlsCert::new(client_cert_options);
let server_cert_options = DtlsCertOptions::default();
let server_cert = OsslDtlsCert::new(server_cert_options);
let mut server = server_cert
.new_dtls_impl()
.expect("Failed to create DTLS server");
server.set_active(false);
let config = Arc::new(Config::default());
let client_x509_der = client_cert
.x509
.to_der()
.expect("Failed to get client cert DER");
let client_pkey_der = client_cert
.pkey
.private_key_to_der()
.expect("Failed to get client private key DER");
let now = Instant::now();
let mut client = Dtls::new_12(
config,
dimpl::DtlsCertificate {
certificate: client_x509_der,
private_key: client_pkey_der,
},
now,
);
client.set_active(true);
let mut server_events = VecDeque::new();
let mut client_connected = false;
let mut client_peer_cert = None;
let mut client_keying_material = None;
let mut server_connected = false;
let mut server_keying_material = None;
let client_test_data = b"Hello from client";
let server_test_data = b"Hello from server";
let mut client_received_data = Vec::new();
let mut server_received_data = Vec::new();
let mut out_buf = vec![0u8; 2048];
for _ in 0..20 {
client.handle_timeout(Instant::now()).unwrap();
let mut continue_polling = true;
while continue_polling {
let output = client.poll_output(&mut out_buf);
match output {
Output::Packet(data) => {
if let Err(e) = server.handle_receive(data, &mut server_events) {
panic!("Server failed to handle client packet: {:?}", e);
}
}
Output::Connected => {
client_connected = true;
println!("Client connected");
}
Output::PeerCert(_cert) => {
client_peer_cert = Some(true);
println!("Client received peer certificate");
}
Output::KeyingMaterial(km, profile) => {
client_keying_material = Some((km.as_ref().to_vec(), profile));
println!("Client received keying material for profile: {:?}", profile);
client
.send_application_data(client_test_data)
.expect("Failed to send client data");
}
Output::ApplicationData(data) => {
client_received_data.extend_from_slice(data);
println!(
"Client received {} bytes of application data: {:02x?}",
data.len(),
data
);
}
Output::Timeout(_) => {
continue_polling = false;
}
_ => {}
}
}
while let Some(event) = server_events.pop_front() {
match event {
DtlsEvent::Connected => {
server_connected = true;
println!("Server connected");
}
DtlsEvent::RemoteFingerprint(fp) => {
println!("Server received fingerprint: {}", fp);
}
DtlsEvent::SrtpKeyingMaterial(km, profile) => {
server_keying_material = Some((km, profile));
println!("Server received keying material for profile: {:?}", profile);
server
.handle_input(server_test_data)
.expect("Failed to send server data");
}
DtlsEvent::Data(data) => {
server_received_data.extend_from_slice(&data);
println!(
"Server received {} bytes of application data: {:02x?}",
data.len(),
data
);
}
}
}
while let Some(datagram) = server.poll_datagram() {
client
.handle_packet(&datagram)
.expect("Failed to handle server packet");
}
if client_connected
&& server_connected
&& !client_received_data.is_empty()
&& !server_received_data.is_empty()
{
break;
}
}
assert!(client_connected, "Client should be connected");
assert!(server_connected, "Server should be connected");
assert!(
client_peer_cert.is_some(),
"Client should have received peer certificate"
);
assert!(
client_keying_material.is_some(),
"Client should have received keying material"
);
assert!(
server_keying_material.is_some(),
"Server should have received keying material"
);
let (client_km, client_profile) = client_keying_material.unwrap();
let (server_km, server_profile) = server_keying_material.unwrap();
assert_eq!(
client_profile, server_profile,
"Client and server should negotiate the same SRTP profile"
);
assert!(
!client_km.is_empty(),
"Client keying material should not be empty"
);
assert_eq!(
client_km.len(),
server_km.len(),
"Client and server keying material should have the same length"
);
assert_eq!(
server_received_data, client_test_data,
"Server should receive correct data from client"
);
assert_eq!(
client_received_data, server_test_data,
"Client should receive correct data from server"
);
}
#[test]
fn dtls12_ossl_server_handshake() {
let _ = env_logger::try_init();
let server_cert_options = DtlsCertOptions::default();
let server_cert = OsslDtlsCert::new(server_cert_options);
let client_cert_options = DtlsCertOptions::default();
let client_cert = OsslDtlsCert::new(client_cert_options);
let mut client = client_cert
.new_dtls_impl()
.expect("Failed to create DTLS client");
client.set_active(true);
let config = Arc::new(Config::default());
let server_x509_der = server_cert
.x509
.to_der()
.expect("Failed to get server cert DER");
let server_pkey_der = server_cert
.pkey
.private_key_to_der()
.expect("Failed to get server private key DER");
let now = Instant::now();
let mut server = Dtls::new_12(
config,
dimpl::DtlsCertificate {
certificate: server_x509_der,
private_key: server_pkey_der,
},
now,
);
server.set_active(false);
let mut client_events = VecDeque::new();
let mut server_connected = false;
let mut client_connected = false;
let mut saw_server_peer_cert = false;
let mut server_keying_material = None;
let mut client_keying_material = None;
let client_test_data = b"Hello from client";
let server_test_data = b"Hello from server";
let mut client_received_data = Vec::new();
let mut server_received_data = Vec::new();
let mut out_buf = vec![0u8; 2048];
for _ in 0..40 {
server.handle_timeout(Instant::now()).unwrap();
client.handle_handshake(&mut client_events).unwrap();
while let Some(datagram) = client.poll_datagram() {
server
.handle_packet(&datagram)
.expect("Server failed to handle client packet");
}
loop {
match server.poll_output(&mut out_buf) {
Output::Packet(data) => {
client
.handle_receive(data, &mut client_events)
.expect("Client failed to handle server packet");
}
Output::Connected => {
server_connected = true;
}
Output::PeerCert(_cert) => {
saw_server_peer_cert = true;
}
Output::KeyingMaterial(km, profile) => {
server_keying_material = Some((km.as_ref().to_vec(), profile));
server
.send_application_data(server_test_data)
.expect("Server failed to send app data");
}
Output::ApplicationData(data) => {
server_received_data.extend_from_slice(data);
}
Output::Timeout(_) => break,
_ => {}
}
}
while let Some(event) = client_events.pop_front() {
match event {
DtlsEvent::Connected => {
client_connected = true;
client
.handle_input(client_test_data)
.expect("Client failed to send app data");
}
DtlsEvent::RemoteFingerprint(_fp) => {
}
DtlsEvent::SrtpKeyingMaterial(km, profile) => {
client_keying_material = Some((km, profile));
}
DtlsEvent::Data(data) => {
client_received_data.extend_from_slice(&data);
}
}
}
while let Some(datagram) = client.poll_datagram() {
server
.handle_packet(&datagram)
.expect("Server failed to handle client packet");
}
if server_connected
&& client_connected
&& !client_received_data.is_empty()
&& !server_received_data.is_empty()
{
break;
}
}
assert!(server_connected, "Server should be connected");
assert!(client_connected, "Client should be connected");
assert!(
saw_server_peer_cert,
"Server should have received peer certificate"
);
assert!(
server_keying_material.is_some(),
"Server should have SRTP keying material"
);
assert!(
client_keying_material.is_some(),
"Client should have SRTP keying material"
);
let (server_km, server_profile) = server_keying_material.unwrap();
let (client_km, client_profile) = client_keying_material.unwrap();
assert_eq!(
server_profile, client_profile,
"Both sides should negotiate same SRTP profile"
);
assert!(
!server_km.is_empty(),
"Server keying material should not be empty"
);
assert_eq!(
server_km.len(),
client_km.len(),
"Keying material length should match"
);
assert_eq!(
server_received_data, client_test_data,
"Server should receive correct data"
);
assert_eq!(
client_received_data, server_test_data,
"Client should receive correct data"
);
}
#[test]
fn dtls12_ossl_client_retransmit_on_timeout() {
let _ = env_logger::try_init();
let client_cert_options = DtlsCertOptions::default();
let client_cert = OsslDtlsCert::new(client_cert_options);
let server_cert_options = DtlsCertOptions::default();
let server_cert = OsslDtlsCert::new(server_cert_options);
let mut server = server_cert
.new_dtls_impl()
.expect("Failed to create DTLS server");
server.set_active(false);
let config = Arc::new(Config::default());
let client_x509_der = client_cert
.x509
.to_der()
.expect("Failed to get client cert DER");
let client_pkey_der = client_cert
.pkey
.private_key_to_der()
.expect("Failed to get client private key DER");
let mut now = Instant::now();
let mut client = Dtls::new_12(
config,
dimpl::DtlsCertificate {
certificate: client_x509_der,
private_key: client_pkey_der,
},
now,
);
client.set_active(true);
let mut server_events = VecDeque::new();
let mut out_buf = vec![0u8; 2048];
client.handle_timeout(now).unwrap();
let mut first_flight_dropped = false;
loop {
match client.poll_output(&mut out_buf) {
Output::Packet(_data) => {
first_flight_dropped = true;
}
Output::Timeout(_) => break,
_ => {}
}
}
assert!(
first_flight_dropped,
"Client should have produced at least one packet in the first flight"
);
now += std::time::Duration::from_millis(50);
client.handle_timeout(now).unwrap();
let flight_timeout;
loop {
if let Output::Timeout(t) = client.poll_output(&mut out_buf) {
flight_timeout = t;
break;
}
}
now = flight_timeout + std::time::Duration::from_millis(1);
client.handle_timeout(now).unwrap();
let mut retransmitted = false;
loop {
match client.poll_output(&mut out_buf) {
Output::Packet(data) => {
retransmitted = true;
if let Err(e) = server.handle_receive(data, &mut server_events) {
panic!(
"Server failed to handle retransmitted client packet: {:?}",
e
);
}
}
Output::Timeout(_) => break,
_ => {}
}
}
assert!(
retransmitted,
"Client should have retransmitted packets after timeout"
);
let mut client_connected = false;
let mut server_connected = false;
for _ in 0..20 {
while let Some(event) = server_events.pop_front() {
if let DtlsEvent::Connected = event {
server_connected = true;
}
}
while let Some(datagram) = server.poll_datagram() {
client
.handle_packet(&datagram)
.expect("Failed to handle server packet");
}
now += std::time::Duration::from_millis(50);
client.handle_timeout(now).unwrap();
loop {
match client.poll_output(&mut out_buf) {
Output::Packet(data) => {
if let Err(e) = server.handle_receive(data, &mut server_events) {
panic!("Server failed to handle client packet: {:?}", e);
}
}
Output::Connected => {
client_connected = true;
}
Output::Timeout(_) => break,
_ => {}
}
}
if client_connected && server_connected {
break;
}
}
assert!(
client_connected,
"Client should be connected after retransmit"
);
assert!(
server_connected,
"Server should be connected after retransmit"
);
}
#[test]
fn dtls12_ossl_client_handles_duplicates() {
let _ = env_logger::try_init();
let client_cert_options = DtlsCertOptions::default();
let client_cert = OsslDtlsCert::new(client_cert_options);
let server_cert_options = DtlsCertOptions::default();
let server_cert = OsslDtlsCert::new(server_cert_options);
let mut server = server_cert
.new_dtls_impl()
.expect("Failed to create DTLS server");
server.set_active(false);
let config = Arc::new(Config::default());
let client_x509_der = client_cert
.x509
.to_der()
.expect("Failed to get client cert DER");
let client_pkey_der = client_cert
.pkey
.private_key_to_der()
.expect("Failed to get client private key DER");
let mut client = Dtls::new_12(
config,
dimpl::DtlsCertificate {
certificate: client_x509_der,
private_key: client_pkey_der,
},
Instant::now(),
);
client.set_active(true);
let mut server_events = VecDeque::new();
let mut client_connected = false;
let mut server_connected = false;
let mut client_keying_material = None;
let mut server_keying_material = None;
let client_test_data = b"Hello from client";
let server_test_data = b"Hello from server";
let mut client_received_data = Vec::new();
let mut server_received_data = Vec::new();
let mut out_buf = vec![0u8; 2048];
for _ in 0..20 {
client.handle_timeout(Instant::now()).unwrap();
loop {
match client.poll_output(&mut out_buf) {
Output::Packet(data) => {
if let Err(e) = server.handle_receive(data, &mut server_events) {
panic!("Server failed to handle client packet: {:?}", e);
}
}
Output::Connected => {
client_connected = true;
}
Output::KeyingMaterial(km, profile) => {
client_keying_material = Some((km.as_ref().to_vec(), profile));
client
.send_application_data(client_test_data)
.expect("Failed to send client data");
}
Output::ApplicationData(data) => {
client_received_data.extend_from_slice(data);
}
Output::Timeout(_) => break,
_ => {}
}
}
while let Some(event) = server_events.pop_front() {
match event {
DtlsEvent::Connected => {
server_connected = true;
}
DtlsEvent::SrtpKeyingMaterial(km, profile) => {
server_keying_material = Some((km, profile));
server
.handle_input(server_test_data)
.expect("Failed to send server data");
}
DtlsEvent::Data(data) => {
server_received_data.extend_from_slice(&data);
}
_ => {}
}
}
let mut server_datagrams = Vec::new();
while let Some(datagram) = server.poll_datagram() {
server_datagrams.push(datagram);
}
for datagram in &server_datagrams {
client
.handle_packet(datagram)
.expect("Failed to handle server packet (first delivery)");
let _ = client.handle_packet(datagram);
}
if client_connected
&& server_connected
&& !client_received_data.is_empty()
&& !server_received_data.is_empty()
{
break;
}
}
assert!(
client_connected,
"Client should be connected despite duplicates"
);
assert!(
server_connected,
"Server should be connected despite duplicates"
);
assert!(
client_keying_material.is_some(),
"Client should have received keying material"
);
assert!(
server_keying_material.is_some(),
"Server should have received keying material"
);
let (_client_km, client_profile) = client_keying_material.unwrap();
let (_server_km, server_profile) = server_keying_material.unwrap();
assert_eq!(
client_profile, server_profile,
"Client and server should negotiate the same SRTP profile"
);
assert_eq!(
server_received_data, client_test_data,
"Server should receive correct data from client"
);
assert_eq!(
client_received_data, server_test_data,
"Client should receive correct data from server"
);
}
#[test]
fn dtls12_ossl_server_bidirectional_data() {
let _ = env_logger::try_init();
let server_cert_options = DtlsCertOptions::default();
let server_cert = OsslDtlsCert::new(server_cert_options);
let client_cert_options = DtlsCertOptions::default();
let client_cert = OsslDtlsCert::new(client_cert_options);
let mut client = client_cert
.new_dtls_impl()
.expect("Failed to create DTLS client");
client.set_active(true);
let config = Arc::new(Config::default());
let server_x509_der = server_cert
.x509
.to_der()
.expect("Failed to get server cert DER");
let server_pkey_der = server_cert
.pkey
.private_key_to_der()
.expect("Failed to get server private key DER");
let mut server = Dtls::new_12(
config,
dimpl::DtlsCertificate {
certificate: server_x509_der,
private_key: server_pkey_der,
},
Instant::now(),
);
server.set_active(false);
let mut client_events = VecDeque::new();
let mut server_connected = false;
let mut client_connected = false;
let server_test_data = b"Hello from server";
let client_test_data = b"Hello from client";
let server_reply_data = b"Server got your message";
let client_reply_data = b"Client got your message";
let mut client_received_data = Vec::new();
let mut server_received_data = Vec::new();
let mut server_first_sent = false;
let mut client_first_sent = false;
let mut server_reply_sent = false;
let mut client_reply_sent = false;
let mut out_buf = vec![0u8; 2048];
for _ in 0..40 {
server.handle_timeout(Instant::now()).unwrap();
client.handle_handshake(&mut client_events).unwrap();
while let Some(datagram) = client.poll_datagram() {
server
.handle_packet(&datagram)
.expect("Server failed to handle client packet");
}
loop {
match server.poll_output(&mut out_buf) {
Output::Packet(data) => {
client
.handle_receive(data, &mut client_events)
.expect("Client failed to handle server packet");
}
Output::Connected => {
server_connected = true;
}
Output::KeyingMaterial(_km, _profile) if !server_first_sent => {
server
.send_application_data(server_test_data)
.expect("Server failed to send app data");
server_first_sent = true;
}
Output::ApplicationData(data) => {
server_received_data.extend_from_slice(data);
if !server_reply_sent && server_received_data.len() >= client_test_data.len() {
server
.send_application_data(server_reply_data)
.expect("Server failed to send reply");
server_reply_sent = true;
}
}
Output::Timeout(_) => break,
_ => {}
}
}
while let Some(event) = client_events.pop_front() {
match event {
DtlsEvent::Connected => {
client_connected = true;
if !client_first_sent {
client
.handle_input(client_test_data)
.expect("Client failed to send app data");
client_first_sent = true;
}
}
DtlsEvent::Data(data) => {
client_received_data.extend_from_slice(&data);
if !client_reply_sent && client_received_data.len() >= server_test_data.len() {
client
.handle_input(client_reply_data)
.expect("Client failed to send reply");
client_reply_sent = true;
}
}
_ => {}
}
}
while let Some(datagram) = client.poll_datagram() {
server
.handle_packet(&datagram)
.expect("Server failed to handle client packet");
}
let expected_server_len = client_test_data.len() + client_reply_data.len();
let expected_client_len = server_test_data.len() + server_reply_data.len();
if server_connected
&& client_connected
&& server_received_data.len() >= expected_server_len
&& client_received_data.len() >= expected_client_len
{
break;
}
}
assert!(server_connected, "Server should be connected");
assert!(client_connected, "Client should be connected");
let mut expected_server_recv = Vec::new();
expected_server_recv.extend_from_slice(client_test_data);
expected_server_recv.extend_from_slice(client_reply_data);
let mut expected_client_recv = Vec::new();
expected_client_recv.extend_from_slice(server_test_data);
expected_client_recv.extend_from_slice(server_reply_data);
assert_eq!(
server_received_data, expected_server_recv,
"Server should receive both client messages"
);
assert_eq!(
client_received_data, expected_client_recv,
"Client should receive both server messages"
);
}