use std::sync::Arc;
use tokio::net::TcpStream;
use tokio::sync::RwLock;
use async_trait::async_trait;
use serde::{Serialize, Deserialize};
use crate::{QsslConnection, QsslContext, QsslResult, QsslError};
use crate::crypto::CipherSuite;
pub struct QsshTransport {
connection: Arc<QsslConnection>,
context: Arc<QsslContext>,
}
impl QsshTransport {
pub async fn connect(addr: &str, context: QsslContext) -> QsslResult<Self> {
let connection = QsslConnection::connect(addr).await?;
Ok(Self {
connection: Arc::new(connection),
context: Arc::new(context),
})
}
pub async fn accept(stream: TcpStream, context: QsslContext) -> QsslResult<Self> {
let connection = QsslConnection::accept(stream).await?;
Ok(Self {
connection: Arc::new(connection),
context: Arc::new(context),
})
}
pub async fn send_message<T: Serialize>(&self, message: &T) -> QsslResult<()> {
let data = bincode::serialize(message)
.map_err(|e| QsslError::Protocol(format!("Serialization failed: {}", e)))?;
self.connection.send(&data).await
}
pub async fn recv_message<T: for<'de> Deserialize<'de>>(&self) -> QsslResult<T> {
let data = self.connection.recv().await?;
bincode::deserialize(&data)
.map_err(|e| QsslError::Protocol(format!("Deserialization failed: {}", e)))
}
pub fn cipher_suite(&self) -> Option<CipherSuite> {
self.connection.cipher_suite()
}
pub async fn is_established(&self) -> bool {
self.connection.is_established().await
}
pub async fn close(&self) -> QsslResult<()> {
self.connection.close().await
}
}
#[derive(Debug, Clone)]
pub struct QsshConfig {
pub qssl_context: QsslContext,
pub enable_compression: bool,
pub enable_multiplexing: bool,
pub max_packet_size: usize,
}
impl Default for QsshConfig {
fn default() -> Self {
let mut context = QsslContext::default();
context.set_cipher_suites(vec![
CipherSuite::Kyber768Falcon512Aes256,
CipherSuite::Kyber512Falcon512Aes128,
]);
context.enable_session_resumption(100);
Self {
qssl_context: context,
enable_compression: false,
enable_multiplexing: true,
max_packet_size: 32768,
}
}
}
#[derive(Debug, Serialize, Deserialize)]
pub enum QsshMessage {
Version {
version: String,
software: String,
comments: Option<String>,
},
KexInit {
cookie: [u8; 16],
kex_algorithms: Vec<String>,
host_key_algorithms: Vec<String>,
encryption_algorithms: Vec<String>,
mac_algorithms: Vec<String>,
compression_algorithms: Vec<String>,
},
AuthRequest {
username: String,
service: String,
method: String,
data: Vec<u8>,
},
ChannelOpen {
channel_type: String,
sender_channel: u32,
window_size: u32,
max_packet_size: u32,
},
ChannelData {
channel: u32,
data: Vec<u8>,
},
Disconnect {
reason_code: u32,
description: String,
},
}
pub struct QsshSessionManager {
qssl_sessions: Arc<RwLock<crate::session::SessionCache>>,
}
impl QsshSessionManager {
pub fn new() -> Self {
Self {
qssl_sessions: Arc::new(RwLock::new(
crate::session::SessionCache::new(
1000,
std::time::Duration::from_secs(3600),
)
)),
}
}
pub async fn store_session(&self, session_id: &[u8], session_data: Vec<u8>) -> QsslResult<()> {
let qssl_session = crate::session::QsslSession::new(
crate::session::SessionId::from_bytes(session_id.to_vec()),
CipherSuite::Kyber768Falcon512Aes256, session_data, [0; 32], [0; 32],
);
self.qssl_sessions.read().await.store(qssl_session).await
}
pub async fn get_session(&self, session_id: &[u8]) -> Option<Vec<u8>> {
let id = crate::session::SessionId::from_bytes(session_id.to_vec());
self.qssl_sessions.read().await.get(&id).await
.map(|session| session.master_secret)
}
pub async fn remove_session(&self, session_id: &[u8]) -> bool {
let id = crate::session::SessionId::from_bytes(session_id.to_vec());
self.qssl_sessions.read().await.remove(&id).await
}
}
pub async fn test_qssh_over_qssl() -> QsslResult<()> {
let config = QsshConfig::default();
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_qssh_config() {
let config = QsshConfig::default();
assert!(!config.qssl_context.cipher_suites.is_empty());
assert!(config.enable_multiplexing);
assert_eq!(config.max_packet_size, 32768);
}
#[test]
fn test_qssh_message_serialization() {
let msg = QsshMessage::Version {
version: "QSSH-2.0".to_string(),
software: "QSSH_1.0".to_string(),
comments: Some("Test".to_string()),
};
let serialized = bincode::serialize(&msg).unwrap();
let deserialized: QsshMessage = bincode::deserialize(&serialized).unwrap();
match deserialized {
QsshMessage::Version { version, .. } => {
assert_eq!(version, "QSSH-2.0");
}
_ => panic!("Wrong message type"),
}
}
#[tokio::test]
async fn test_qssh_session_manager() {
let manager = QsshSessionManager::new();
let session_id = b"test_session";
let session_data = vec![1, 2, 3, 4, 5];
manager.store_session(session_id, session_data.clone()).await.unwrap();
let retrieved = manager.get_session(session_id).await.unwrap();
assert_eq!(retrieved, session_data);
assert!(manager.remove_session(session_id).await);
assert!(manager.get_session(session_id).await.is_none());
}
}