mirror of
https://github.com/nukesor/pueue
synced 2024-10-01 13:34:07 +00:00
Server side tls code
This commit is contained in:
parent
36435b3781
commit
3b2e711271
88
Cargo.lock
generated
88
Cargo.lock
generated
|
@ -136,6 +136,19 @@ version = "4.0.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e91831deabf0d6d7ec49552e489aed63b7456a7a3c46cff62adad428110b0af0"
|
||||
|
||||
[[package]]
|
||||
name = "async-tls"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f23d769dbf1838d5df5156e7b1ad404f4c463d1ac2c6aeb6cd943630f8a8400"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"rustls",
|
||||
"webpki",
|
||||
"webpki-roots",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.42"
|
||||
|
@ -686,9 +699,9 @@ checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35"
|
|||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.6.0"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55e2e4c765aa53a0424761bf9f41aa7a6ac1efa87238f59560640e27fca028f2"
|
||||
checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
|
@ -1153,6 +1166,7 @@ version = "0.9.1-alpha.0"
|
|||
dependencies = [
|
||||
"anyhow",
|
||||
"async-std",
|
||||
"async-tls",
|
||||
"async-trait",
|
||||
"bincode",
|
||||
"byteorder",
|
||||
|
@ -1173,6 +1187,7 @@ dependencies = [
|
|||
"proptest",
|
||||
"psutil",
|
||||
"rand",
|
||||
"rustls",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
|
@ -1289,6 +1304,21 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.16.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "024a1e66fea74c66c66624ee5622a7ff0e4b73a13b4f5c326ddb50c708944226"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"spin",
|
||||
"untrusted",
|
||||
"web-sys",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-argon2"
|
||||
version = "0.8.3"
|
||||
|
@ -1301,6 +1331,19 @@ dependencies = [
|
|||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "064fd21ff87c6e87ed4506e68beb42459caa4a0e2eb144932e6776768556980b"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"log",
|
||||
"ring",
|
||||
"sct",
|
||||
"webpki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rusty-fork"
|
||||
version = "0.3.0"
|
||||
|
@ -1331,6 +1374,16 @@ version = "1.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "sct"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3042af939fca8c3453b7af0f1c66e533a15a86169e39de2657310ade8f98d3c"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.118"
|
||||
|
@ -1443,6 +1496,12 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
|
@ -1583,6 +1642,12 @@ version = "0.2.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
|
||||
|
||||
[[package]]
|
||||
name = "users"
|
||||
version = "0.11.0"
|
||||
|
@ -1720,6 +1785,25 @@ dependencies = [
|
|||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki"
|
||||
version = "0.21.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki-roots"
|
||||
version = "0.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82015b7e0b8bad8185994674a13a93306bea76cf5a16c5a181382fd3a5ec2376"
|
||||
dependencies = [
|
||||
"webpki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wepoll-sys"
|
||||
version = "3.0.1"
|
||||
|
|
|
@ -29,7 +29,9 @@ path = "shared/lib.rs"
|
|||
[dependencies]
|
||||
anyhow = "1"
|
||||
async-std = { version = "1", features = ["attributes", "std"] }
|
||||
async-tls = "0.11"
|
||||
async-trait = "0.1"
|
||||
rustls = "0.19"
|
||||
dirs = "3"
|
||||
chrono = { version = "^0.4", features = ["serde"] }
|
||||
chrono-english = "^0.1.0"
|
||||
|
|
|
@ -1,25 +1,28 @@
|
|||
use std::sync::mpsc::Sender;
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use async_std::task;
|
||||
use async_tls::TlsAcceptor;
|
||||
use log::{debug, info, warn};
|
||||
|
||||
use pueue::message::*;
|
||||
use pueue::protocol::*;
|
||||
use pueue::state::SharedState;
|
||||
use pueue::tls::load_config;
|
||||
|
||||
use crate::cli::CliArguments;
|
||||
use crate::instructions::handle_message;
|
||||
use crate::streaming::handle_follow;
|
||||
|
||||
/// Poll the unix listener and accept new incoming connections.
|
||||
/// Poll the listener and accept new incoming connections.
|
||||
/// Create a new future to handle the message and spawn it.
|
||||
pub async fn accept_incoming(
|
||||
sender: Sender<Message>,
|
||||
state: SharedState,
|
||||
opt: CliArguments,
|
||||
) -> Result<()> {
|
||||
let (unix_socket_path, port) = {
|
||||
let (unix_socket_path, tcp_info) = {
|
||||
let state = state.lock().unwrap();
|
||||
let shared = &state.settings.shared;
|
||||
|
||||
|
@ -27,29 +30,46 @@ pub async fn accept_incoming(
|
|||
if shared.use_unix_socket {
|
||||
(Some(shared.unix_socket_path.clone()), None)
|
||||
} else {
|
||||
// Otherwise use tcp sockets and a given port
|
||||
// Otherwise use tcp sockets on a given port and host.
|
||||
// Commandline argument overwrites the configuration files values for port.
|
||||
// This also initializes the TLS acceptor.
|
||||
let port = if let Some(port) = opt.port.clone() {
|
||||
port
|
||||
} else {
|
||||
shared.port.clone()
|
||||
};
|
||||
|
||||
(None, Some(port))
|
||||
let config = load_config(&state.settings)?;
|
||||
let acceptor = TlsAcceptor::from(Arc::new(config));
|
||||
(None, Some((port, acceptor)))
|
||||
}
|
||||
};
|
||||
|
||||
let listener = get_listener(unix_socket_path, port).await?;
|
||||
let listener = get_listener(unix_socket_path, tcp_info.clone()).await?;
|
||||
|
||||
loop {
|
||||
// Poll if we have a new incoming connection.
|
||||
let socket = listener.accept().await?;
|
||||
// Poll incoming connections.
|
||||
// We have to decide between Unix sockets and TCP sockets.
|
||||
// In case of a TCP connection, we have to add a TLS layer.
|
||||
let stream = if let Some((_, acceptor)) = tcp_info.clone() {
|
||||
let stream = listener.accept().await?;
|
||||
Box::new(acceptor.accept(stream).await?)
|
||||
} else {
|
||||
listener.accept().await?
|
||||
};
|
||||
|
||||
//let socket = if let Some((_, ref acceptor)) = tcp_info {
|
||||
// let stream = listener.accept().await?;
|
||||
// Box::new(acceptor.accept(stream)?)
|
||||
//} else {
|
||||
// listener.accept().await?
|
||||
//};
|
||||
|
||||
// Start a new task for the request
|
||||
let sender_clone = sender.clone();
|
||||
let state_clone = state.clone();
|
||||
task::spawn(async move {
|
||||
let _result = handle_incoming(socket, sender_clone, state_clone).await;
|
||||
let _result = handle_incoming(stream, sender_clone, state_clone).await;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,3 +6,4 @@ pub mod protocol;
|
|||
pub mod settings;
|
||||
pub mod state;
|
||||
pub mod task;
|
||||
pub mod tls;
|
||||
|
|
|
@ -4,6 +4,7 @@ use anyhow::{bail, Context, Result};
|
|||
use async_std::io::{Read, Write};
|
||||
use async_std::net::{TcpListener, TcpStream};
|
||||
use async_std::os::unix::net::{UnixListener, UnixStream};
|
||||
use async_tls::{server::TlsStream, TlsAcceptor};
|
||||
use async_trait::async_trait;
|
||||
|
||||
/// A new trait, which can be used to represent Unix- and TcpListeners.
|
||||
|
@ -31,9 +32,10 @@ impl GenericListener for UnixListener {
|
|||
|
||||
/// A new trait, which can be used to represent Unix- and TcpStream.
|
||||
/// This is necessary to easily write generic functions where both types can be used.
|
||||
pub trait GenericSocket: Read + Write + Unpin + Send + Sync {}
|
||||
pub trait GenericSocket: Read + Write + Unpin + Send {}
|
||||
impl GenericSocket for TcpStream {}
|
||||
impl GenericSocket for UnixStream {}
|
||||
impl GenericSocket for TlsStream<Box<dyn GenericSocket>> {}
|
||||
|
||||
/// Two convenient types, so we don't have type write Box<dyn ...> all the time.
|
||||
pub type Listener = Box<dyn GenericListener>;
|
||||
|
@ -73,7 +75,7 @@ pub async fn get_client(unix_socket_path: Option<String>, port: Option<String>)
|
|||
/// which depends on the parameters.
|
||||
pub async fn get_listener(
|
||||
unix_socket_path: Option<String>,
|
||||
port: Option<String>,
|
||||
port: Option<(String, TlsAcceptor)>,
|
||||
) -> Result<Listener> {
|
||||
if let Some(socket_path) = unix_socket_path {
|
||||
// Check, if the socket already exists
|
||||
|
@ -95,7 +97,7 @@ pub async fn get_listener(
|
|||
return Ok(Box::new(UnixListener::bind(socket_path).await?));
|
||||
}
|
||||
|
||||
let port = port.unwrap();
|
||||
let (port, _) = port.unwrap();
|
||||
let address = format!("127.0.0.1:{}", port);
|
||||
Ok(Box::new(TcpListener::bind(address).await?))
|
||||
}
|
||||
|
|
|
@ -14,11 +14,16 @@ use crate::platform::directories::*;
|
|||
/// All settings which are used by both, the client and the daemon
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct Shared {
|
||||
pub port: String,
|
||||
pub secret: String,
|
||||
pub pueue_directory: String,
|
||||
pub use_unix_socket: bool,
|
||||
pub unix_socket_path: String,
|
||||
|
||||
pub url: String,
|
||||
pub port: String,
|
||||
pub daemon_cert: PathBuf,
|
||||
pub daemon_key: PathBuf,
|
||||
pub client_cert: String,
|
||||
}
|
||||
|
||||
/// All settings which are used by the client
|
||||
|
@ -57,12 +62,19 @@ impl Settings {
|
|||
pub fn new(require_config: bool, from_file: &Option<PathBuf>) -> Result<Settings> {
|
||||
let mut config = Config::new();
|
||||
|
||||
config.set_default("shared.port", "6924")?;
|
||||
let pueue_path = default_pueue_path()?;
|
||||
config.set_default("shared.secret", gen_random_secret())?;
|
||||
config.set_default("shared.pueue_directory", default_pueue_path()?)?;
|
||||
config.set_default("shared.pueue_directory", pueue_path.clone())?;
|
||||
config.set_default("shared.use_unix_socket", false)?;
|
||||
config.set_default("shared.unix_socket_path", get_unix_socket_path()?)?;
|
||||
|
||||
config.set_default("shared.url", "localhost")?;
|
||||
config.set_default("shared.port", "6924")?;
|
||||
config.set_default("shared.tls_enabled", true)?;
|
||||
config.set_default("shared.key_cert", pueue_path.clone() + "/daemon.key")?;
|
||||
config.set_default("shared.daemon_cert", pueue_path.clone() + "/daemon.cert")?;
|
||||
config.set_default("shared.client_cert", pueue_path + "/client.cert")?;
|
||||
|
||||
// Client specific config
|
||||
config.set_default("client.read_local_logs", true)?;
|
||||
config.set_default("client.show_expanded_aliases", false)?;
|
||||
|
|
42
shared/tls.rs
Normal file
42
shared/tls.rs
Normal file
|
@ -0,0 +1,42 @@
|
|||
use std::{
|
||||
fs::File,
|
||||
io::{self, BufReader},
|
||||
path::Path,
|
||||
};
|
||||
|
||||
use rustls::{
|
||||
internal::pemfile::certs, internal::pemfile::rsa_private_keys, Certificate, NoClientAuth,
|
||||
PrivateKey, ServerConfig,
|
||||
};
|
||||
|
||||
use crate::settings::Settings;
|
||||
|
||||
/// Configure the server using rusttls
|
||||
/// See https://docs.rs/rustls/0.16.0/rustls/struct.ServerConfig.html for details
|
||||
///
|
||||
/// A TLS server needs a certificate and a fitting private key
|
||||
pub fn load_config(settings: &Settings) -> io::Result<ServerConfig> {
|
||||
let certs = load_certs(&settings.shared.daemon_cert)?;
|
||||
let mut keys = load_keys(&settings.shared.daemon_key)?;
|
||||
|
||||
// we don't use client authentication
|
||||
let mut config = ServerConfig::new(NoClientAuth::new());
|
||||
config
|
||||
// set this server to use one cert together with the loaded private key
|
||||
.set_single_cert(certs, keys.remove(0))
|
||||
.map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err))?;
|
||||
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
/// Load the passed certificates file
|
||||
fn load_certs(path: &Path) -> io::Result<Vec<Certificate>> {
|
||||
certs(&mut BufReader::new(File::open(path)?))
|
||||
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid cert"))
|
||||
}
|
||||
|
||||
/// Load the passed keys file
|
||||
fn load_keys(path: &Path) -> io::Result<Vec<PrivateKey>> {
|
||||
rsa_private_keys(&mut BufReader::new(File::open(path)?))
|
||||
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid key"))
|
||||
}
|
Loading…
Reference in a new issue