summaryrefslogtreecommitdiffstats
path: root/tool/src/commands/key.rs
blob: 43dde438f1c2c82f8effe886b805068773e71f21 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
use failure;
use clap::ArgMatches;

use openpgp::tpk::{TPKBuilder, CipherSuite};
use openpgp::packet::KeyFlags;
use openpgp::armor::{Writer, Kind};
use openpgp::serialize::Serialize;

use ::create_or_stdout;

pub fn generate(m: &ArgMatches, force: bool) -> failure::Fallible<()> {
    let mut builder = TPKBuilder::new();

    // User ID
    match m.value_of("userid") {
        Some(uid) => { builder = builder.add_userid(uid); }
        None => {
            eprintln!("No user ID given, using direct key signature");
        }
    }

    // Cipher Suite
    match m.value_of("cipher-suite") {
        None | Some("rsa3k") => {
            builder = builder.set_cipher_suite(CipherSuite::RSA3k);
        }
        Some("cv25519") => {
            builder = builder.set_cipher_suite(CipherSuite::Cv25519);
        }
        Some(ref cs) => {
            return Err(format_err!("Unknown cipher suite '{}'", cs));
        }
    }

    // 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(
                format_err!("Conflicting arguments --can-sign and --cannot-sign"));
        }
    }

    // Encryption Capability
    match (m.value_of("can-encrypt"), m.is_present("cannot-encrypt")) {
        (Some("all"), false) | (None, false) => {
            builder = builder.add_encryption_subkey();
        }
        (Some("rest"), false) => {
            builder = builder.add_subkey(KeyFlags::default()
                                         .set_encrypt_at_rest(true));
        }
        (Some("transport"), false) => {
            builder = builder.add_subkey(KeyFlags::default()
                                         .set_encrypt_for_transport(true));
        }
        (None, true) => { /* no encryption subkey */ }
        (Some(_), true) => {
            return Err(
                format_err!("Conflicting arguments --can-encrypt and \
                             --cannot-encrypt"));
        }
        (Some(ref cap), false) => {
            return Err(
                format_err!("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(failure::err_msg("Passwords do not match."));
        }
    }

    // Generate the key
    let (tpk, 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(
                        format_err!("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(
                        format_err!("Conflicting arguments --rev-cert and \
                                     --export")),
            };

        // write out key
        {
            let w = create_or_stdout(Some(&key_path), force)?;
            let mut w = Writer::new(w, Kind::SecretKey, &[])?;
            tpk.as_tsk().serialize(&mut w)?;
        }

        // write out rev cert
        {
            let w = create_or_stdout(Some(&rev_path), force)?;
            let mut w = Writer::new(w, Kind::Signature, &[])?;
            rev.serialize(&mut w)?;
        }
    } else {
        return Err(
            format_err!("Saving generated key to the store isn't implemented \
                         yet."));
    }

    Ok(())
}