summaryrefslogtreecommitdiffstats
path: root/tool/src/commands/key.rs
diff options
context:
space:
mode:
Diffstat (limited to 'tool/src/commands/key.rs')
-rw-r--r--tool/src/commands/key.rs248
1 files changed, 0 insertions, 248 deletions
diff --git a/tool/src/commands/key.rs b/tool/src/commands/key.rs
deleted file mode 100644
index dc1df48a..00000000
--- a/tool/src/commands/key.rs
+++ /dev/null
@@ -1,248 +0,0 @@
-use anyhow::Context as _;
-use clap::ArgMatches;
-use itertools::Itertools;
-use std::time::{SystemTime, Duration};
-
-use crate::openpgp::Result;
-use crate::openpgp::Packet;
-use crate::openpgp::cert::prelude::*;
-use crate::openpgp::types::KeyFlags;
-use crate::openpgp::armor::{Writer, Kind};
-use crate::openpgp::serialize::Serialize;
-
-use crate::create_or_stdout;
-
-const SECONDS_IN_DAY : u64 = 24 * 60 * 60;
-const SECONDS_IN_YEAR : u64 =
- // Average number of days in a year.
- (365.2422222 * SECONDS_IN_DAY as f64) as u64;
-
-pub fn generate(m: &ArgMatches, force: bool) -> Result<()> {
- let mut builder = CertBuilder::new();
-
- // User ID
- match m.values_of("userid") {
- Some(uids) => for uid in uids {
- builder = builder.add_userid(uid);
- },
- None => {
- eprintln!("No user ID given, using direct key signature");
- }
- }
-
- // Expiration.
- match (m.value_of("expires"), m.value_of("expires-in")) {
- (None, None) => // Default expiration.
- builder = builder.set_validity_period(
- Some(Duration::new(3 * SECONDS_IN_YEAR, 0))),
- (Some(t), None) if t == "never" =>
- builder = builder.set_validity_period(None),
- (Some(t), None) => {
- let now = builder.creation_time()
- .unwrap_or_else(std::time::SystemTime::now);
- let expiration = SystemTime::from(
- crate::parse_iso8601(t, chrono::NaiveTime::from_hms(0, 0, 0))?);
- let validity = expiration.duration_since(now)?;
- builder = builder.set_creation_time(now)
- .set_validity_period(validity);
- },
- (None, Some(d)) if d == "never" =>
- builder = builder.set_validity_period(None),
- (None, Some(d)) => {
- let d = parse_duration(d)?;
- builder = builder.set_validity_period(Some(d));
- },
- (Some(_), Some(_)) => unreachable!("conflicting args"),
- }
-
- // Cipher Suite
- match m.value_of("cipher-suite") {
- Some("rsa3k") => {
- builder = builder.set_cipher_suite(CipherSuite::RSA3k);
- }
- Some("rsa4k") => {
- builder = builder.set_cipher_suite(CipherSuite::RSA4k);
- }
- Some("cv25519") => {
- builder = builder.set_cipher_suite(CipherSuite::Cv25519);
- }
- Some(ref cs) => {
- return Err(anyhow::anyhow!("Unknown cipher suite '{}'", cs));
- }
- None => panic!("argument has a default value"),
- }
-
- // Signing Capability
- match (m.is_present("can-sign"), m.is_present("cannot-sign")) {
- (false, false) | (true, false) => {
- builder = builder.add_signing_subkey();
- }
- (false, true) => { /* no signing subkey */ }
- (true, true) => {
- return Err(
- anyhow::anyhow!("Conflicting arguments --can-sign and --cannot-sign"));
- }
- }
-
- // Encryption Capability
- match (m.value_of("can-encrypt"), m.is_present("cannot-encrypt")) {
- (Some("universal"), false) | (None, false) => {
- builder = builder.add_subkey(KeyFlags::empty()
- .set_transport_encryption()
- .set_storage_encryption(),
- None,
- None);
- }
- (Some("storage"), false) => {
- builder = builder.add_storage_encryption_subkey();
- }
- (Some("transport"), false) => {
- builder = builder.add_transport_encryption_subkey();
- }
- (None, true) => { /* no encryption subkey */ }
- (Some(_), true) => {
- return Err(
- anyhow::anyhow!("Conflicting arguments --can-encrypt and \
- --cannot-encrypt"));
- }
- (Some(ref cap), false) => {
- return Err(
- anyhow::anyhow!("Unknown encryption capability '{}'", cap));
- }
- }
-
- if m.is_present("with-password") {
- let p0 = rpassword::read_password_from_tty(Some(
- "Enter password to protect the key: "))?.into();
- let p1 = rpassword::read_password_from_tty(Some(
- "Repeat the password once more: "))?.into();
-
- if p0 == p1 {
- builder = builder.set_password(Some(p0));
- } else {
- return Err(anyhow::anyhow!("Passwords do not match."));
- }
- }
-
- // Generate the key
- let (cert, rev) = builder.generate()?;
-
- // Export
- if m.is_present("export") {
- let (key_path, rev_path) =
- match (m.value_of("export"), m.value_of("rev-cert")) {
- (Some("-"), Some("-")) =>
- ("-".to_string(), "-".to_string()),
- (Some("-"), Some(ref rp)) =>
- ("-".to_string(), rp.to_string()),
- (Some("-"), None) =>
- return Err(
- anyhow::anyhow!("Missing arguments: --rev-cert is mandatory \
- if --export is '-'.")),
- (Some(ref kp), None) =>
- (kp.to_string(), format!("{}.rev", kp)),
- (Some(ref kp), Some("-")) =>
- (kp.to_string(), "-".to_string()),
- (Some(ref kp), Some(ref rp)) =>
- (kp.to_string(), rp.to_string()),
- _ =>
- return Err(
- anyhow::anyhow!("Conflicting arguments --rev-cert and \
- --export")),
- };
-
- let headers = cert.armor_headers();
-
- // write out key
- {
- let headers: Vec<_> = headers.iter()
- .map(|value| ("Comment", value.as_str()))
- .collect();
-
- let w = create_or_stdout(Some(&key_path), force)?;
- let mut w = Writer::with_headers(w, Kind::SecretKey, headers)?;
- cert.as_tsk().serialize(&mut w)?;
- w.finalize()?;
- }
-
- // write out rev cert
- {
- let mut headers: Vec<_> = headers.iter()
- .map(|value| ("Comment", value.as_str()))
- .collect();
- headers.insert(0, ("Comment", "Revocation certificate for"));
-
- let w = create_or_stdout(Some(&rev_path), force)?;
- let mut w = Writer::with_headers(w, Kind::Signature, headers)?;
- Packet::Signature(rev).serialize(&mut w)?;
- w.finalize()?;
- }
- } else {
- return Err(
- anyhow::anyhow!("Saving generated key to the store isn't implemented \
- yet."));
- }
-
- Ok(())
-}
-
-fn parse_duration(expiry: &str) -> Result<Duration> {
- let mut expiry = expiry.chars().peekable();
-
- let _ = expiry.by_ref()
- .peeking_take_while(|c| c.is_whitespace())
- .for_each(|_| ());
- let digits = expiry.by_ref()
- .peeking_take_while(|c| {
- *c == '+' || *c == '-' || c.is_digit(10)
- }).collect::<String>();
- let _ = expiry.by_ref()
- .peeking_take_while(|c| c.is_whitespace())
- .for_each(|_| ());
- let suffix = expiry.next();
- let _ = expiry.by_ref()
- .peeking_take_while(|c| c.is_whitespace())
- .for_each(|_| ());
- let junk = expiry.collect::<String>();
-
- if digits == "" {
- return Err(anyhow::anyhow!(
- "--expiry: missing count \
- (try: '2y' for 2 years)"));
- }
-
- let count = match digits.parse::<i32>() {
- Ok(count) if count < 0 =>
- return Err(anyhow::anyhow!(
- "--expiry: Expiration can't be in the past")),
- Ok(count) => count as u64,
- Err(err) =>
- return Err(err).context("--expiry: count is out of range"),
- };
-
- let factor = match suffix {
- Some('y') | Some('Y') => SECONDS_IN_YEAR,
- Some('m') | Some('M') => SECONDS_IN_YEAR / 12,
- Some('w') | Some('W') => 7 * SECONDS_IN_DAY,
- Some('d') | Some('D') => SECONDS_IN_DAY,
- None =>
- return Err(anyhow::anyhow!(
- "--expiry: missing suffix \
- (try: '{}y', '{}m', '{}w' or '{}d' instead)",
- digits, digits, digits, digits)),
- Some(suffix) =>
- return Err(anyhow::anyhow!(
- "--expiry: invalid suffix '{}' \
- (try: '{}y', '{}m', '{}w' or '{}d' instead)",
- suffix, digits, digits, digits, digits)),
- };
-
- if junk != "" {
- return Err(anyhow::anyhow!(
- "--expiry: contains trailing junk ('{:?}') \
- (try: '{}{}')",
- junk, count, factor));
- }
-
- Ok(Duration::new(count * factor, 0))
-}