keyfork: impl `derive openpgp`
This commit is contained in:
parent
6fc2c47391
commit
87a40f636d
|
@ -1062,10 +1062,13 @@ name = "keyfork"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
|
"keyfork-derive-openpgp",
|
||||||
|
"keyfork-derive-util",
|
||||||
"keyfork-mnemonic-util",
|
"keyfork-mnemonic-util",
|
||||||
"keyfork-plumbing",
|
"keyfork-plumbing",
|
||||||
"keyfork-shard",
|
"keyfork-shard",
|
||||||
"keyforkd",
|
"keyforkd",
|
||||||
|
"keyforkd-client",
|
||||||
"serde",
|
"serde",
|
||||||
"smex",
|
"smex",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
|
|
|
@ -15,6 +15,7 @@ use sequoia_openpgp::{
|
||||||
types::{KeyFlags, SignatureType},
|
types::{KeyFlags, SignatureType},
|
||||||
Cert, Packet,
|
Cert, Packet,
|
||||||
};
|
};
|
||||||
|
pub use sequoia_openpgp as openpgp;
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
|
|
@ -42,6 +42,15 @@ impl DerivationPath {
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.path.is_empty()
|
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 {
|
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"] }
|
serde = { version = "1.0.192", features = ["derive"] }
|
||||||
keyforkd = { version = "0.1.0", path = "../keyforkd", features = ["tracing"] }
|
keyforkd = { version = "0.1.0", path = "../keyforkd", features = ["tracing"] }
|
||||||
tokio = { version = "1.35.1", default-features = false, features = ["rt-multi-thread"] }
|
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};
|
use clap::{Parser, Subcommand};
|
||||||
|
|
||||||
|
mod derive;
|
||||||
mod mnemonic;
|
mod mnemonic;
|
||||||
mod provision;
|
mod provision;
|
||||||
mod shard;
|
mod shard;
|
||||||
|
@ -16,6 +17,9 @@ pub struct Keyfork {
|
||||||
|
|
||||||
#[derive(Subcommand, Clone, Debug)]
|
#[derive(Subcommand, Clone, Debug)]
|
||||||
pub enum KeyforkCommands {
|
pub enum KeyforkCommands {
|
||||||
|
/// Derive keys of various formats.
|
||||||
|
Derive(derive::Derive),
|
||||||
|
|
||||||
/// Mnemonic generation and persistence utilities.
|
/// Mnemonic generation and persistence utilities.
|
||||||
Mnemonic(mnemonic::Mnemonic),
|
Mnemonic(mnemonic::Mnemonic),
|
||||||
|
|
||||||
|
@ -33,6 +37,9 @@ pub enum KeyforkCommands {
|
||||||
impl KeyforkCommands {
|
impl KeyforkCommands {
|
||||||
pub fn handle(&self, keyfork: &Keyfork) -> Result<(), Box<dyn std::error::Error>> {
|
pub fn handle(&self, keyfork: &Keyfork) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
match self {
|
match self {
|
||||||
|
KeyforkCommands::Derive(d) => {
|
||||||
|
d.handle(keyfork)?;
|
||||||
|
}
|
||||||
KeyforkCommands::Mnemonic(m) => {
|
KeyforkCommands::Mnemonic(m) => {
|
||||||
let response = m.command.handle(m, keyfork)?;
|
let response = m.command.handle(m, keyfork)?;
|
||||||
println!("{response}");
|
println!("{response}");
|
||||||
|
|
Loading…
Reference in New Issue