Implement PTY-native session terminal control
This commit is contained in:
parent
058e58e816
commit
8cef037fa3
1 changed files with 1488 additions and 382 deletions
|
|
@ -28,6 +28,7 @@ use rustls::{ClientConfig, ClientConnection, RootCertStore};
|
|||
use sha2::{Digest, Sha256};
|
||||
|
||||
pub const CONTROL_ALPN: &[u8] = b"lazaret-control/1";
|
||||
pub const CONTROL_ALPN_V2: &[u8] = b"lazaret-control/2";
|
||||
pub const CONTROL_SERVER_NAME: &str = "coordinator.lazaret.invalid";
|
||||
pub const CONTROL_SOCKET_NAME: &str = "c.sock";
|
||||
pub const PUBLICATION_IDENTITY_NAME: &str = "protocol-identity.postcard";
|
||||
|
|
@ -237,6 +238,25 @@ impl ControlClient {
|
|||
pub fn config(
|
||||
publication: &ProtocolPublicationIdentity,
|
||||
client: Option<(&TlsCredential, PrivateKeyDer<'static>)>,
|
||||
) -> Result<ClientConfig, ControlClientError> {
|
||||
Self::config_with_alpn(publication, client, CONTROL_ALPN)
|
||||
}
|
||||
|
||||
/// Creates a TLS client configuration for the interactive v2 protocol.
|
||||
///
|
||||
/// # Errors
|
||||
/// Returns malformed trust or credential failures.
|
||||
pub fn config_v2(
|
||||
publication: &ProtocolPublicationIdentity,
|
||||
client: Option<(&TlsCredential, PrivateKeyDer<'static>)>,
|
||||
) -> Result<ClientConfig, ControlClientError> {
|
||||
Self::config_with_alpn(publication, client, CONTROL_ALPN_V2)
|
||||
}
|
||||
|
||||
fn config_with_alpn(
|
||||
publication: &ProtocolPublicationIdentity,
|
||||
client: Option<(&TlsCredential, PrivateKeyDer<'static>)>,
|
||||
alpn: &[u8],
|
||||
) -> Result<ClientConfig, ControlClientError> {
|
||||
let mut roots = RootCertStore::empty();
|
||||
roots.add(CertificateDer::from(
|
||||
|
|
@ -258,7 +278,7 @@ impl ControlClient {
|
|||
} else {
|
||||
builder.with_no_client_auth()
|
||||
};
|
||||
config.alpn_protocols = vec![CONTROL_ALPN.to_vec()];
|
||||
config.alpn_protocols = vec![alpn.to_vec()];
|
||||
config.enable_early_data = false;
|
||||
config.resumption = rustls::client::Resumption::disabled();
|
||||
Ok(config)
|
||||
|
|
@ -275,6 +295,33 @@ impl ControlClient {
|
|||
) -> Result<
|
||||
rustls::StreamOwned<ClientConnection, std::os::unix::net::UnixStream>,
|
||||
ControlClientError,
|
||||
> {
|
||||
Self::connect_with_alpn(socket_path, config, publication, CONTROL_ALPN)
|
||||
}
|
||||
|
||||
/// Connects a pinned TLS stream using the interactive v2 ALPN.
|
||||
///
|
||||
/// # Errors
|
||||
/// Returns socket, TLS, or certificate-profile failures.
|
||||
pub fn connect_v2(
|
||||
socket_path: &Path,
|
||||
config: ClientConfig,
|
||||
publication: &ProtocolPublicationIdentity,
|
||||
) -> Result<
|
||||
rustls::StreamOwned<ClientConnection, std::os::unix::net::UnixStream>,
|
||||
ControlClientError,
|
||||
> {
|
||||
Self::connect_with_alpn(socket_path, config, publication, CONTROL_ALPN_V2)
|
||||
}
|
||||
|
||||
fn connect_with_alpn(
|
||||
socket_path: &Path,
|
||||
config: ClientConfig,
|
||||
publication: &ProtocolPublicationIdentity,
|
||||
alpn: &[u8],
|
||||
) -> Result<
|
||||
rustls::StreamOwned<ClientConnection, std::os::unix::net::UnixStream>,
|
||||
ControlClientError,
|
||||
> {
|
||||
let socket = std::os::unix::net::UnixStream::connect(socket_path)?;
|
||||
let server_name = ServerName::try_from(CONTROL_SERVER_NAME)
|
||||
|
|
@ -288,7 +335,7 @@ impl ControlClient {
|
|||
return Err(ControlClientError::InvalidCertificateProfile);
|
||||
};
|
||||
if connection.protocol_version() != Some(rustls::ProtocolVersion::TLSv1_3)
|
||||
|| connection.alpn_protocol() != Some(CONTROL_ALPN)
|
||||
|| connection.alpn_protocol() != Some(alpn)
|
||||
|| certificate_digest(certificate) != publication.coordinator_tls_certificate_sha256
|
||||
{
|
||||
return Err(ControlClientError::InvalidCertificateProfile);
|
||||
|
|
|
|||
Loading…
Reference in a new issue