mirror of
https://github.com/htrefil/rkvm.git
synced 2025-01-19 10:26:13 +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",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anyhow"
|
||||||
|
version = "1.0.33"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a1fd36ffbb1fb7c834eac128ea8d0e310c5aeb635548f9d58861e1308d46e71c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arc-swap"
|
name = "arc-swap"
|
||||||
version = "0.4.7"
|
version = "0.4.7"
|
||||||
|
@ -99,6 +105,15 @@ version = "1.0.60"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ef611cc68ff783f18535d77ddd080185275713d852c4f5cbb6122c462a7a825c"
|
checksum = "ef611cc68ff783f18535d77ddd080185275713d852c4f5cbb6122c462a7a825c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "certificate-gen"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"structopt",
|
||||||
|
"tempfile",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cexpr"
|
name = "cexpr"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
[workspace]
|
[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"
|
listen-address = "0.0.0.0:5258"
|
||||||
switch-keys = [29, 56, 111]
|
switch-keys = [29, 56, 111]
|
||||||
identity-path = "identity.p12"
|
identity-path = "identity.p12"
|
||||||
|
# Doesn't have to be set.
|
||||||
identity-password = "123456789"
|
identity-password = "123456789"
|
|
@ -1,13 +1,14 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::Deserialize;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Deserialize)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub listen_address: SocketAddr,
|
pub listen_address: SocketAddr,
|
||||||
pub switch_keys: HashSet<u16>,
|
pub switch_keys: HashSet<u16>,
|
||||||
pub identity_path: PathBuf,
|
pub identity_path: PathBuf,
|
||||||
|
#[serde(default)]
|
||||||
pub identity_password: String,
|
pub identity_password: String,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue