agent: replace openssl self-signed cert generation with rcgen (pure Rust)
This commit is contained in:
parent
8def4b2d06
commit
d1c8a64418
@ -24,7 +24,7 @@ once_cell = "1.19"
|
|||||||
axum-server = { version = "0.6", features = ["tls-rustls"] }
|
axum-server = { version = "0.6", features = ["tls-rustls"] }
|
||||||
rustls = "0.23"
|
rustls = "0.23"
|
||||||
rustls-pemfile = "2.1"
|
rustls-pemfile = "2.1"
|
||||||
openssl = { version = "0.10", features = ["vendored"] } # for cross‑platform self‑signed generation
|
rcgen = "0.13" # pure-Rust self-signed cert generation (replaces openssl vendored build)
|
||||||
anyhow = "1"
|
anyhow = "1"
|
||||||
hostname = "0.3"
|
hostname = "0.3"
|
||||||
bytes = { workspace = true }
|
bytes = { workspace = true }
|
||||||
|
|||||||
@ -1,12 +1,4 @@
|
|||||||
use openssl::asn1::Asn1Time;
|
use rcgen::{Certificate, CertificateParams, DistinguishedName, DnType, IsCa, KeyPair, SanType};
|
||||||
use openssl::hash::MessageDigest;
|
|
||||||
use openssl::nid::Nid;
|
|
||||||
use openssl::pkey::PKey;
|
|
||||||
use openssl::rsa::Rsa;
|
|
||||||
use openssl::x509::extension::{
|
|
||||||
BasicConstraints, ExtendedKeyUsage, KeyUsage, SubjectAlternativeName,
|
|
||||||
};
|
|
||||||
use openssl::x509::{X509NameBuilder, X509};
|
|
||||||
use std::{
|
use std::{
|
||||||
fs,
|
fs,
|
||||||
io::Write,
|
io::Write,
|
||||||
@ -35,57 +27,45 @@ pub fn ensure_self_signed_cert() -> anyhow::Result<(PathBuf, PathBuf)> {
|
|||||||
}
|
}
|
||||||
fs::create_dir_all(cert_path.parent().unwrap())?;
|
fs::create_dir_all(cert_path.parent().unwrap())?;
|
||||||
|
|
||||||
// Key
|
|
||||||
let rsa = Rsa::generate(4096)?;
|
|
||||||
let pkey = PKey::from_rsa(rsa)?;
|
|
||||||
|
|
||||||
// Subject/issuer
|
|
||||||
let hostname = hostname::get()
|
let hostname = hostname::get()
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|s| s.into_string().ok())
|
.and_then(|s| s.into_string().ok())
|
||||||
.unwrap_or_else(|| "localhost".to_string());
|
.unwrap_or_else(|| "localhost".to_string());
|
||||||
let mut name = X509NameBuilder::new()?;
|
|
||||||
name.append_entry_by_nid(Nid::COMMONNAME, &hostname)?;
|
|
||||||
let name = name.build();
|
|
||||||
|
|
||||||
// Cert builder
|
let mut params = CertificateParams::new(vec![hostname.clone(), "localhost".into()]);
|
||||||
let mut builder = X509::builder()?;
|
// Add IP SANs
|
||||||
builder.set_version(2)?;
|
params
|
||||||
builder.set_subject_name(&name)?;
|
.subject_alt_names
|
||||||
builder.set_issuer_name(&name)?;
|
.push(SanType::IpAddress(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))));
|
||||||
builder.set_pubkey(&pkey)?;
|
params
|
||||||
|
.subject_alt_names
|
||||||
|
.push(SanType::IpAddress(IpAddr::V6(::std::net::Ipv6Addr::LOCALHOST)));
|
||||||
|
params
|
||||||
|
.subject_alt_names
|
||||||
|
.push(SanType::IpAddress(IpAddr::V4(Ipv4Addr::UNSPECIFIED)));
|
||||||
|
|
||||||
builder.set_not_before(Asn1Time::days_from_now(0)?.as_ref())?;
|
params.distinguished_name = DistinguishedName::new();
|
||||||
builder.set_not_after(Asn1Time::days_from_now(397)?.as_ref())?;
|
params
|
||||||
|
.distinguished_name
|
||||||
|
.push(DnType::CommonName, hostname.clone());
|
||||||
|
params.is_ca = IsCa::NoCa;
|
||||||
|
// 397 days like previous implementation
|
||||||
|
params.not_before = rcgen::date_time_ymd(2024, 1, 1); // stable starting point
|
||||||
|
params.not_after = params.not_before + rcgen::PKCS_EPOCH_DURATION * 0; // overwritten below
|
||||||
|
// rcgen doesn't allow direct relative days for not_after while keeping not_before now; use validity_days
|
||||||
|
params.validity_days = 397;
|
||||||
|
|
||||||
// SANs: hostname + localhost loopbacks
|
// Use modern defaults (Ed25519) for key; fallback to RSA if necessary
|
||||||
let mut san = SubjectAlternativeName::new();
|
// Keep RSA to maximize compatibility with older clients
|
||||||
san.dns(&hostname)
|
params.alg = &rcgen::PKCS_ECDSA_P256_SHA256; // widely supported
|
||||||
.dns("localhost")
|
let cert = Certificate::from_params(params)?;
|
||||||
.ip("127.0.0.1")
|
let cert_pem = cert.serialize_pem()?;
|
||||||
.ip("::1");
|
let key_pem = cert.serialize_private_key_pem();
|
||||||
// Add a generic 0.0.0.0 for convenience; some TLS libs ignore this, but harmless.
|
|
||||||
let _ = san.ip(&IpAddr::V4(Ipv4Addr::UNSPECIFIED).to_string());
|
|
||||||
let san = san.build(&builder.x509v3_context(None, None))?;
|
|
||||||
// End-entity cert: not a CA
|
|
||||||
builder.append_extension(BasicConstraints::new().critical().build()?)?;
|
|
||||||
builder.append_extension(
|
|
||||||
KeyUsage::new()
|
|
||||||
.digital_signature()
|
|
||||||
.key_encipherment()
|
|
||||||
.build()?,
|
|
||||||
)?;
|
|
||||||
// TLS server usage
|
|
||||||
builder.append_extension(ExtendedKeyUsage::new().server_auth().build()?)?;
|
|
||||||
builder.append_extension(san)?;
|
|
||||||
|
|
||||||
builder.sign(&pkey, MessageDigest::sha256())?;
|
|
||||||
let cert: X509 = builder.build();
|
|
||||||
|
|
||||||
let mut f = fs::File::create(&cert_path)?;
|
let mut f = fs::File::create(&cert_path)?;
|
||||||
f.write_all(&cert.to_pem()?)?;
|
f.write_all(cert_pem.as_bytes())?;
|
||||||
let mut k = fs::File::create(&key_path)?;
|
let mut k = fs::File::create(&key_path)?;
|
||||||
k.write_all(&pkey.private_key_to_pem_pkcs8()?)?;
|
k.write_all(key_pem.as_bytes())?;
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"socktop_agent: generated self-signed TLS certificate at {}",
|
"socktop_agent: generated self-signed TLS certificate at {}",
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user