我正在一个文件传输系统中工作,该系统具有使用 Rust 的 p2p 连接库。它仅使用 tcp 即可工作,但现在我想使用 TLS 改进它,但我不明白两件事。两个对等方如何共享证书颁发机构 CA,以便他们可以验证连接是否值得信赖。在我描述的对等连接中,只有 2 个对等点尝试传输一些文件。由于他们没有纯域名 IP,因此无法正常工作。如果有人能给我一些帮助,请提供一些如何处理的指南,那就太好了,谢谢。
native-tls
同步 connect
函数的
docs说:
如果同时禁用 SNI 和主机名验证,则域将被忽略。
考虑到这一点,切换到
async
API,并生成自签名证书,我们得到以下工作代码:
[package]
name = "tls"
version = "0.1.0"
edition = "2021"
[dependencies]
rcgen = "0.13.1"
tokio = { version = "1.41.1", features = ["full"] }
tokio-native-tls = "0.3.1"
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::{TcpListener, TcpStream};
use tokio_native_tls::native_tls::Identity;
use tokio_native_tls::{native_tls, TlsAcceptor, TlsConnector};
#[tokio::main]
async fn main() {
let cert = rcgen::generate_simple_self_signed([]).unwrap();
let listener = TcpListener::bind("127.0.0.1:8001").await.unwrap();
let trusted = native_tls::Certificate::from_pem(cert.cert.pem().as_bytes()).unwrap();
tokio::spawn(async move {
let connector = TlsConnector::from(
native_tls::TlsConnector::builder()
.disable_built_in_roots(true)
.add_root_certificate(trusted)
.danger_accept_invalid_hostnames(true)
.use_sni(false)
.build()
.unwrap(),
);
let tcp = TcpStream::connect("0.0.0.0:8001").await.unwrap();
let mut tls = connector.connect("N/A", tcp).await.unwrap();
tls.write_all(b"hello!").await.unwrap();
tls.shutdown().await.unwrap();
});
let acceptor = TlsAcceptor::from(
native_tls::TlsAcceptor::new(
Identity::from_pkcs8(
cert.cert.pem().as_bytes(),
cert.key_pair.serialize_pem().as_bytes(),
)
.unwrap(),
)
.unwrap(),
);
let (tcp, _) = listener.accept().await.unwrap();
let mut tls = acceptor.accept(tcp).await.unwrap();
let mut buf = String::new();
tls.read_to_string(&mut buf).await.unwrap();
println!("read: {buf}");
}
rustls
这里是使用
rustls
的类似代码。差异包括:
[package]
name = "tls"
version = "0.1.0"
edition = "2021"
[dependencies]
rcgen = "0.13.1"
tokio = { version = "1.41.1", features = ["full"] }
tokio-rustls = "0.26.0"
use std::net::Ipv4Addr;
use std::sync::Arc;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::{TcpListener, TcpStream};
use tokio_rustls::rustls::pki_types::pem::PemObject;
use tokio_rustls::rustls::pki_types::{PrivateKeyDer, PrivatePkcs8KeyDer, ServerName};
use tokio_rustls::rustls::{ClientConfig, RootCertStore};
use tokio_rustls::{rustls, TlsAcceptor, TlsConnector};
#[tokio::main]
async fn main() {
let cert = rcgen::generate_simple_self_signed(["127.0.0.1".to_owned()]).unwrap();
let listener = TcpListener::bind("127.0.0.1:8001").await.unwrap();
let mut trusted = RootCertStore::empty();
trusted.add(cert.cert.der().clone()).unwrap();
tokio::spawn(async move {
let connector: TlsConnector = TlsConnector::from(Arc::new(
ClientConfig::builder()
.with_root_certificates(trusted)
.with_no_client_auth(),
));
let tcp = TcpStream::connect("127.0.0.1:8001").await.unwrap();
let mut tls = connector
.connect(
ServerName::IpAddress(Ipv4Addr::new(127, 0, 0, 1).into()),
tcp,
)
.await
.unwrap();
tls.write_all(b"hello!").await.unwrap();
tls.shutdown().await.unwrap();
});
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(),
));
let (tcp, _) = listener.accept().await.unwrap();
let mut tls = acceptor.accept(tcp).await.unwrap();
let mut buf = String::new();
tls.read_to_string(&mut buf).await.unwrap();
println!("read: {buf}");
}
如果您想使用 CA 签名的证书,则可以将 CA 证书添加为受信任的根。