keyfork-user-guide: more additions
This commit is contained in:
parent
8809db6f7f
commit
5d5d5181b3
|
@ -1 +1,2 @@
|
|||
target
|
||||
testing_data
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::{env, str::FromStr};
|
||||
use std::{env, process::ExitCode, str::FromStr};
|
||||
|
||||
use keyfork_derive_util::{
|
||||
request::{DerivationAlgorithm, DerivationError, DerivationRequest},
|
||||
|
@ -27,7 +27,7 @@ fn validate(algo: &str, path: &str) -> Result<(DerivationAlgorithm, DerivationPa
|
|||
Ok((algo, path))
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
fn run() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut args = env::args();
|
||||
let program_name = args.next().expect("program name");
|
||||
let args = args.collect::<Vec<_>>();
|
||||
|
@ -42,3 +42,12 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
println!("{}", smex::encode(&response.data));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() -> ExitCode {
|
||||
if let Err(e) = run() {
|
||||
eprintln!("Error: {e}");
|
||||
ExitCode::FAILURE
|
||||
} else {
|
||||
ExitCode::SUCCESS
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use std::{
|
||||
collections::VecDeque,
|
||||
env,
|
||||
io::{stdin, stdout},
|
||||
path::PathBuf,
|
||||
|
@ -7,30 +6,7 @@ use std::{
|
|||
str::FromStr,
|
||||
};
|
||||
|
||||
use keyfork_shard::{combine, discover_certs, openpgp::Cert, EncryptedMessage};
|
||||
use openpgp::{
|
||||
packet::Packet,
|
||||
parse::Parse,
|
||||
PacketPile,
|
||||
};
|
||||
use sequoia_openpgp as openpgp;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum Error {
|
||||
Usage(String),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Error::Usage(program_name) => {
|
||||
write!(f, "Usage: {program_name} threshold key_discovery")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for Error {}
|
||||
use keyfork_shard::{combine, discover_certs, parse_messages, openpgp::Cert};
|
||||
|
||||
type Result<T, E = Box<dyn std::error::Error>> = std::result::Result<T, E>;
|
||||
|
||||
|
@ -53,25 +29,10 @@ fn run() -> Result<()> {
|
|||
let args = args.collect::<Vec<_>>();
|
||||
let (threshold, cert_list) = match args.as_slice() {
|
||||
[threshold, key_discovery] => validate(threshold, key_discovery)?,
|
||||
_ => return Err(Error::Usage(program_name).into()),
|
||||
_ => panic!("Usage: {program_name} threshold key_discovery"),
|
||||
};
|
||||
|
||||
let stdin = stdin();
|
||||
|
||||
let mut pkesks = Vec::new();
|
||||
let mut encrypted_messages = VecDeque::new();
|
||||
|
||||
for packet in PacketPile::from_reader(stdin)?.into_children() {
|
||||
match packet {
|
||||
Packet::PKESK(p) => pkesks.push(p),
|
||||
Packet::SEIP(s) => {
|
||||
encrypted_messages.push_back(EncryptedMessage::with_swap(&mut pkesks, s));
|
||||
}
|
||||
s => {
|
||||
panic!("Invalid variant found: {}", s.tag());
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut encrypted_messages = parse_messages(stdin())?;
|
||||
|
||||
let encrypted_metadata = encrypted_messages
|
||||
.pop_front()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use std::{
|
||||
collections::HashMap,
|
||||
collections::{HashMap, VecDeque},
|
||||
io::{Read, Write},
|
||||
path::Path,
|
||||
str::FromStr,
|
||||
|
@ -12,7 +12,7 @@ use keyfork_derive_openpgp::derive_util::{
|
|||
use openpgp::{
|
||||
armor::{Kind, Writer},
|
||||
cert::{Cert, CertParser, ValidCert},
|
||||
packet::{Tag, UserID, PKESK, SEIP},
|
||||
packet::{Packet, Tag, UserID, PKESK, SEIP},
|
||||
parse::{stream::DecryptorBuilder, Parse},
|
||||
policy::{NullPolicy, Policy, StandardPolicy},
|
||||
serialize::{
|
||||
|
@ -20,7 +20,7 @@ use openpgp::{
|
|||
Marshal,
|
||||
},
|
||||
types::KeyFlags,
|
||||
KeyID,
|
||||
KeyID, PacketPile
|
||||
};
|
||||
pub use sequoia_openpgp as openpgp;
|
||||
use sharks::{Share, Sharks};
|
||||
|
@ -75,24 +75,6 @@ impl EncryptedMessage {
|
|||
message.write_all(&packet)?;
|
||||
message.finalize()?;
|
||||
|
||||
/*
|
||||
// TODO: only serialize the message and use provided PKESK vec
|
||||
let mut pkesks = vec![];
|
||||
let ppr = PacketParser::from_reader(&packets[..])?;
|
||||
while let PacketParserResult::Some(mut pp) = ppr {
|
||||
match pp.packet {
|
||||
openpgp::Packet::PKESK(pkesk) => pkesks.push(pkesk),
|
||||
openpgp::Packet::SEIP(_) => {
|
||||
keyring.decrypt(&pkesks, &[], None, |algo, sk| {
|
||||
// pushes packet to stack
|
||||
pp.decrypt(algo, sk).is_ok()
|
||||
});
|
||||
},
|
||||
p => panic!("Unexpected packet type: {}", p.tag()),
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
let mut decryptor =
|
||||
DecryptorBuilder::from_bytes(&packets)?.with_policy(policy, None, keyring)?;
|
||||
|
||||
|
@ -124,6 +106,25 @@ pub fn discover_certs(path: impl AsRef<Path>) -> Result<Vec<Cert>> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn parse_messages(reader: impl Read + Send + Sync) -> Result<VecDeque<EncryptedMessage> >{
|
||||
let mut pkesks = Vec::new();
|
||||
let mut encrypted_messages = VecDeque::new();
|
||||
|
||||
for packet in PacketPile::from_reader(reader)?.into_children() {
|
||||
match packet {
|
||||
Packet::PKESK(p) => pkesks.push(p),
|
||||
Packet::SEIP(s) => {
|
||||
encrypted_messages.push_back(EncryptedMessage::with_swap(&mut pkesks, s));
|
||||
}
|
||||
s => {
|
||||
panic!("Invalid variant found: {}", s.tag());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(encrypted_messages)
|
||||
}
|
||||
|
||||
fn get_encryption_keys<'a>(
|
||||
cert: &'a ValidCert,
|
||||
) -> openpgp::cert::prelude::ValidKeyAmalgamationIter<
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
<!-- vim:set et sts=0 sw=2 ts=2: -->
|
||||
# Summary
|
||||
|
||||
# User Guide
|
||||
|
||||
- [Installing Keyfork](./INSTALL.md)
|
||||
- [Common Usage](./usage.md)
|
||||
- [Binaries](./bin/index.md)
|
||||
|
@ -11,4 +13,8 @@
|
|||
- [keyfork-mnemonic-from-seed](./bin/keyfork-plumbing/mnemonic-from-seed.md)
|
||||
- [keyfork-derive-key](./bin/keyfork-derive-key.md)
|
||||
- [keyfork-derive-openpgp](./bin/keyfork-derive-openpgp.md)
|
||||
- [Development Guide](./dev-guide/index.md)
|
||||
|
||||
# Developers Guide
|
||||
|
||||
- [Writing Binaries](./dev-guide/index.md)
|
||||
- [Auditing](./dev-guide/auditing.md)
|
||||
|
|
|
@ -18,3 +18,5 @@ the shell silently ignoring the single quotes in the derivation path.
|
|||
|
||||
Hex-encoded private key. Note that this is not the _extended_ private key, and
|
||||
can't be used to derive further data.
|
||||
|
||||
[`keyforkd`]: ./bin/keyforkd.md
|
||||
|
|
|
@ -28,3 +28,5 @@ the shell silently ignoring the single quotes in the derivation path.
|
|||
## Output
|
||||
|
||||
OpenPGP ASCII armored key, signed to be valid for 24 hours.
|
||||
|
||||
[`keyforkd`]: ./bin/keyforkd.md
|
||||
|
|
|
@ -12,11 +12,16 @@ requires a system be both offline and running an up-to-date kernel before
|
|||
generating a mnemonic. However, the command may be run with the variable
|
||||
`INSECURE_HARDWARE_ALLOWED=1` to override system validation.
|
||||
|
||||
## Usage
|
||||
## Arguments
|
||||
|
||||
```
|
||||
% keyfork mnemonic generate
|
||||
ceiling talent smooth jealous dust render hello resource ripple crucial pepper tribe noble gate shield glad slide document pulse negative spider this fancy seven
|
||||
% keyfork mnemonic generate --size 128
|
||||
sustain glory control silk gym argue jaguar citizen remember doctor depth senior
|
||||
```
|
||||
`keyfork mnemonic generate --source=system --size=256`
|
||||
|
||||
* `--source`: The source from where a seed is created. Can be:
|
||||
* `system`
|
||||
|
||||
Choosing any option besides `system` will prompt the user for input:
|
||||
|
||||
* `playing`
|
||||
* `tarot`
|
||||
* `dice`
|
||||
* `--size`: The size in bits for the memonic, either `128` or `256`.
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
# Auditing Dependencies
|
||||
|
||||
Dependencies must be reviewed before being added to the repository, and must
|
||||
not be added for pure convenience. There are few exceptions, such as `clap` and
|
||||
`thiserror`, which provide derivation macros that are used heavily throughout
|
||||
`keyfork` and the codebase as a whole. Any dependency added must be reviewed at
|
||||
least on a surface level to ensure no malicious actions are performed with the
|
||||
data the library will be responsible for handling. For example, any use of
|
||||
`std::process` in a crate providing cryptographic functions should be heavily
|
||||
scrutinized, and any crate that loads arbitrary code or performs networking
|
||||
requests should have an incredibly important reason for doing so.
|
||||
|
||||
Dependencies should be restricted such that the least amount of dead code is
|
||||
enabled. For instance, a crate such as `keyfork_derive_openpgp` can only make
|
||||
use of the `ed25519` algorithm, so it exports its own `derive_util` that only
|
||||
includes the crates required for that library. This can then be used by
|
||||
programs such as `keyfork-shard`'s OpenPGP mode or `keyfork provision openpgp`
|
||||
to ensure only the required dependencies are enabled. This reduces the burden
|
||||
of auditors, but it does mean we can't use projects such as [`hakari`] to
|
||||
optimize full-project builds.
|
||||
|
||||
[`hakari`]: https://docs.rs/cargo-hakari/latest/cargo_hakari/index.html
|
|
@ -1,4 +1,4 @@
|
|||
# Development Guide
|
||||
# Writing Binaries
|
||||
|
||||
### Binaries - Porcelain and Plumbing
|
||||
|
||||
|
@ -13,25 +13,80 @@ Usually, only cryptographic functionality (such as `sequoia-openpgp` or
|
|||
`dalek-ed25519`) or hardware integration libraries (such as `openpgp-card`) are
|
||||
included.
|
||||
|
||||
### Auditing Dependencies
|
||||
### Writing Binaries
|
||||
|
||||
Dependencies must be reviewed before being added to the repository, and must
|
||||
not be added for pure convenience. There are few exceptions, such as `clap` and
|
||||
`thiserror`, which provide derivation macros that are used heavily throughout
|
||||
`keyfork` and the codebase as a whole. Any dependency added must be reviewed at
|
||||
least on a surface level to ensure no malicious actions are performed with the
|
||||
data the library will be responsible for handling. For example, any use of
|
||||
`std::process` in a crate providing cryptographic functions should be heavily
|
||||
scrutinized, and any crate that loads arbitrary code or performs networking
|
||||
requests should have an incredibly important reason for doing so.
|
||||
Crates can be either a library, or a library and binary, but should never be
|
||||
just a binary. When creating a crate with a binary, the `main.rs` file should
|
||||
be designed to validate arguments, load any necessary system resources, and
|
||||
call a separate exposed function to do the heavy lifting. The following example
|
||||
was taken from `keyfork-shard` to demonstrate how a program can validate
|
||||
arguments, parse input, and stream an output.
|
||||
|
||||
Dependencies should be restricted such that the least amount of dead code is
|
||||
enabled. For instance, a crate such as `keyfork_derive_openpgp` can only make
|
||||
use of the `ed25519` algorithm, so it exports its own `derive_util` that only
|
||||
includes the crates required for that library. This can then be used by
|
||||
programs such as `keyfork-shard`'s OpenPGP mode or `keyfork provision openpgp`
|
||||
to ensure only the required dependencies are enabled. This reduces the burden
|
||||
of auditors, but it does mean we can't use projects such as [`hakari`] to
|
||||
optimize full-project builds.
|
||||
```rust
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
env,
|
||||
io::{stdin, stdout},
|
||||
path::PathBuf,
|
||||
process::ExitCode,
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
[`hakari`]: https://docs.rs/cargo-hakari/latest/cargo_hakari/index.html
|
||||
use keyfork_shard::openpgp::{combine, discover_certs, openpgp::Cert};
|
||||
use sequoia_openpgp as openpgp;
|
||||
|
||||
type Result<T, E = Box<dyn std::error::Error>> = std::result::Result<T, E>;
|
||||
|
||||
fn validate(threshold: &str, key_discovery: &str) -> Result<(u8, Vec<Cert>)> {
|
||||
let threshold = u8::from_str(threshold)?;
|
||||
let key_discovery = PathBuf::from(key_discovery);
|
||||
|
||||
// Verify path exists
|
||||
std::fs::metadata(&key_discovery)?;
|
||||
|
||||
// Load certs from path
|
||||
let certs = discover_certs(key_discovery)?;
|
||||
|
||||
Ok((threshold, certs))
|
||||
}
|
||||
|
||||
fn run() -> Result<()> {
|
||||
let mut args = env::args();
|
||||
let program_name = args.next().expect("program name");
|
||||
let args = args.collect::<Vec<_>>();
|
||||
let (threshold, cert_list) = match args.as_slice() {
|
||||
[threshold, key_discovery] => validate(threshold, key_discovery)?,
|
||||
_ => panic!("Usage: {program_name} threshold key_discovery"),
|
||||
};
|
||||
|
||||
let encrypted_messages = parse_messages(stdin())?;
|
||||
|
||||
let encrypted_metadata = encrypted_messages
|
||||
.pop_front()
|
||||
.expect("any pgp encrypted message");
|
||||
|
||||
combine(
|
||||
threshold,
|
||||
cert_list,
|
||||
encrypted_metadata,
|
||||
encrypted_messages.into(),
|
||||
stdout(),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() -> ExitCode {
|
||||
let result = run();
|
||||
if let Err(e) = result {
|
||||
eprintln!("Error: {e}");
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
ExitCode::SUCCESS
|
||||
}
|
||||
```
|
||||
|
||||
Designing binaries with this format makes it easier to load them to the Keyfork
|
||||
porcelain binary, since the porcelain can call `combine()` with arguments that
|
||||
it has parsed using its own configuration systems, using a `String` as a `mut
|
||||
Write` as necessary.
|
||||
|
|
Loading…
Reference in New Issue