mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
vm-migration: server-side of a TLS connection
Code for the TLS server, i.e. the receiver of a live migration. On-behalf-of: SAP sebastian.eydam@sap.com Signed-off-by: Sebastian Eydam <sebastian.eydam@cyberus-technology.de>
This commit is contained in:
committed by
Rob Bradford
parent
8e9d779688
commit
eaceef5aa0
@@ -26,8 +26,10 @@ use std::sync::Arc;
|
|||||||
use log::warn;
|
use log::warn;
|
||||||
use rustls::pki_types::pem::PemObject;
|
use rustls::pki_types::pem::PemObject;
|
||||||
use rustls::pki_types::{CertificateDer, InvalidDnsNameError, PrivateKeyDer, ServerName};
|
use rustls::pki_types::{CertificateDer, InvalidDnsNameError, PrivateKeyDer, ServerName};
|
||||||
use rustls::server::VerifierBuilderError;
|
use rustls::server::{VerifierBuilderError, WebPkiClientVerifier};
|
||||||
use rustls::{ClientConfig, ClientConnection, RootCertStore, StreamOwned};
|
use rustls::{
|
||||||
|
ClientConfig, ClientConnection, RootCertStore, ServerConfig, ServerConnection, StreamOwned,
|
||||||
|
};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::MigratableError;
|
use crate::MigratableError;
|
||||||
@@ -35,6 +37,8 @@ use crate::MigratableError;
|
|||||||
const CA_CERT_FILE: &str = "ca-cert.pem";
|
const CA_CERT_FILE: &str = "ca-cert.pem";
|
||||||
const CLIENT_CERT_FILE: &str = "client-cert.pem";
|
const CLIENT_CERT_FILE: &str = "client-cert.pem";
|
||||||
const CLIENT_KEY_FILE: &str = "client-key.pem";
|
const CLIENT_KEY_FILE: &str = "client-key.pem";
|
||||||
|
const SERVER_CERT_FILE: &str = "server-cert.pem";
|
||||||
|
const SERVER_KEY_FILE: &str = "server-key.pem";
|
||||||
|
|
||||||
/// Errors that can occur when establishing a TLS-encrypted migration channel.
|
/// Errors that can occur when establishing a TLS-encrypted migration channel.
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
@@ -67,6 +71,7 @@ pub enum TlsError {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum TlsStreamParticipant {
|
enum TlsStreamParticipant {
|
||||||
Client(StreamOwned<ClientConnection, TcpStream>),
|
Client(StreamOwned<ClientConnection, TcpStream>),
|
||||||
|
Server(StreamOwned<ServerConnection, TcpStream>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Server/Client-agnostic TLS stream.
|
/// Server/Client-agnostic TLS stream.
|
||||||
@@ -122,6 +127,72 @@ impl TlsStream {
|
|||||||
stream: TlsStreamParticipant::Client(tls),
|
stream: TlsStreamParticipant::Client(tls),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a server [`TlsStream`]. Encrypts and decrypts data sent through
|
||||||
|
/// this stream using the certificates and key from the provided
|
||||||
|
/// [`TlsServerConfig`].
|
||||||
|
pub fn new_server(
|
||||||
|
socket: TcpStream,
|
||||||
|
config: &TlsServerConfig,
|
||||||
|
) -> result::Result<Self, MigratableError> {
|
||||||
|
let conn = ServerConnection::new(config.config.clone())
|
||||||
|
.map_err(TlsError::RustlsError)
|
||||||
|
.map_err(MigratableError::Tls)?;
|
||||||
|
|
||||||
|
let mut tls = StreamOwned::new(conn, socket);
|
||||||
|
while tls.conn.is_handshaking() {
|
||||||
|
let (rd, wr) = tls
|
||||||
|
.conn
|
||||||
|
.complete_io(&mut tls.sock)
|
||||||
|
.map_err(TlsError::RustlsIoError)
|
||||||
|
.map_err(MigratableError::Tls)?;
|
||||||
|
// No handshake progress on a connection that should be handshaking, we treat
|
||||||
|
// that as a failure.
|
||||||
|
if rd == 0 && wr == 0 {
|
||||||
|
return Err(MigratableError::Tls(TlsError::HandshakeError));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
stream: TlsStreamParticipant::Server(tls),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Carries a TLS server configuration. Intended to be turned into a [`TlsStream`]
|
||||||
|
/// when paired with a [`TcpStream`].
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct TlsServerConfig {
|
||||||
|
/// This config is shared between all server connections.
|
||||||
|
config: Arc<ServerConfig>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TlsServerConfig {
|
||||||
|
/// Creates a [`TlsServerConfig`] from the certificate chain in
|
||||||
|
/// `server-cert.pem`, the private key in `server-key.pem`, and the client
|
||||||
|
/// trust anchors in `ca-cert.pem`.
|
||||||
|
///
|
||||||
|
/// Client certificates presented during the TLS handshake must chain to a CA in
|
||||||
|
/// `ca-cert.pem`.
|
||||||
|
pub fn new(cert_dir: &Path) -> result::Result<Self, MigratableError> {
|
||||||
|
let server_certs = load_cert_chain(&cert_dir.join(SERVER_CERT_FILE))?;
|
||||||
|
let server_key = load_private_key(&cert_dir.join(SERVER_KEY_FILE))?;
|
||||||
|
// Trust anchors used to verify client certificates for mTLS.
|
||||||
|
let client_roots = Arc::new(load_root_store(&cert_dir.join(CA_CERT_FILE))?);
|
||||||
|
|
||||||
|
let client_verifier = WebPkiClientVerifier::builder(client_roots)
|
||||||
|
.build()
|
||||||
|
.map_err(TlsError::RustlsVerifierBuilderError)
|
||||||
|
.map_err(MigratableError::Tls)?;
|
||||||
|
|
||||||
|
let config = ServerConfig::builder()
|
||||||
|
.with_client_cert_verifier(client_verifier)
|
||||||
|
.with_single_cert(server_certs, server_key)
|
||||||
|
.map_err(TlsError::RustlsError)
|
||||||
|
.map_err(MigratableError::Tls)?;
|
||||||
|
let config = Arc::new(config);
|
||||||
|
Ok(Self { config })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads trusted CA certificates into a root store, i.e. the set of trust anchors
|
/// Loads trusted CA certificates into a root store, i.e. the set of trust anchors
|
||||||
|
|||||||
Reference in New Issue
Block a user