Add signkey create

- Add a CLI command for creating a new signing key.
This commit is contained in:
Malte Meiboom
2026-06-19 12:27:43 +02:00
parent e47b1b837c
commit 7688e6c5a2
5 changed files with 113 additions and 4 deletions
+29 -3
View File
@@ -30,9 +30,7 @@ if [ -f /var/mail/juliette ] ; then
if [ "$SIGN_FPR" != "$FOUND_FPR" ] ; then
echo "Found wrong fingerprint '$FOUND_FPR' - expected '$SIGN_FPR'"
RESULT_CODE=1
else
RESULT_CODE=0
exit 1
fi
else
echo "no encryption detected"
@@ -43,3 +41,31 @@ else
exit 1
fi
echo "set new signing key"
SIGN_FPR=$($HUSK_BIN --config config/config.toml signkey create | cut -d ':' -f 2 | tr -d ' ')
echo "new signing key $SIGN_FPR"
# remove old mail
rm /var/mail/juliette
echo "send mail to juliette@example.com"
send_test_mail juliette@example.com
if [ -f /var/mail/juliette ] ; then
if grep -q "BEGIN PGP MESSAGE" /var/mail/juliette ; then
FOUND_FPR=$(sq packet dump /var/mail/juliette | grep "Issuer Fingerprint:" | cut -d ':' -f 2 | tr -d ' ')
if [ "$SIGN_FPR" != "$FOUND_FPR" ] ; then
echo "Found wrong fingerprint '$FOUND_FPR' - expected '$SIGN_FPR'"
exit 1
fi
else
echo "no encryption detected"
exit 1
fi
else
echo "no mail detected"
exit 1
fi
+18 -1
View File
@@ -18,7 +18,7 @@ pub struct CliArgs {
#[clap(
long,
global = true,
help = "Certification store (SEQUOIA_HOME).",
help = "Certificate store (SEQUOIA_HOME).",
)]
pub home: Option<String>,
@@ -207,6 +207,7 @@ pub struct SignkeyCommand {
#[derive(Debug, Subcommand)]
pub enum SignkeySubcommand {
Set(SignkeySetCommand),
Create(SignkeyCreateCommand),
#[clap(
about = "Show the fingerprint of the signing key."
)]
@@ -239,3 +240,19 @@ pub struct SignkeySetCommand {
pub cert: Option<String>,
}
#[derive(Parser, Debug)]
#[clap(
about = "Create a new signing key.",
)]
pub struct SignkeyCreateCommand {
#[clap(
long,
help = "Set the userid of the new key.",
value_name = "USERID",
default_value = "Husk signing key",
)]
pub userid: String,
}
+4
View File
@@ -9,12 +9,16 @@ use crate::config::HuskConfigContainer;
use crate::types::husk_context::HuskContext;
pub mod set;
pub mod create;
pub async fn dispatch(cmd: SignkeyCommand, config: HuskConfigContainer) -> Result<()> {
match cmd.subcommand {
SignkeySubcommand::Set(set_cmd) => {
set::dispatch(set_cmd, config).await?;
},
SignkeySubcommand::Create(create_cmd) => {
create::dispatch(create_cmd, config).await?;
}
SignkeySubcommand::Show => {
let context = HuskContext::new(&config.into())?;
if let Some(key) = context.signing_key {
+35
View File
@@ -0,0 +1,35 @@
//! signkey create command
use std::path::PathBuf;
use anyhow::Result;
use sequoia_openpgp::cert::CertBuilder;
use sequoia_directories::Home;
use crate::cli::cli_args::SignkeyCreateCommand;
use crate::common::crypto;
use crate::config::{HuskConfig, HuskConfigContainer};
use crate::types::husk_context::HuskContext;
pub async fn dispatch(cmd: SignkeyCreateCommand, config: HuskConfigContainer)
-> Result<()> {
let config: HuskConfig = config.into();
let context = HuskContext::new(&config)?;
let sequoia_home = Home::new(PathBuf::from(&config.sequoia_home))?;
// XXX: cleanup the userid before using
let (cert, _) = CertBuilder::new()
.add_signing_subkey()
.add_userid(cmd.userid)
.generate()?;
if crypto::import_key(sequoia_home, &cert) {
let vc = cert.with_policy(&context.policy, None)?;
crypto::set_signing_key(&context, &vc)?;
println!("New signing key: {}", vc.fingerprint());
}
Ok(())
}
+27
View File
@@ -692,6 +692,33 @@ pub fn get_all_keys(sequoia_home: Home) -> Vec<Key> {
result
}
pub fn import_key(sequoia_home: Home, cert: &Cert) -> bool {
let mut imported = false;
std::thread::scope(|s| {
s.spawn(|| {
if let Ok(keystore_base) = Context::configure()
.home(sequoia_home.data_dir(sequoia_directories::Component::Keystore))
.build() {
if let Ok(mut keystore) = Keystore::connect(&keystore_base) {
if let Ok(mut backends) = keystore.backends() {
for backend in &mut backends {
if let Ok(id) = backend.id() {
if id == "softkeys" {
if let Ok(_) = backend.import(cert) {
imported = true;
}
}
}
}
}
}
}
});
});
imported
}
#[cfg(test)]
pub mod tests {
use sequoia_cert_store::store::CertD;