keyfork: impl `derive openpgp`
This commit is contained in:
parent
6fc2c47391
commit
87a40f636d
|
@ -1062,10 +1062,13 @@ name = "keyfork"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"keyfork-derive-openpgp",
|
||||
"keyfork-derive-util",
|
||||
"keyfork-mnemonic-util",
|
||||
"keyfork-plumbing",
|
||||
"keyfork-shard",
|
||||
"keyforkd",
|
||||
"keyforkd-client",
|
||||
"serde",
|
||||
"smex",
|
||||
"thiserror",
|
||||
|
|
|
@ -15,6 +15,7 @@ use sequoia_openpgp::{
|
|||
types::{KeyFlags, SignatureType},
|
||||
Cert, Packet,
|
||||
};
|
||||
pub use sequoia_openpgp as openpgp;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
|
|
|
@ -42,6 +42,15 @@ impl DerivationPath {
|
|||
pub fn is_empty(&self) -> bool {
|
||||
self.path.is_empty()
|
||||
}
|
||||
|
||||
pub fn push(&mut self, index: DerivationIndex) {
|
||||
self.path.push(index);
|
||||
}
|
||||
|
||||
pub fn chain_push(mut self, index: DerivationIndex) -> Self {
|
||||
self.path.push(index);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for DerivationPath {
|
||||
|
|
|
@ -16,3 +16,6 @@ keyfork-shard = { version = "0.1.0", path = "../keyfork-shard" }
|
|||
serde = { version = "1.0.192", features = ["derive"] }
|
||||
keyforkd = { version = "0.1.0", path = "../keyforkd", features = ["tracing"] }
|
||||
tokio = { version = "1.35.1", default-features = false, features = ["rt-multi-thread"] }
|
||||
keyfork-derive-openpgp = { version = "0.1.0", path = "../keyfork-derive-openpgp" }
|
||||
keyforkd-client = { version = "0.1.0", path = "../keyforkd-client", default-features = false, features = ["ed25519"] }
|
||||
keyfork-derive-util = { version = "0.1.0", path = "../keyfork-derive-util", default-features = false, features = ["ed25519"] }
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
use super::Keyfork;
|
||||
use clap::{Parser, Subcommand};
|
||||
|
||||
use keyfork_derive_util::{
|
||||
request::{DerivationAlgorithm, DerivationRequest, DerivationResponse},
|
||||
DerivationIndex, DerivationPath,
|
||||
};
|
||||
use keyforkd_client::Client;
|
||||
use keyfork_derive_openpgp::openpgp::{types::KeyFlags, packet::UserID, armor::{Kind, Writer}, serialize::Marshal};
|
||||
|
||||
type Result<T, E = Box<dyn std::error::Error>> = std::result::Result<T, E>;
|
||||
|
||||
#[derive(Subcommand, Clone, Debug)]
|
||||
pub enum DeriveSubcommands {
|
||||
/// Derive an OpenPGP certificate.
|
||||
#[command(name = "openpgp")]
|
||||
OpenPGP {
|
||||
/// Default User ID for the certificate.
|
||||
user_id: String,
|
||||
},
|
||||
}
|
||||
|
||||
impl DeriveSubcommands {
|
||||
fn handle(&self, account: DerivationIndex) -> Result<()> {
|
||||
match self {
|
||||
DeriveSubcommands::OpenPGP { user_id } => {
|
||||
let mut pgp_u32 = [0u8; 4];
|
||||
pgp_u32[1..].copy_from_slice(&"pgp".bytes().collect::<Vec<u8>>());
|
||||
let chain = DerivationIndex::new(u32::from_be_bytes(pgp_u32), true)?;
|
||||
let path = DerivationPath::default()
|
||||
.chain_push(chain)
|
||||
.chain_push(account);
|
||||
// TODO: should this be customizable?
|
||||
let subkeys = vec![
|
||||
KeyFlags::empty().set_certification(),
|
||||
KeyFlags::empty().set_signing(),
|
||||
KeyFlags::empty().set_transport_encryption().set_storage_encryption(),
|
||||
KeyFlags::empty().set_authentication(),
|
||||
];
|
||||
let request = DerivationRequest::new(DerivationAlgorithm::Ed25519, &path);
|
||||
let derived_data: DerivationResponse = Client::discover_socket()?
|
||||
.request(&request.into())?
|
||||
.try_into()?;
|
||||
let default_userid = UserID::from(user_id.as_str());
|
||||
let cert = keyfork_derive_openpgp::derive(derived_data, &subkeys, &default_userid)?;
|
||||
|
||||
let mut w = Writer::new(std::io::stdout(), Kind::SecretKey)?;
|
||||
|
||||
for packet in cert.into_packets() {
|
||||
packet.serialize(&mut w)?;
|
||||
}
|
||||
|
||||
w.finalize()?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Parser, Debug, Clone)]
|
||||
pub struct Derive {
|
||||
#[command(subcommand)]
|
||||
command: DeriveSubcommands,
|
||||
|
||||
/// Account ID. Required for all derivations.
|
||||
#[arg(long, global = true, default_value = "0")]
|
||||
account_id: u32,
|
||||
}
|
||||
|
||||
impl Derive {
|
||||
pub fn handle(&self, _k: &Keyfork) -> Result<()> {
|
||||
let account = DerivationIndex::new(self.account_id, true)?;
|
||||
self.command.handle(account)
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
use clap::{Parser, Subcommand};
|
||||
|
||||
mod derive;
|
||||
mod mnemonic;
|
||||
mod provision;
|
||||
mod shard;
|
||||
|
@ -16,6 +17,9 @@ pub struct Keyfork {
|
|||
|
||||
#[derive(Subcommand, Clone, Debug)]
|
||||
pub enum KeyforkCommands {
|
||||
/// Derive keys of various formats.
|
||||
Derive(derive::Derive),
|
||||
|
||||
/// Mnemonic generation and persistence utilities.
|
||||
Mnemonic(mnemonic::Mnemonic),
|
||||
|
||||
|
@ -33,6 +37,9 @@ pub enum KeyforkCommands {
|
|||
impl KeyforkCommands {
|
||||
pub fn handle(&self, keyfork: &Keyfork) -> Result<(), Box<dyn std::error::Error>> {
|
||||
match self {
|
||||
KeyforkCommands::Derive(d) => {
|
||||
d.handle(keyfork)?;
|
||||
}
|
||||
KeyforkCommands::Mnemonic(m) => {
|
||||
let response = m.command.handle(m, keyfork)?;
|
||||
println!("{response}");
|
||||
|
|
Loading…
Reference in New Issue