admin管理员组文章数量:1431904
I'm developing a Rust file transfer project, it is just a library to transfer files from device to device, it now works with just TCP but I want to implement TLS encryption for secure connections between the client and server. However, I'm struggling to get it working properly.
Right now, the server starts up, but when the client attempts to connect, the TLS handshake fails, and I can't pinpoint the issue.
I want to set up TLS correctly for this project, including certificate generation, configuring Rustls, and debugging handshake errors.
What I have tried:
- Generated self-signed certificates using OpenSSL.
- Configured Rustls with the generated certificates.
- Verified the certificates are being loaded correctly in both client and server.
- Simplified the TLS configuration to troubleshoot, but the issue persists.
Goals:
- Secure the connection between the client and server with TLS.
- Work in a p2p connection
- Ensure certificates are properly configured and verified.
- Cross Platform, it needs to work in all devices and connect between diffent os
I am using rustls and tokio_rustls for now but if changing to another library is better it would not be a problem.
I share here the code for client connection and the server.
Client:
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(())
}
}
Server:
#[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(())
}
}
I'm developing a Rust file transfer project, it is just a library to transfer files from device to device, it now works with just TCP but I want to implement TLS encryption for secure connections between the client and server. However, I'm struggling to get it working properly.
Right now, the server starts up, but when the client attempts to connect, the TLS handshake fails, and I can't pinpoint the issue.
I want to set up TLS correctly for this project, including certificate generation, configuring Rustls, and debugging handshake errors.
What I have tried:
- Generated self-signed certificates using OpenSSL.
- Configured Rustls with the generated certificates.
- Verified the certificates are being loaded correctly in both client and server.
- Simplified the TLS configuration to troubleshoot, but the issue persists.
Goals:
- Secure the connection between the client and server with TLS.
- Work in a p2p connection
- Ensure certificates are properly configured and verified.
- Cross Platform, it needs to work in all devices and connect between diffent os
I am using rustls and tokio_rustls for now but if changing to another library is better it would not be a problem.
I share here the code for client connection and the server.
Client:
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(())
}
}
Server:
#[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(())
}
}
Share
Improve this question
edited Nov 23, 2024 at 19:36
halfer
20.4k19 gold badges109 silver badges202 bronze badges
asked Nov 19, 2024 at 4:26
David Martínez GilDavid Martínez Gil
3431 gold badge2 silver badges7 bronze badges
2
- In case my answer doesn't reflect the only problem, knowing the error message (or other incorrect behavior) might be helpful! – Finn Bear Commented Nov 19, 2024 at 4:45
- Editor's note: if a link to a repo must be supplied to show all the necessary files, then by definition the question is off-topic. I have thus removed that, plus some requests for general advice, as they could cause the question to be closed. You'll find it easier to get help here if you ask one question at a time, and each question is highly focused on just one thing. – halfer Commented Nov 23, 2024 at 19:38
1 Answer
Reset to default 0Your code generates1 a random certificate for the server and then an unrelated random certificate for the client. For the TLS handshake to succeed, the certificates must match directly (self-signed) or indirectly (CA signature chain). Try generating a random certificate once and then passing it, as a parameter, to both the server and the client.
1rcgen::generate_simple_self_signed
本文标签: sslHow to implement TLS for Rust file transfer projectStack Overflow
版权声明:本文标题:ssl - How to implement TLS for Rust file transfer project - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1745582643a2664711.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论