Add creating an introducer from a files

- Introducers can now be created by specifying a file. The certificate
  gets imported and declared as an introducer for the passed domains.
- Add some checks, so that the imported certificate can actually be used
  as an introducer (certificate is alive, not revoked, has certification
  capabilities)
This commit is contained in:
Malte Meiboom
2026-05-13 11:49:40 +02:00
parent 0df4c723d9
commit 4ddc3db6c0
5 changed files with 61 additions and 18 deletions
+35 -14
View File
@@ -3,10 +3,14 @@
use anyhow::Result;
use sequoia_cert_store::Store;
use sequoia_openpgp::cert::ValidCert;
use sequoia_openpgp::cert;
use sequoia_openpgp::parse::Parse;
use sequoia_openpgp::{Fingerprint, KeyHandle};
use sequoia_openpgp::types::RevocationStatus;
use crate::cli::cli_args::IntroducerAddCommand;
use crate::commands::CommandError;
use crate::common::crypto;
use crate::config::HuskConfigContainer;
use crate::types::husk_context::HuskContext;
use crate::types::introducer::Introducer;
@@ -14,29 +18,46 @@ use crate::types::introducer::Introducer;
pub async fn dispatch(cmd: IntroducerAddCommand, config: HuskConfigContainer) -> Result<()> {
println!("add");
println!(" {:?}", cmd.cert);
println!(" {:?}", cmd.cert_file);
println!(" {:?}", cmd.domains);
let context = HuskContext::new(&config.into())?;
let policy = &context.policy;
let cert_store = &context.cert_store;
// Get the certificate
let fpr = Fingerprint::from_hex(&cmd.cert)?;
let certs = cert_store.lookup_by_cert(&KeyHandle::try_from(&fpr)?)
.map_err(|_| CommandError::CertNotFound(fpr.clone()))?;
if let Some(cert_file) = cmd.cert_file {
let c = cert::Cert::from_file(cert_file)?;
let vc = c.with_policy(policy, None)?;
let certs: Vec<ValidCert> = certs.iter()
.filter_map(|c|
c.with_policy(policy, None).ok()
)
.collect();
// guards
if vc.alive().is_err() {
return Err(CommandError::CertNotAlive(vc.fingerprint()).into());
}
if matches!(vc.revocation_status(), RevocationStatus::Revoked(_)) {
return Err(CommandError::CertRevoked(vc.fingerprint()).into());
}
if !crypto::has_certification_capability(&vc) {
return Err(CommandError::CertNotUsable(vc.fingerprint()).into());
}
if let Some(cert) = certs.first() {
Introducer::create(&context, cert, cmd.domains)?;
} else {
return Err(CommandError::CertNotUsable(fpr).into());
Introducer::create(&context, &vc, cmd.domains)?;
} else if let Some(cert) = cmd.cert {
let fpr = Fingerprint::from_hex(cert.as_str())?;
let certs = cert_store.lookup_by_cert(&KeyHandle::try_from(&fpr)?)
.map_err(|_| CommandError::CertNotFound(fpr.clone()))?;
let certs: Vec<ValidCert> = certs.iter()
.filter_map(|c|
c.with_policy(policy, None).ok()
)
.collect();
if let Some(cert) = certs.first() {
Introducer::create(&context, &cert, cmd.domains)?;
} else {
return Err(CommandError::CertNotUsable(fpr).into());
}
}
Ok(())
}