1
1
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:
Wez Furlong 2019-06-22 09:04:13 -07:00
parent 86251f1787
commit 9054343e51
3 changed files with 76 additions and 81 deletions

View File

@ -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![],
}
}
}

View File

@ -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)?)

View File

@ -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)