You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

跨平台P2P Rust文件传输库的TLS加密实现及握手故障排查求助

跨平台P2P Rust文件传输库的TLS加密实现及握手故障排查求助

大家好,我正在开发一个Rust语言的文件传输类库,目标是实现设备间的文件互传,目前已经基于TCP完成了基础功能,但现在想给客户端和服务端的连接加上TLS加密,却卡在了TLS握手失败的问题上——服务端能正常启动,但客户端发起连接时握手总是失败,我一直没定位到根源。

我已经尝试的排查方案

  • 用OpenSSL生成了自签名证书
  • 基于rustls配置加载这些证书
  • 确认客户端和服务端都能正确读取并加载证书
  • 简化TLS配置来缩小排查范围,但握手失败的问题依然存在

我的核心目标

  1. 给客户端与服务端的连接加上TLS加密保护
  2. 支持P2P连接模式
  3. 确保证书的配置与验证流程完全合规
  4. 实现跨平台兼容,能在不同操作系统的设备间正常建立连接

当前使用的技术栈

我目前用的是rustls和tokio_rustls,如果换用其他更适配场景的库也完全没问题。

客户端与服务端核心代码

客户端连接代码

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(())
    }
}

备注:内容来源于stack exchange,提问作者David Martínez Gil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.15 10:33:02