certs: refactor certificate logic into module
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
use std::fs;
|
||||
use std::io::Write;
|
||||
|
||||
use anyhow::Result;
|
||||
use openssl::hash::MessageDigest;
|
||||
use openssl::pkey::{PKey, Private};
|
||||
use openssl::rsa::Rsa;
|
||||
use openssl::x509::X509;
|
||||
|
||||
pub fn get_cert_and_key() -> Result<(X509, PKey<Private>)> {
|
||||
if let Ok((cert, key)) = load_cert_and_key_from_disk() {
|
||||
Ok((cert, key))
|
||||
} else {
|
||||
generate_cert_and_key()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_cert_and_key_from_disk() -> Result<(X509, PKey<Private>)> {
|
||||
let project_dirs =
|
||||
directories::ProjectDirs::from("xyz", "ohea", "gamestream-webtransport-proxy")
|
||||
.ok_or(anyhow::anyhow!("Could not get project dirs"))?;
|
||||
let data_dir = project_dirs.data_dir();
|
||||
let cert_dir = data_dir.join("certs");
|
||||
fs::create_dir_all(&cert_dir)?;
|
||||
|
||||
let cert_filepath = cert_dir.join("cert");
|
||||
let key_filepath = cert_dir.join("key");
|
||||
|
||||
let cert_bytes = fs::read(cert_filepath)?;
|
||||
let key_bytes = fs::read(key_filepath)?;
|
||||
|
||||
let cert = X509::from_pem(&cert_bytes)?;
|
||||
let key = PKey::<Private>::private_key_from_pem(&key_bytes)?;
|
||||
|
||||
Ok((cert, key))
|
||||
}
|
||||
|
||||
pub fn generate_cert_and_key() -> Result<(X509, PKey<Private>)> {
|
||||
let rsa = Rsa::generate(2048)?;
|
||||
let key = PKey::from_rsa(rsa)?;
|
||||
|
||||
let mut cert_builder = X509::builder()?;
|
||||
|
||||
let serial_number_u32 = openssl::bn::BigNum::from_u32(0)?;
|
||||
let serial_number = openssl::asn1::Asn1Integer::from_bn(&serial_number_u32)?;
|
||||
|
||||
let now_unix = std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.expect("Time went backwards")
|
||||
.as_secs()
|
||||
- 1000000;
|
||||
let now = openssl::asn1::Asn1Time::from_unix(now_unix as i64)?;
|
||||
let ten_years_from_now = openssl::asn1::Asn1Time::days_from_now(365 * 10)?;
|
||||
|
||||
let mut x509_name_builder = openssl::x509::X509NameBuilder::new()?;
|
||||
x509_name_builder.append_entry_by_text("CN", "NVIDIA GameStream Client")?;
|
||||
let x509_name = x509_name_builder.build();
|
||||
|
||||
cert_builder.set_version(2)?;
|
||||
cert_builder.set_not_before(&now)?;
|
||||
cert_builder.set_not_after(&ten_years_from_now)?;
|
||||
cert_builder.set_pubkey(&key)?;
|
||||
cert_builder.set_serial_number(&serial_number)?;
|
||||
cert_builder.set_issuer_name(&x509_name)?;
|
||||
cert_builder.set_subject_name(&x509_name)?;
|
||||
cert_builder.sign(&key, MessageDigest::sha256())?;
|
||||
let cert = cert_builder.build();
|
||||
|
||||
save_cert_and_key_to_disk(&cert, &key)?;
|
||||
|
||||
Ok((cert, key))
|
||||
}
|
||||
|
||||
pub fn save_cert_and_key_to_disk(cert: &X509, key: &PKey<Private>) -> Result<()> {
|
||||
let project_dirs =
|
||||
directories::ProjectDirs::from("xyz", "ohea", "gamestream-webtransport-proxy")
|
||||
.ok_or(anyhow::anyhow!("Could not get project dirs"))?;
|
||||
let data_dir = project_dirs.data_dir();
|
||||
let cert_dir = data_dir.join("certs");
|
||||
fs::create_dir_all(&cert_dir)?;
|
||||
|
||||
let cert_filepath = cert_dir.join("cert");
|
||||
let key_filepath = cert_dir.join("key");
|
||||
|
||||
let mut cert_file_builder = std::fs::OpenOptions::new();
|
||||
cert_file_builder.create(true);
|
||||
cert_file_builder.truncate(true);
|
||||
cert_file_builder.write(true);
|
||||
|
||||
let mut key_file_builder = std::fs::OpenOptions::new();
|
||||
key_file_builder.create(true);
|
||||
key_file_builder.truncate(true);
|
||||
key_file_builder.write(true);
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
{
|
||||
use std::os::unix::fs::OpenOptionsExt;
|
||||
|
||||
key_file_builder.mode(0o600);
|
||||
cert_file_builder.mode(0o600);
|
||||
}
|
||||
|
||||
let mut cert_file = cert_file_builder.open(&cert_filepath)?;
|
||||
let mut key_file = key_file_builder.open(&key_filepath)?;
|
||||
|
||||
cert_file.write_all(&cert.to_pem()?)?;
|
||||
key_file.write_all(&key.private_key_to_pem_pkcs8()?)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn http_client_with_identity() {}
|
||||
@@ -7,6 +7,7 @@ use moonlight_common_c_sys::{
|
||||
STREAM_CFG_LOCAL, VIDEO_FORMAT_H264,
|
||||
};
|
||||
|
||||
mod certs;
|
||||
mod pair;
|
||||
|
||||
fn get_server_info() -> _SERVER_INFORMATION {
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
use anyhow::Result;
|
||||
use openssl::hash::MessageDigest;
|
||||
use openssl::pkey::{PKey, Private};
|
||||
use openssl::rsa::Rsa;
|
||||
use openssl::sha::Sha256;
|
||||
use openssl::x509::X509;
|
||||
use rand::Rng;
|
||||
use salvo::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fs;
|
||||
use std::io::Write;
|
||||
|
||||
#[derive(Debug, Deserialize, ToSchema)]
|
||||
struct PostPairParams {
|
||||
@@ -55,82 +51,6 @@ struct ServerPairingSecret {
|
||||
signature: Vec<u8>,
|
||||
}
|
||||
|
||||
fn get_cert_and_private_key() -> Result<(X509, PKey<Private>)> {
|
||||
let rsa = Rsa::generate(2048)?;
|
||||
let key_pair = PKey::from_rsa(rsa)?;
|
||||
|
||||
let mut cert_builder = X509::builder()?;
|
||||
|
||||
let serial_number_u32 = openssl::bn::BigNum::from_u32(0)?;
|
||||
let serial_number = openssl::asn1::Asn1Integer::from_bn(&serial_number_u32)?;
|
||||
|
||||
let now_unix = std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.expect("Time went backwards")
|
||||
.as_secs()
|
||||
- 1000000;
|
||||
let now = openssl::asn1::Asn1Time::from_unix(now_unix as i64)?;
|
||||
let ten_years_from_now = openssl::asn1::Asn1Time::days_from_now(365 * 10)?;
|
||||
|
||||
let mut x509_name_builder = openssl::x509::X509NameBuilder::new()?;
|
||||
x509_name_builder.append_entry_by_text("CN", "NVIDIA GameStream Client")?;
|
||||
let x509_name = x509_name_builder.build();
|
||||
|
||||
cert_builder.set_version(2)?;
|
||||
cert_builder.set_not_before(&now)?;
|
||||
cert_builder.set_not_after(&ten_years_from_now)?;
|
||||
cert_builder.set_pubkey(&key_pair)?;
|
||||
cert_builder.set_serial_number(&serial_number)?;
|
||||
cert_builder.set_issuer_name(&x509_name)?;
|
||||
cert_builder.set_subject_name(&x509_name)?;
|
||||
cert_builder.sign(&key_pair, MessageDigest::sha256())?;
|
||||
let cert = cert_builder.build();
|
||||
Ok((cert, key_pair))
|
||||
}
|
||||
|
||||
fn save_cert_and_key_to_disk(
|
||||
cert: X509,
|
||||
key: PKey<Private>,
|
||||
host: &String,
|
||||
port: u16,
|
||||
) -> Result<()> {
|
||||
let project_dirs =
|
||||
directories::ProjectDirs::from("xyz", "ohea", "gamestream-webtransport-proxy")
|
||||
.ok_or(anyhow::anyhow!("Could not get project dirs"))?;
|
||||
let data_dir = project_dirs.data_dir();
|
||||
let cert_dir = data_dir.join("certs");
|
||||
fs::create_dir_all(&cert_dir)?;
|
||||
|
||||
let cert_filepath = cert_dir.join(format!("{host}_{port}_cert"));
|
||||
let key_filepath = cert_dir.join(format!("{host}_{port}_key"));
|
||||
|
||||
let mut cert_file_builder = std::fs::OpenOptions::new();
|
||||
cert_file_builder.create(true);
|
||||
cert_file_builder.truncate(true);
|
||||
cert_file_builder.write(true);
|
||||
|
||||
let mut key_file_builder = std::fs::OpenOptions::new();
|
||||
key_file_builder.create(true);
|
||||
key_file_builder.truncate(true);
|
||||
key_file_builder.write(true);
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
{
|
||||
use std::os::unix::fs::OpenOptionsExt;
|
||||
|
||||
key_file_builder.mode(0o600);
|
||||
cert_file_builder.mode(0o600);
|
||||
}
|
||||
|
||||
let mut cert_file = cert_file_builder.open(&cert_filepath)?;
|
||||
let mut key_file = key_file_builder.open(&key_filepath)?;
|
||||
|
||||
cert_file.write_all(&cert.to_pem()?)?;
|
||||
key_file.write_all(&key.private_key_to_pem_pkcs8()?)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_url(base_url: &mut url_constructor::UrlConstructor) -> Result<String> {
|
||||
let mut uuidv2 = [0u8; 16];
|
||||
openssl::rand::rand_bytes(&mut uuidv2)?;
|
||||
@@ -425,8 +345,8 @@ pub async fn post_pair(body: salvo::oapi::extract::JsonBody<PostPairParams>) ->
|
||||
return StatusCode::INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
// Generate certificates
|
||||
let (cert, private_key) = match get_cert_and_private_key() {
|
||||
// Get or generate cert / private key
|
||||
let (cert, private_key) = match crate::certs::get_cert_and_key() {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
println!("Could not generate certs: {e}");
|
||||
@@ -496,11 +416,5 @@ pub async fn post_pair(body: salvo::oapi::extract::JsonBody<PostPairParams>) ->
|
||||
println!("Paired with server {host}:{port} successfully!");
|
||||
}
|
||||
|
||||
// Save certificate to disk so it can be used for subsequent connections
|
||||
if let Err(e) = save_cert_and_key_to_disk(cert, private_key, ¶ms.host, params.port) {
|
||||
println!("Could not save cert and key to disk");
|
||||
return StatusCode::INTERNAL_SERVER_ERROR;
|
||||
};
|
||||
|
||||
StatusCode::OK
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user