Files
tkmind_go/crates/goose-server/src/tls.rs
T
2026-02-25 19:38:57 +00:00

53 lines
1.6 KiB
Rust

use anyhow::Result;
use aws_lc_rs::digest;
use axum_server::tls_rustls::RustlsConfig;
use rcgen::{CertificateParams, DnType, KeyPair, SanType};
pub struct TlsSetup {
pub config: RustlsConfig,
pub fingerprint: String,
}
/// Generate a self-signed TLS certificate for localhost (127.0.0.1) and
/// return a [`TlsSetup`] containing the rustls config and the SHA-256
/// fingerprint of the generated certificate (colon-separated hex).
///
/// The fingerprint is printed to stdout so the parent process (e.g. Electron)
/// can pin it and reject connections from any other certificate.
pub async fn self_signed_config() -> Result<TlsSetup> {
let _ = rustls::crypto::aws_lc_rs::default_provider().install_default();
let mut params = CertificateParams::default();
params
.distinguished_name
.push(DnType::CommonName, "goosed localhost");
params.subject_alt_names = vec![
SanType::IpAddress(std::net::IpAddr::V4(std::net::Ipv4Addr::LOCALHOST)),
SanType::DnsName("localhost".try_into()?),
];
let key_pair = KeyPair::generate()?;
let cert = params.self_signed(&key_pair)?;
let cert_der = cert.der();
let sha256 = digest::digest(&digest::SHA256, cert_der);
let fingerprint = sha256
.as_ref()
.iter()
.map(|b| format!("{b:02X}"))
.collect::<Vec<_>>()
.join(":");
println!("GOOSED_CERT_FINGERPRINT={fingerprint}");
let cert_pem = cert.pem();
let key_pem = key_pair.serialize_pem();
let config = RustlsConfig::from_pem(cert_pem.into_bytes(), key_pem.into_bytes()).await?;
Ok(TlsSetup {
config,
fingerprint,
})
}