需要帮助为 Rust 文件传输项目实现 TLS

问题描述 投票:0回答:1

我正在开发一个 Rust 文件传输项目,它只是一个用于在设备之间传输文件的库,它现在仅适用于 TCP,但我想实现 TLS 加密以确保客户端和服务器之间的安全连接。然而,我正在努力让它正常工作,并且需要一些指导。

现在,服务器启动了,但是当客户端尝试连接时,TLS 握手失败,我无法查明问题所在。

如果您能够为该项目正确设置 TLS,包括证书生成、配置 Rustls 和调试握手错误,我将不胜感激。

我尝试过的:

  • 使用 OpenSSL 生成自签名证书。
  • 使用生成的证书配置 Rustls。
  • 验证证书已正确加载到客户端和服务器中。
  • 简化了 TLS 配置以进行故障排除,但问题仍然存在。

目标:

  1. 使用 TLS 保护客户端和服务器之间的连接。
  2. 在 p2p 连接中工作
  3. 确保正确配置和验证证书。
  4. 跨平台,需要在所有设备上工作并在不同操作系统之间连接

我现在使用 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(())
    }
}
ssl network-programming rust p2p
1个回答
0
投票

您的代码为服务器生成一个随机证书,然后为客户端生成一个(不同的)随机证书。证书必须匹配才能使 TLS 握手成功。尝试生成一次随机证书,然后将其作为参数传递给服务器和客户端。

© www.soinside.com 2019 - 2024. All rights reserved.