我正在开发一个 Rust 文件传输项目,它只是一个用于在设备之间传输文件的库,它现在仅适用于 TCP,但我想实现 TLS 加密以确保客户端和服务器之间的安全连接。然而,我正在努力让它正常工作,并且需要一些指导。
现在,服务器启动了,但是当客户端尝试连接时,TLS 握手失败,我无法查明问题所在。
如果您能够为该项目正确设置 TLS,包括证书生成、配置 Rustls 和调试握手错误,我将不胜感激。
我尝试过的:
目标:
我现在使用 rustls 和 tokio_rustls,但如果更改为另一个库更好,那就不是问题了
我在这里分享客户端连接和服务器的代码,但我很难在这里展示代码的每个部分,所以请检查存储库https://github.com/Bicheka/file-transfer-system。如果您需要进一步澄清任何事情,请告诉我。感谢您提前的帮助。
客户:
pub struct Client {
client_storage_path: String,
server_address: IpAddr,
timeout: Option<Duration>,
connection: Arc<Mutex<Option<TlsStream<TcpStream>>>>,
}
impl Client {
pub fn new(client_storage_path: &str, server_address: IpAddr) -> Self {
Self {
client_storage_path: client_storage_path.to_owned(),
server_address,
timeout: None,
connection: Arc::new(Mutex::new(None))
}
}
/// Sets a timeout duration for the client.
pub fn set_timeout(&mut self, timeout: Duration) {
self.timeout = Some(timeout);
}
/// Connects to the server.
pub async fn connect(&mut self) -> Result<(), anyhow::Error> {
let crypto_provider = tokio_rustls::rustls::crypto::aws_lc_rs::default_provider();
if let Err(err) = crypto_provider.install_default() {
eprintln!("Failed to install default CryptoProvider: {:?}", err)
}
let cert = rcgen::generate_simple_self_signed(vec![self.server_address.to_string()]).unwrap();
println!("Server Certificate:\n{}", cert.key_pair.serialize_pem());
let mut trusted = RootCertStore::empty();
trusted.add(cert.cert.der().clone()).unwrap();
let connector: TlsConnector = TlsConnector::from(Arc::new(
ClientConfig::builder()
.with_root_certificates(trusted)
.with_no_client_auth(),
));
let addr = SocketAddr::new(self.server_address, 8080);
let tcp = TcpStream::connect(addr).await?;
let tls = connector
.connect(ServerName::IpAddress(self.server_address.into()), tcp)
.await.expect("Could not connect with tls");
let mut connection = self.connection.lock().await;
*connection = Some(tokio_rustls::TlsStream::Client(tls));
Ok(())
}
}
服务器:
#[derive(Clone)]
pub struct Server {
/// Indicates if the server is currently running.
pub is_server_running: Arc<Mutex<bool>>,
/// The IP address on which the server listens.
pub ip: IpAddr,
/// The port on which the server listens.
pub port: u16,
/// The path to the directory where files are stored.
pub path: String,
/// Buffer size for file transfer operations.
pub buffer_size: u64,
/// Notification signal for stopping the server.
pub stop_signal: Arc<Notify>,
}
impl Server {
/// Creates a new instance of the `Server`.
///
/// # Parameters
///
/// - `ip`: IP address on which the server will listen.
/// - `port`: Port on which the server will listen.
/// - `path`: Directory path for file storage and retrieval.
/// - `buffer_size`: Size of the buffer used for file transfers.
pub fn new(ip: IpAddr, port: u16, path: &str, buffer_size: u64, stop_signal: Arc<Notify>) -> Self {
let is_server_running = Arc::new(Mutex::new(false));
Self {
is_server_running,
ip,
port,
path: path.to_owned(),
buffer_size,
stop_signal,
}
}
/// Starts the server, accepting and handling incoming connections.
pub async fn start_server(&mut self) -> Result<(), Box<dyn std::error::Error>> {
let crypto_provider = rustls::crypto::ring::default_provider();
if let Err(err) = crypto_provider.install_default() {
eprintln!("Failed to install default CryptoProvider: {:?}", err)
}
let listener = TcpListener::bind(SocketAddr::new(self.ip.to_owned(), self.port)).await?;
let cert = rcgen::generate_simple_self_signed(vec![self.ip.to_string()])
.map_err(|e| format!("Certificate generation failed: {:?}", e))?;
println!("Server Certificate:\n{}", cert.key_pair.serialize_pem());
println!("Server running on {}", self.ip);
// accept connection
let acceptor = TlsAcceptor::from(Arc::new(
rustls::ServerConfig::builder()
.with_no_client_auth()
.with_single_cert(
vec![cert.cert.der().clone()],
PrivateKeyDer::Pkcs8(
PrivatePkcs8KeyDer::from_pem_slice(cert.key_pair.serialize_pem().as_bytes())
.unwrap(),
),
)
.unwrap(),
));
loop {
tokio::select! {
// Wait for an incoming connection
result = listener.accept() => {
match result {
Ok((socket, addr)) => {
let tls = acceptor.accept(socket).await.unwrap();
println!("New connection from: {}", addr);
let stop_signal_clone = Arc::clone(&self.stop_signal);
let self_clone = self.clone();
tokio::spawn(async {
if let Err(e) = self_clone.handle_request(tokio_rustls::TlsStream::Server(tls), stop_signal_clone).await {
eprintln!("Error handling connection: {:?}", e);
}
});
}
Err(e) => {
eprintln!("Failed to accept connection: {:?}", e);
}
}
},
_ = self.stop_signal.notified() => {
println!("Stopping server...");
break;
},
}
}
Ok(())
}
}
您的代码为服务器生成一个随机证书,然后为客户端生成一个(不同的)随机证书。证书必须匹配才能使 TLS 握手成功。尝试生成一次随机证书,然后将其作为参数传递给服务器和客户端。