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:
+12
-3
@@ -80,9 +80,18 @@ pub enum IntroducerSubcommand {
|
|||||||
pub struct IntroducerAddCommand {
|
pub struct IntroducerAddCommand {
|
||||||
#[clap(
|
#[clap(
|
||||||
long = "cert",
|
long = "cert",
|
||||||
help = "Certificate to declare as introducer."
|
help = "Certificate to declare as introducer.",
|
||||||
|
conflicts_with = "cert_file"
|
||||||
)]
|
)]
|
||||||
pub cert: String,
|
pub cert: Option<String>,
|
||||||
|
|
||||||
|
#[clap(
|
||||||
|
long = "cert-file",
|
||||||
|
help = "Import certificate from CERT_FILE and declare it as introducer.",
|
||||||
|
value_name = "CERT_FILE",
|
||||||
|
conflicts_with = "cert"
|
||||||
|
)]
|
||||||
|
pub cert_file: Option<String>,
|
||||||
|
|
||||||
#[clap(
|
#[clap(
|
||||||
long = "domains",
|
long = "domains",
|
||||||
@@ -146,7 +155,7 @@ pub struct LocalAddCommand {
|
|||||||
long = "cert",
|
long = "cert",
|
||||||
help = "Certificate to add."
|
help = "Certificate to add."
|
||||||
)]
|
)]
|
||||||
pub cert: String,
|
pub cert_file: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
|
|||||||
@@ -16,6 +16,10 @@ pub enum CommandError {
|
|||||||
CertNotFound(Fingerprint),
|
CertNotFound(Fingerprint),
|
||||||
#[error("Certificate not usable: {0}")]
|
#[error("Certificate not usable: {0}")]
|
||||||
CertNotUsable(Fingerprint),
|
CertNotUsable(Fingerprint),
|
||||||
|
#[error("Certificate {0} is not alive (is expired or created in the future)")]
|
||||||
|
CertNotAlive(Fingerprint),
|
||||||
|
#[error("Certificate is revoked: {0}")]
|
||||||
|
CertRevoked(Fingerprint),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn dispatch(cli: CliArgs, config: HuskConfigContainer) -> Result<()> {
|
pub async fn dispatch(cli: CliArgs, config: HuskConfigContainer) -> Result<()> {
|
||||||
|
|||||||
@@ -3,10 +3,14 @@
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use sequoia_cert_store::Store;
|
use sequoia_cert_store::Store;
|
||||||
use sequoia_openpgp::cert::ValidCert;
|
use sequoia_openpgp::cert::ValidCert;
|
||||||
|
use sequoia_openpgp::cert;
|
||||||
|
use sequoia_openpgp::parse::Parse;
|
||||||
use sequoia_openpgp::{Fingerprint, KeyHandle};
|
use sequoia_openpgp::{Fingerprint, KeyHandle};
|
||||||
|
use sequoia_openpgp::types::RevocationStatus;
|
||||||
|
|
||||||
use crate::cli::cli_args::IntroducerAddCommand;
|
use crate::cli::cli_args::IntroducerAddCommand;
|
||||||
use crate::commands::CommandError;
|
use crate::commands::CommandError;
|
||||||
|
use crate::common::crypto;
|
||||||
use crate::config::HuskConfigContainer;
|
use crate::config::HuskConfigContainer;
|
||||||
use crate::types::husk_context::HuskContext;
|
use crate::types::husk_context::HuskContext;
|
||||||
use crate::types::introducer::Introducer;
|
use crate::types::introducer::Introducer;
|
||||||
@@ -14,29 +18,46 @@ use crate::types::introducer::Introducer;
|
|||||||
pub async fn dispatch(cmd: IntroducerAddCommand, config: HuskConfigContainer) -> Result<()> {
|
pub async fn dispatch(cmd: IntroducerAddCommand, config: HuskConfigContainer) -> Result<()> {
|
||||||
println!("add");
|
println!("add");
|
||||||
println!(" {:?}", cmd.cert);
|
println!(" {:?}", cmd.cert);
|
||||||
|
println!(" {:?}", cmd.cert_file);
|
||||||
println!(" {:?}", cmd.domains);
|
println!(" {:?}", cmd.domains);
|
||||||
|
|
||||||
let context = HuskContext::new(&config.into())?;
|
let context = HuskContext::new(&config.into())?;
|
||||||
let policy = &context.policy;
|
let policy = &context.policy;
|
||||||
let cert_store = &context.cert_store;
|
let cert_store = &context.cert_store;
|
||||||
|
|
||||||
// Get the certificate
|
if let Some(cert_file) = cmd.cert_file {
|
||||||
let fpr = Fingerprint::from_hex(&cmd.cert)?;
|
let c = cert::Cert::from_file(cert_file)?;
|
||||||
let certs = cert_store.lookup_by_cert(&KeyHandle::try_from(&fpr)?)
|
let vc = c.with_policy(policy, None)?;
|
||||||
.map_err(|_| CommandError::CertNotFound(fpr.clone()))?;
|
|
||||||
|
|
||||||
let certs: Vec<ValidCert> = certs.iter()
|
// guards
|
||||||
.filter_map(|c|
|
if vc.alive().is_err() {
|
||||||
c.with_policy(policy, None).ok()
|
return Err(CommandError::CertNotAlive(vc.fingerprint()).into());
|
||||||
)
|
}
|
||||||
.collect();
|
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, &vc, cmd.domains)?;
|
||||||
Introducer::create(&context, cert, cmd.domains)?;
|
} else if let Some(cert) = cmd.cert {
|
||||||
} else {
|
let fpr = Fingerprint::from_hex(cert.as_str())?;
|
||||||
return Err(CommandError::CertNotUsable(fpr).into());
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use crate::config::HuskConfigContainer;
|
|||||||
|
|
||||||
pub async fn dispatch(cmd: LocalAddCommand, _config: &HuskConfigContainer) -> Result<()> {
|
pub async fn dispatch(cmd: LocalAddCommand, _config: &HuskConfigContainer) -> Result<()> {
|
||||||
println!("add");
|
println!("add");
|
||||||
println!(" {:?}", cmd.cert);
|
println!(" {:?}", cmd.cert_file);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -472,6 +472,15 @@ pub fn authenticate(context: &HuskContext, cert: &ValidCert, activate: bool, dom
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn has_certification_capability(cert: &ValidCert) -> bool {
|
||||||
|
cert.keys()
|
||||||
|
.for_certification()
|
||||||
|
.alive()
|
||||||
|
.supported()
|
||||||
|
.revoked(false)
|
||||||
|
.count() > 0
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod tests {
|
pub mod tests {
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user