Certificate generation

This commit is contained in:
Arne Beer 2020-12-19 20:36:51 +01:00
parent 9c292dbe5f
commit dd44788fc7
7 changed files with 136 additions and 19 deletions

49
Cargo.lock generated
View file

@ -284,12 +284,6 @@ version = "1.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
[[package]]
name = "bytes"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0dcbc35f504eb6fc275a6d20e4ebcda18cf50d40ba6fabff8c711fa16cb3b16"
[[package]]
name = "cache-padded"
version = "1.1.1"
@ -988,6 +982,17 @@ dependencies = [
"winapi",
]
[[package]]
name = "pem"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4c220d01f863d13d96ca82359d1e81e64a7c6bf0637bcde7b2349630addf0c6"
dependencies = [
"base64",
"once_cell",
"regex",
]
[[package]]
name = "pest"
version = "2.1.3"
@ -1170,7 +1175,6 @@ dependencies = [
"async-trait",
"bincode",
"byteorder",
"bytes",
"chrono",
"chrono-english",
"clap",
@ -1187,6 +1191,7 @@ dependencies = [
"proptest",
"psutil",
"rand",
"rcgen",
"rustls",
"serde",
"serde_derive",
@ -1272,6 +1277,18 @@ dependencies = [
"rand_core",
]
[[package]]
name = "rcgen"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cb7a2dc0e5307189b6933a61290ff06b65b35bdcaae2b2c50a0c3e355cb118e"
dependencies = [
"chrono",
"pem",
"ring",
"yasna",
]
[[package]]
name = "redox_syscall"
version = "0.1.57"
@ -1289,6 +1306,15 @@ dependencies = [
"rust-argon2",
]
[[package]]
name = "regex"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c"
dependencies = [
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.21"
@ -1852,3 +1878,12 @@ checksum = "39f0c922f1a334134dc2f7a8b67dc5d25f0735263feec974345ff706bcf20b0d"
dependencies = [
"linked-hash-map",
]
[[package]]
name = "yasna"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0de7bff972b4f2a06c85f6d8454b09df153af7e3a4ec2aac81db1b105b684ddb"
dependencies = [
"chrono",
]

View file

@ -28,10 +28,6 @@ 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"
@ -39,9 +35,14 @@ ctrlc = { version = "3", features = ["termination"] }
rand = "^0.7"
strum = "^0.20"
strum_macros = "^0.20"
tempfile = "^3"
handlebars = "3"
bytes = "^0.6"
async-std = { version = "1", features = ["attributes", "std"] }
async-tls = "0.11"
async-trait = "0.1"
rustls = "0.19"
rcgen = "0.8"
byteorder = "^1"
snap = "1"
serde = "^1.0"
@ -50,14 +51,13 @@ serde_json = "^1.0"
serde_yaml = "^0.8"
serde_derive = "^1.0"
log = "0.4"
config = { version = "^0.10", default-features = false, features = ["yaml"] }
log = "0.4"
simplelog = { version = "0.8", default-features = false }
clap = "3.0.0-beta.2"
clap_generate = "3.0.0-beta.2"
crossterm = "^0.18"
comfy-table= "^1"
tempfile = "^3"
[target.'cfg(not(windows))'.dependencies]
users = "^0.11"

View file

@ -8,6 +8,7 @@ use anyhow::Result;
use clap::Clap;
use simplelog::{Config, LevelFilter, SimpleLogger};
use pueue::network::certificate::create_certificates;
use pueue::network::message::Message;
use pueue::network::secret::init_shared_secret;
use pueue::settings::Settings;
@ -60,6 +61,9 @@ async fn main() -> Result<()> {
};
init_directories(&settings.shared.pueue_directory);
if !settings.shared.daemon_key.exists() && !settings.shared.daemon_cert.exists() {
create_certificates(&settings)?;
}
init_shared_secret(&settings.shared.shared_secret_path)?;
let state = State::new(&settings, opt.config.clone());
@ -127,6 +131,17 @@ fn init_directories(pueue_dir: &PathBuf) {
}
}
// Task certs dir
let certs_dir = pueue_dir.join("certs");
if !certs_dir.exists() {
if let Err(error) = create_dir_all(&certs_dir) {
panic!(
"Failed to create certificate directory at {:?} error: {:?}",
certs_dir, error
);
}
}
// Task log dir
let logs_dir = pueue_dir.join("task_logs");
if !logs_dir.exists() {

View file

@ -0,0 +1,52 @@
use std::{fs::File, io::Write, path::PathBuf};
use anyhow::{bail, Context, Result};
use log::info;
use rcgen::generate_simple_self_signed;
use crate::settings::Settings;
/// This the default certificates at the default `pueue_dir/certs` location.
pub fn create_certificates(settings: &Settings) -> Result<()> {
let certs_dir = settings.shared.pueue_directory.join("certs");
let daemon_cert_path = certs_dir.join("daemon.cert");
let daemon_key_path = certs_dir.join("daemon.key");
if daemon_key_path.exists() || daemon_cert_path.exists() {
if !(daemon_key_path.exists() && daemon_cert_path.exists()) {
bail!(
"Not all default certificates exist, some are missing. \
Please fix your cert/key paths.\n \
You can also remove the `$pueue_directory/certs` directory \
and restart the daemon to create new certificates/keys."
);
}
info!("All default keys do exist.");
return Ok(());
}
let subject_alt_names = vec!["pueue.local".to_string(), "localhost".to_string()];
let cert = generate_simple_self_signed(subject_alt_names).unwrap();
// The certificate is now valid for localhost and the domain "hello.world.example"
let ca_cert = cert
.serialize_pem()
.context("Failed to serialize daemon certificate.")?;
write_file(ca_cert, "daemon cert", &daemon_cert_path)?;
let ca_key = cert.serialize_private_key_pem();
write_file(ca_key, "daemon key", &daemon_key_path)?;
Ok(())
}
pub fn write_file(blob: String, name: &str, path: &PathBuf) -> Result<()> {
info!("Generate {}.", name);
let error_message = format!("Cannot write default {}: {:?}", name, path);
let mut file = File::create(path).context(error_message.clone())?;
file.write_all(&blob.into_bytes()).context(error_message)?;
Ok(())
}

View file

@ -1,3 +1,4 @@
pub mod certificate;
pub mod message;
pub mod protocol;
pub mod secret;

View file

@ -3,10 +3,10 @@ use std::io::{BufReader, Cursor};
use std::path::Path;
use std::sync::Arc;
use anyhow::{anyhow, Context, Error, Result};
use anyhow::{anyhow, bail, Context, Error, Result};
use async_tls::{TlsAcceptor, TlsConnector};
use rustls::{
internal::pemfile::{certs, rsa_private_keys},
internal::pemfile::{certs, pkcs8_private_keys, rsa_private_keys},
NoClientAuth,
};
use rustls::{Certificate, ClientConfig, PrivateKey, ServerConfig};
@ -20,7 +20,7 @@ pub async fn get_tls_connector(settings: &Settings) -> Result<TlsConnector> {
let mut config = ClientConfig::new();
// Trust server-certificates signed with our own CA.
let mut ca = load_ca(&settings.shared.ca_cert)?;
let mut ca = load_ca(&settings.shared.daemon_cert)?;
config
.root_store
.add_pem_file(&mut ca)
@ -40,6 +40,13 @@ pub fn get_tls_listener(settings: &Settings) -> Result<TlsAcceptor> {
// Set the server-side key and certificate that should be used for any communication
let certs = load_certs(&settings.shared.daemon_cert)?;
let mut keys = load_keys(&settings.shared.daemon_key)?;
if keys.is_empty() {
bail!(
"Couldn't extract private key from keyfile {:?}",
&settings.shared.daemon_key
);
}
config
// set this server to use one cert together with the loaded private key
.set_single_cert(certs, keys.remove(0))
@ -58,6 +65,15 @@ fn load_certs(path: &Path) -> Result<Vec<Certificate>> {
/// Load the passed keys file
fn load_keys(path: &Path) -> Result<Vec<PrivateKey>> {
let file = File::open(path).context(format!("Cannot open key {:?}", path))?;
// Try to read pkcs8 format first
let keys = pkcs8_private_keys(&mut BufReader::new(&file))
.map_err(|_| anyhow!("Failed to parse daemon key."))?;
if !keys.is_empty() {
return Ok(keys);
}
// Try the normal rsa format afterwards.
rsa_private_keys(&mut BufReader::new(file)).map_err(|_| anyhow!("Failed to parse daemon key."))
}

View file

@ -18,7 +18,6 @@ pub struct Shared {
pub unix_socket_path: PathBuf,
pub port: String,
pub ca_cert: PathBuf,
pub daemon_cert: PathBuf,
pub daemon_key: PathBuf,
pub shared_secret_path: PathBuf,
@ -66,7 +65,6 @@ impl Settings {
config.set_default("shared.port", "6924")?;
config.set_default("shared.tls_enabled", true)?;
config.set_default("shared.ca_cert", pueue_path.clone() + "/certs/ca.cert")?;
config.set_default(
"shared.daemon_key",
pueue_path.clone() + "/certs/daemon.key",