mirror of
https://github.com/wez/wezterm.git
synced 2024-11-23 15:04:36 +03:00
factor out tls client configuration
We can now also specify multiple tls clients
This commit is contained in:
parent
86251f1787
commit
9054343e51
@ -87,39 +87,9 @@ pub struct Config {
|
||||
#[serde(default)]
|
||||
pub tls_servers: Vec<TlsDomainServer>,
|
||||
|
||||
/// When using the mux client domain, identifies the host:port
|
||||
/// pair of the remote server.
|
||||
pub mux_server_remote_address: Option<String>,
|
||||
|
||||
/// When using the mux client domain:
|
||||
/// the path to an x509 PEM encoded private key file
|
||||
pub mux_client_pem_private_key: Option<PathBuf>,
|
||||
|
||||
/// When using the mux client domain:
|
||||
/// the path to an x509 PEM encoded certificate file
|
||||
pub mux_client_pem_cert: Option<PathBuf>,
|
||||
|
||||
/// When using the mux client domain:
|
||||
/// the path to an x509 PEM encoded CA chain file
|
||||
pub mux_client_pem_ca: Option<PathBuf>,
|
||||
|
||||
pub mux_pem_root_certs: Option<Vec<PathBuf>>,
|
||||
|
||||
/// When using the mux client domain, explicitly control whether
|
||||
/// the client checks that the certificate presented by the
|
||||
/// server matches the hostname portion of mux_server_remote_address.
|
||||
/// The default is true.
|
||||
/// This option is made available for troubleshooting purposes and
|
||||
/// should not be used outside of a controlled environment as it
|
||||
/// weakens the security of the TLS channel.
|
||||
pub mux_client_accept_invalid_hostnames: Option<bool>,
|
||||
|
||||
/// When connecting to a mux server, the hostname string that we
|
||||
/// expect to match against the common name field in the certificate
|
||||
/// presented by the server. This defaults to the hostname portion
|
||||
/// of the `mux_server_bind_address` configuration and you should
|
||||
/// not normally need to override this value.
|
||||
pub mux_client_expected_cn: Option<String>,
|
||||
/// The set of tls domains that we can connect to as a client
|
||||
#[serde(default)]
|
||||
pub tls_clients: Vec<TlsDomainClient>,
|
||||
|
||||
/// Constrains the rate at which output from a child command is
|
||||
/// processed and applied to the terminal model.
|
||||
@ -444,6 +414,43 @@ pub struct TlsDomainServer {
|
||||
pub pem_root_certs: Vec<PathBuf>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Deserialize)]
|
||||
pub struct TlsDomainClient {
|
||||
/// identifies the host:port pair of the remote server.
|
||||
pub remote_address: String,
|
||||
|
||||
/// the path to an x509 PEM encoded private key file
|
||||
pub pem_private_key: Option<PathBuf>,
|
||||
|
||||
/// the path to an x509 PEM encoded certificate file
|
||||
pub pem_cert: Option<PathBuf>,
|
||||
|
||||
/// the path to an x509 PEM encoded CA chain file
|
||||
pub pem_ca: Option<PathBuf>,
|
||||
|
||||
/// A set of paths to load additional CA certificates.
|
||||
/// Each entry can be either the path to a directory or to a PEM encoded
|
||||
/// CA file. If an entry is a directory, then its contents will be
|
||||
/// loaded as CA certs and added to the trust store.
|
||||
#[serde(default)]
|
||||
pub pem_root_certs: Vec<PathBuf>,
|
||||
|
||||
/// explicitly control whether the client checks that the certificate
|
||||
/// presented by the server matches the hostname portion of
|
||||
/// `remote_address`. The default is true. This option is made
|
||||
/// available for troubleshooting purposes and should not be used outside
|
||||
/// of a controlled environment as it weakens the security of the TLS
|
||||
/// channel.
|
||||
#[serde(default)]
|
||||
pub accept_invalid_hostnames: bool,
|
||||
|
||||
/// the hostname string that we expect to match against the common name
|
||||
/// field in the certificate presented by the server. This defaults to
|
||||
/// the hostname portion of the `remote_address` configuration and you
|
||||
/// should not normally need to override this value.
|
||||
pub expected_cn: Option<String>,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
@ -459,19 +466,13 @@ impl Default for Config {
|
||||
hyperlink_rules: default_hyperlink_rules(),
|
||||
term: default_term(),
|
||||
default_prog: None,
|
||||
mux_server_remote_address: None,
|
||||
mux_client_pem_private_key: None,
|
||||
mux_client_pem_cert: None,
|
||||
mux_client_pem_ca: None,
|
||||
mux_client_accept_invalid_hostnames: None,
|
||||
mux_client_expected_cn: None,
|
||||
ratelimit_output_bytes_per_second: None,
|
||||
ratelimit_mux_output_pushes_per_second: None,
|
||||
ratelimit_mux_output_scans_per_second: None,
|
||||
mux_pem_root_certs: None,
|
||||
unix_domains: UnixDomain::default_unix_domains(),
|
||||
keys: vec![],
|
||||
tls_servers: vec![],
|
||||
tls_clients: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -150,7 +150,11 @@ fn run_terminal_gui(config: Arc<config::Config>, opts: &StartCommand) -> Result<
|
||||
let client = Client::new_default_unix_domain(&config)?;
|
||||
Arc::new(ClientDomain::new(client))
|
||||
} else if opts.mux_tls_client_as_default_domain {
|
||||
let client = Client::new_tls(&config)?;
|
||||
let tls_client = config
|
||||
.tls_clients
|
||||
.first()
|
||||
.expect("tls clients to be configured");
|
||||
let client = Client::new_tls(&config, tls_client)?;
|
||||
Arc::new(ClientDomain::new(client))
|
||||
} else {
|
||||
Arc::new(LocalDomain::new(&config)?)
|
||||
|
@ -1,5 +1,5 @@
|
||||
#![allow(dead_code)]
|
||||
use crate::config::{Config, UnixDomain};
|
||||
use crate::config::{Config, TlsDomainClient, UnixDomain};
|
||||
use crate::frontend::gui_executor;
|
||||
use crate::mux::Mux;
|
||||
use crate::server::codec::*;
|
||||
@ -7,7 +7,7 @@ use crate::server::pollable::*;
|
||||
use crate::server::tab::ClientTab;
|
||||
use crate::server::UnixStream;
|
||||
use crossbeam_channel::TryRecvError;
|
||||
use failure::{bail, err_msg, format_err, Fallible};
|
||||
use failure::{bail, format_err, Fallible};
|
||||
use log::info;
|
||||
use promise::{Future, Promise};
|
||||
use std::collections::HashMap;
|
||||
@ -159,17 +159,14 @@ impl Client {
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "openssl", unix))]
|
||||
pub fn new_tls(config: &Arc<Config>) -> Fallible<Self> {
|
||||
pub fn new_tls(_config: &Arc<Config>, tls_client: &TlsDomainClient) -> Fallible<Self> {
|
||||
use crate::server::listener::read_bytes;
|
||||
use openssl::ssl::{SslConnector, SslFiletype, SslMethod};
|
||||
use openssl::x509::X509;
|
||||
|
||||
openssl::init();
|
||||
|
||||
let remote_address = config
|
||||
.mux_server_remote_address
|
||||
.as_ref()
|
||||
.ok_or_else(|| err_msg("missing mux_server_remote_address config value"))?;
|
||||
let remote_address = &tls_client.remote_address;
|
||||
|
||||
let remote_host_name = remote_address.split(':').next().ok_or_else(|| {
|
||||
format_err!(
|
||||
@ -180,38 +177,36 @@ impl Client {
|
||||
|
||||
let mut connector = SslConnector::builder(SslMethod::tls())?;
|
||||
|
||||
if let Some(cert_file) = config.mux_client_pem_cert.as_ref() {
|
||||
if let Some(cert_file) = tls_client.pem_cert.as_ref() {
|
||||
connector.set_certificate_file(cert_file, SslFiletype::PEM)?;
|
||||
}
|
||||
if let Some(chain_file) = config.mux_client_pem_ca.as_ref() {
|
||||
if let Some(chain_file) = tls_client.pem_ca.as_ref() {
|
||||
connector.set_certificate_chain_file(chain_file)?;
|
||||
}
|
||||
if let Some(key_file) = config.mux_client_pem_private_key.as_ref() {
|
||||
if let Some(key_file) = tls_client.pem_private_key.as_ref() {
|
||||
connector.set_private_key_file(key_file, SslFiletype::PEM)?;
|
||||
}
|
||||
if let Some(root_certs) = config.mux_pem_root_certs.as_ref() {
|
||||
fn load_cert(name: &Path) -> Fallible<X509> {
|
||||
let cert_bytes = read_bytes(name)?;
|
||||
log::trace!("loaded {}", name.display());
|
||||
Ok(X509::from_pem(&cert_bytes)?)
|
||||
}
|
||||
for name in root_certs {
|
||||
if name.is_dir() {
|
||||
for entry in std::fs::read_dir(name)? {
|
||||
if let Ok(cert) = load_cert(&entry?.path()) {
|
||||
connector.cert_store_mut().add_cert(cert).ok();
|
||||
}
|
||||
fn load_cert(name: &Path) -> Fallible<X509> {
|
||||
let cert_bytes = read_bytes(name)?;
|
||||
log::trace!("loaded {}", name.display());
|
||||
Ok(X509::from_pem(&cert_bytes)?)
|
||||
}
|
||||
for name in &tls_client.pem_root_certs {
|
||||
if name.is_dir() {
|
||||
for entry in std::fs::read_dir(name)? {
|
||||
if let Ok(cert) = load_cert(&entry?.path()) {
|
||||
connector.cert_store_mut().add_cert(cert).ok();
|
||||
}
|
||||
} else {
|
||||
connector.cert_store_mut().add_cert(load_cert(name)?)?;
|
||||
}
|
||||
} else {
|
||||
connector.cert_store_mut().add_cert(load_cert(name)?)?;
|
||||
}
|
||||
}
|
||||
|
||||
let connector = connector.build();
|
||||
let connector = connector
|
||||
.configure()?
|
||||
.verify_hostname(!config.mux_client_accept_invalid_hostnames.unwrap_or(false));
|
||||
.verify_hostname(!tls_client.accept_invalid_hostnames);
|
||||
|
||||
let stream = TcpStream::connect(remote_address)
|
||||
.map_err(|e| format_err!("connecting to {}: {}", remote_address, e))?;
|
||||
@ -220,8 +215,8 @@ impl Client {
|
||||
let stream = Box::new(
|
||||
connector
|
||||
.connect(
|
||||
config
|
||||
.mux_client_expected_cn
|
||||
tls_client
|
||||
.expected_cn
|
||||
.as_ref()
|
||||
.map(String::as_str)
|
||||
.unwrap_or(remote_host_name),
|
||||
@ -241,15 +236,12 @@ impl Client {
|
||||
}
|
||||
|
||||
#[cfg(not(any(feature = "openssl", unix)))]
|
||||
pub fn new_tls(config: &Arc<Config>) -> Fallible<Self> {
|
||||
pub fn new_tls(_config: &Arc<Config>, tls_client: &TlsDomainClient) -> Fallible<Self> {
|
||||
use crate::server::listener::IdentitySource;
|
||||
use native_tls::TlsConnector;
|
||||
use std::convert::TryInto;
|
||||
|
||||
let remote_address = config
|
||||
.mux_server_remote_address
|
||||
.as_ref()
|
||||
.ok_or_else(|| err_msg("missing mux_server_remote_address config value"))?;
|
||||
let remote_address = &tls_client.remote_address;
|
||||
|
||||
let remote_host_name = remote_address.split(':').next().ok_or_else(|| {
|
||||
format_err!(
|
||||
@ -259,20 +251,18 @@ impl Client {
|
||||
})?;
|
||||
|
||||
let identity = IdentitySource::PemFiles {
|
||||
key: config
|
||||
.mux_client_pem_private_key
|
||||
key: tls_client
|
||||
.pem_private_key
|
||||
.as_ref()
|
||||
.ok_or_else(|| err_msg("missing mux_client_pem_private_key config value"))?
|
||||
.ok_or_else(|| failure::err_msg("missing mux_client_pem_private_key config value"))?
|
||||
.into(),
|
||||
cert: config.mux_client_pem_cert.clone(),
|
||||
chain: config.mux_client_pem_ca.clone(),
|
||||
cert: tls_client.pem_cert.clone(),
|
||||
chain: tls_client.pem_ca.clone(),
|
||||
};
|
||||
|
||||
let connector = TlsConnector::builder()
|
||||
.identity(identity.try_into()?)
|
||||
.danger_accept_invalid_hostnames(
|
||||
config.mux_client_accept_invalid_hostnames.unwrap_or(false),
|
||||
)
|
||||
.danger_accept_invalid_hostnames(tls_client.accept_invalid_hostnames.unwrap_or(false))
|
||||
.build()?;
|
||||
|
||||
let stream = TcpStream::connect(remote_address)
|
||||
|
Loading…
Reference in New Issue
Block a user