CA
This commit is contained in:
118
protocol/gurtca/src/main.rs
Normal file
118
protocol/gurtca/src/main.rs
Normal file
@@ -0,0 +1,118 @@
|
||||
use clap::{Parser, Subcommand};
|
||||
use anyhow::Result;
|
||||
|
||||
mod challenges;
|
||||
mod crypto;
|
||||
mod client;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(name = "gurtca")]
|
||||
#[command(about = "Gurted Certificate Authority CLI - Get TLS certificates for your domains")]
|
||||
struct Cli {
|
||||
#[command(subcommand)]
|
||||
command: Commands,
|
||||
|
||||
#[arg(long, default_value = "gurt://localhost:8877")]
|
||||
ca_url: String,
|
||||
|
||||
#[arg(long, help = "Skip TLS certificate verification (insecure, for bootstrapping only)")]
|
||||
insecure: bool,
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
enum Commands {
|
||||
Request {
|
||||
domain: String,
|
||||
|
||||
#[arg(long, default_value = "./certs")]
|
||||
output: String,
|
||||
},
|
||||
GetCa {
|
||||
#[arg(long, default_value = "./ca.crt")]
|
||||
output: String,
|
||||
},
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
let cli = Cli::parse();
|
||||
|
||||
let client = if cli.insecure {
|
||||
client::GurtCAClient::new_insecure(cli.ca_url)?
|
||||
} else {
|
||||
client::GurtCAClient::new_with_ca_discovery(cli.ca_url).await?
|
||||
};
|
||||
|
||||
match cli.command {
|
||||
Commands::Request { domain, output } => {
|
||||
println!("🔐 Requesting certificate for: {}", domain);
|
||||
request_certificate(&client, &domain, &output).await?;
|
||||
},
|
||||
Commands::GetCa { output } => {
|
||||
println!("📋 Fetching CA certificate from server...");
|
||||
get_ca_certificate(&client, &output).await?;
|
||||
},
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn request_certificate(
|
||||
client: &client::GurtCAClient,
|
||||
domain: &str,
|
||||
output_dir: &str
|
||||
) -> Result<()> {
|
||||
println!("🔍 Verifying domain exists...");
|
||||
if !client.verify_domain_exists(domain).await? {
|
||||
anyhow::bail!("❌ Domain does not exist or is not approved: {}", domain);
|
||||
}
|
||||
|
||||
println!("🔑 Generating key pair...");
|
||||
let (private_key, csr) = crypto::generate_key_and_csr(domain)?;
|
||||
|
||||
println!("📝 Submitting certificate request...");
|
||||
let challenge = client.request_certificate(domain, &csr).await?;
|
||||
|
||||
println!("🧩 Completing DNS challenge...");
|
||||
challenges::complete_dns_challenge(&challenge, client).await?;
|
||||
|
||||
println!("⏳ Waiting for certificate issuance...");
|
||||
let certificate = client.poll_certificate(&challenge.token).await?;
|
||||
|
||||
println!("💾 Saving certificate files...");
|
||||
std::fs::create_dir_all(output_dir)?;
|
||||
|
||||
std::fs::write(
|
||||
format!("{}/{}.crt", output_dir, domain),
|
||||
certificate.cert_pem
|
||||
)?;
|
||||
|
||||
std::fs::write(
|
||||
format!("{}/{}.key", output_dir, domain),
|
||||
private_key
|
||||
)?;
|
||||
|
||||
println!("✅ Certificate successfully issued for: {}", domain);
|
||||
println!("📁 Files saved to: {}", output_dir);
|
||||
println!(" - Certificate: {}/{}.crt", output_dir, domain);
|
||||
println!(" - Private Key: {}/{}.key", output_dir, domain);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_ca_certificate(
|
||||
client: &client::GurtCAClient,
|
||||
output_path: &str
|
||||
) -> Result<()> {
|
||||
let ca_cert = client.fetch_ca_certificate().await?;
|
||||
|
||||
std::fs::write(output_path, &ca_cert)?;
|
||||
|
||||
println!("✅ CA certificate saved to: {}", output_path);
|
||||
println!("💡 To trust this CA system-wide:");
|
||||
println!(" Windows: Import {} into 'Trusted Root Certification Authorities'", output_path);
|
||||
println!(" macOS: sudo security add-trusted-cert -d -r trustRoot -k /System/Library/Keychains/SystemRootCertificates.keychain {}", output_path);
|
||||
println!(" Linux: Copy {} to /usr/local/share/ca-certificates/ and run sudo update-ca-certificates", output_path);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user