mirror of
https://github.com/htrefil/rkvm.git
synced 2025-01-18 10:26:12 +01:00
Add certificate generation tool, make identity passwords optional
This commit is contained in:
parent
d05d9b7d2a
commit
dfde202a7b
6 changed files with 168 additions and 3 deletions
15
Cargo.lock
generated
15
Cargo.lock
generated
|
@ -18,6 +18,12 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1fd36ffbb1fb7c834eac128ea8d0e310c5aeb635548f9d58861e1308d46e71c"
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
version = "0.4.7"
|
||||
|
@ -99,6 +105,15 @@ version = "1.0.60"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef611cc68ff783f18535d77ddd080185275713d852c4f5cbb6122c462a7a825c"
|
||||
|
||||
[[package]]
|
||||
name = "certificate-gen"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"structopt",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cexpr"
|
||||
version = "0.4.0"
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
[workspace]
|
||||
members = ["client", "server", "input", "net"]
|
||||
members = ["client", "server", "input", "net", "certificate-gen"]
|
12
certificate-gen/Cargo.toml
Normal file
12
certificate-gen/Cargo.toml
Normal file
|
@ -0,0 +1,12 @@
|
|||
[package]
|
||||
name = "certificate-gen"
|
||||
version = "0.1.0"
|
||||
authors = ["htrefil <8711792+htrefil@users.noreply.github.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
structopt = "0.3.20"
|
||||
tempfile = "3.1.0"
|
||||
anyhow = "1.0.33"
|
136
certificate-gen/src/main.rs
Normal file
136
certificate-gen/src/main.rs
Normal file
|
@ -0,0 +1,136 @@
|
|||
use anyhow::{Context, Error};
|
||||
use std::fmt::Write as _;
|
||||
use std::io::Write;
|
||||
use std::net::IpAddr;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{self, Command};
|
||||
use structopt::StructOpt;
|
||||
use tempfile::NamedTempFile;
|
||||
|
||||
fn run(
|
||||
identity_path: &Path,
|
||||
certificate_path: &Path,
|
||||
key_path: &Path,
|
||||
dns_names: &[String],
|
||||
ip_addresses: &[IpAddr],
|
||||
) -> Result<(), Error> {
|
||||
if dns_names.is_empty() && ip_addresses.is_empty() {
|
||||
return Err(anyhow::anyhow!(
|
||||
"No DNS names nor IP addresses were provided"
|
||||
));
|
||||
}
|
||||
|
||||
let mut config = "[req]
|
||||
prompt = no
|
||||
default_bits = 2048
|
||||
distinguished_name = req_distinguished_name
|
||||
req_extensions = req_ext
|
||||
x509_extensions = v3_req
|
||||
[req_distinguished_name]
|
||||
commonName = rkvm
|
||||
countryName = CZ
|
||||
localityName = rkvm
|
||||
organizationName = rkvm
|
||||
organizationalUnitName = IT
|
||||
stateOrProvinceName = rkvm
|
||||
emailAddress = nowhere@example.com
|
||||
[req_ext]
|
||||
subjectAltName = @alt_names
|
||||
[v3_req]
|
||||
subjectAltName = @alt_names
|
||||
[alt_names]"
|
||||
.to_owned();
|
||||
for (i, name) in dns_names.iter().enumerate() {
|
||||
write!(config, "\nDNS.{} = {}", i + 1, name)?;
|
||||
}
|
||||
|
||||
for (i, address) in ip_addresses.iter().enumerate() {
|
||||
write!(config, "\nIP.{} = {}", i + 1, address)?;
|
||||
}
|
||||
|
||||
let mut file = NamedTempFile::new().context("Failed to open config file")?;
|
||||
file.write_all(config.as_bytes())
|
||||
.context("Failed to write to config file")?;
|
||||
|
||||
let code = Command::new("openssl")
|
||||
.arg("req")
|
||||
.arg("-sha256")
|
||||
.arg("-x509")
|
||||
.arg("-nodes")
|
||||
.arg("-days")
|
||||
.arg("365")
|
||||
.arg("-newkey")
|
||||
.arg("rsa:2048")
|
||||
.arg("-keyout")
|
||||
.arg(key_path)
|
||||
.arg("-out")
|
||||
.arg(certificate_path)
|
||||
.arg("-config")
|
||||
.arg(file.path())
|
||||
.status()
|
||||
.context("Failed to launch OpenSSL")?
|
||||
.code();
|
||||
|
||||
if code != Some(0) {
|
||||
return Err(anyhow::anyhow!("OpenSSL exited unsuccessfully"));
|
||||
}
|
||||
|
||||
let code = Command::new("openssl")
|
||||
.arg("pkcs12")
|
||||
.arg("-export")
|
||||
.arg("-out")
|
||||
.arg(identity_path)
|
||||
.arg("-inkey")
|
||||
.arg(key_path)
|
||||
.arg("-in")
|
||||
.arg(certificate_path)
|
||||
.status()
|
||||
.context("Failed to launch OpenSSL")?
|
||||
.code();
|
||||
|
||||
if code != Some(0) {
|
||||
return Err(anyhow::anyhow!("OpenSSL exited unsuccessfully"));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(StructOpt)]
|
||||
#[structopt(
|
||||
name = "rkvm-certificate-gen",
|
||||
about = "A tool to generate certificates to use with rkvm"
|
||||
)]
|
||||
struct Args {
|
||||
#[structopt(help = "Path to output identity file (PKCS12 archive)")]
|
||||
identity_path: PathBuf,
|
||||
#[structopt(help = "Path to output certificate file (PEM file)")]
|
||||
certificate_path: PathBuf,
|
||||
#[structopt(help = "Path to output key file (PEM file)")]
|
||||
key_path: PathBuf,
|
||||
#[structopt(
|
||||
long,
|
||||
short,
|
||||
help = "List of DNS names to be used, can be empty if at least one IP address is provided"
|
||||
)]
|
||||
dns_names: Vec<String>,
|
||||
#[structopt(
|
||||
long,
|
||||
short,
|
||||
help = "List of IP addresses to be used, can be empty if at least one DNS name is provided"
|
||||
)]
|
||||
ip_addresses: Vec<IpAddr>,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = Args::from_args();
|
||||
if let Err(err) = run(
|
||||
&args.identity_path,
|
||||
&args.certificate_path,
|
||||
&args.key_path,
|
||||
&args.dns_names,
|
||||
&args.ip_addresses,
|
||||
) {
|
||||
println!("Error: {}", err);
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
listen-address = "0.0.0.0:5258"
|
||||
switch-keys = [29, 56, 111]
|
||||
identity-path = "identity.p12"
|
||||
# Doesn't have to be set.
|
||||
identity-password = "123456789"
|
|
@ -1,13 +1,14 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
use serde::Deserialize;
|
||||
use std::collections::HashSet;
|
||||
use std::net::SocketAddr;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct Config {
|
||||
pub listen_address: SocketAddr,
|
||||
pub switch_keys: HashSet<u16>,
|
||||
pub identity_path: PathBuf,
|
||||
#[serde(default)]
|
||||
pub identity_password: String,
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue