Switch to prompt library and autogenerate default comment

This commit is contained in:
pjht 2023-08-23 11:41:50 -05:00
parent f57c373faa
commit 6680f4c274
Signed by: pjht
GPG Key ID: CA239FC6934E6F3A
3 changed files with 288 additions and 92 deletions

241
Cargo.lock generated
View File

@ -49,7 +49,7 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
dependencies = [
"windows-sys",
"windows-sys 0.48.0",
]
[[package]]
@ -59,7 +59,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c677ab05e09154296dd37acecd46420c17b9713e8366facafa8fc0885167cf4c"
dependencies = [
"anstyle",
"windows-sys",
"windows-sys 0.48.0",
]
[[package]]
@ -131,6 +131,12 @@ version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.4.0"
@ -248,6 +254,19 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "console"
version = "0.15.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8"
dependencies = [
"encode_unicode",
"lazy_static",
"libc",
"unicode-width",
"windows-sys 0.45.0",
]
[[package]]
name = "const-oid"
version = "0.9.5"
@ -308,6 +327,16 @@ dependencies = [
"x509-parser",
]
[[package]]
name = "ctrlc"
version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a011bbe2c35ce9c1f143b7af6f94f29a167beb4cd1d29e6740ce836f723120e"
dependencies = [
"nix",
"windows-sys 0.48.0",
]
[[package]]
name = "curve25519-dalek"
version = "4.0.0"
@ -371,6 +400,18 @@ version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7684a49fb1af197853ef7b2ee694bc1f5b4179556f1e5710e1760c5db6f5e929"
[[package]]
name = "dialoguer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59c6f2989294b9a498d3ad5491a79c6deb604617378e1cdc4bfc1c1361fe2f87"
dependencies = [
"console",
"shell-words",
"tempfile",
"zeroize",
]
[[package]]
name = "digest"
version = "0.10.7"
@ -447,6 +488,12 @@ dependencies = [
"zeroize",
]
[[package]]
name = "encode_unicode"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
[[package]]
name = "errno"
version = "0.3.2"
@ -455,7 +502,7 @@ checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f"
dependencies = [
"errno-dragonfly",
"libc",
"windows-sys",
"windows-sys 0.48.0",
]
[[package]]
@ -468,6 +515,12 @@ dependencies = [
"libc",
]
[[package]]
name = "fastrand"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764"
[[package]]
name = "ff"
version = "0.13.0"
@ -489,12 +542,15 @@ name = "fido_ssh_maker"
version = "0.1.0"
dependencies = [
"anyhow",
"bitflags",
"bitflags 2.4.0",
"clap",
"ctap-hid-fido2",
"rpassword",
"ctrlc",
"dialoguer",
"gethostname",
"ssh-encoding",
"ssh-key",
"whoami",
]
[[package]]
@ -508,6 +564,16 @@ dependencies = [
"zeroize",
]
[[package]]
name = "gethostname"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818"
dependencies = [
"libc",
"windows-targets 0.48.1",
]
[[package]]
name = "getrandom"
version = "0.2.10"
@ -593,7 +659,7 @@ checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
dependencies = [
"hermit-abi",
"rustix",
"windows-sys",
"windows-sys 0.48.0",
]
[[package]]
@ -656,6 +722,18 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "nix"
version = "0.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a"
dependencies = [
"bitflags 1.3.2",
"cfg-if",
"libc",
"static_assertions",
]
[[package]]
name = "nom"
version = "7.1.3"
@ -912,6 +990,15 @@ dependencies = [
"getrandom",
]
[[package]]
name = "redox_syscall"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
dependencies = [
"bitflags 1.3.2",
]
[[package]]
name = "rfc6979"
version = "0.4.0"
@ -937,17 +1024,6 @@ dependencies = [
"winapi",
]
[[package]]
name = "rpassword"
version = "7.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6678cf63ab3491898c0d021b493c94c9b221d91295294a2a5746eacbe5928322"
dependencies = [
"libc",
"rtoolbox",
"winapi",
]
[[package]]
name = "rsa"
version = "0.9.2"
@ -971,16 +1047,6 @@ dependencies = [
"zeroize",
]
[[package]]
name = "rtoolbox"
version = "0.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "034e22c514f5c0cb8a10ff341b9b048b5ceb21591f31c8f44c43b960f9b3524a"
dependencies = [
"libc",
"winapi",
]
[[package]]
name = "rustc_version"
version = "0.4.0"
@ -1005,11 +1071,11 @@ version = "0.38.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f"
dependencies = [
"bitflags",
"bitflags 2.4.0",
"errno",
"libc",
"linux-raw-sys",
"windows-sys",
"windows-sys 0.48.0",
]
[[package]]
@ -1065,6 +1131,12 @@ dependencies = [
"digest",
]
[[package]]
name = "shell-words"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde"
[[package]]
name = "signature"
version = "2.1.0"
@ -1138,6 +1210,12 @@ dependencies = [
"zeroize",
]
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "strsim"
version = "0.10.0"
@ -1203,6 +1281,19 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "tempfile"
version = "3.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef"
dependencies = [
"cfg-if",
"fastrand",
"redox_syscall",
"rustix",
"windows-sys 0.48.0",
]
[[package]]
name = "thiserror"
version = "1.0.44"
@ -1363,6 +1454,16 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "whoami"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22fc3756b8a9133049b26c7f61ab35416c130e8c09b660f5b3958b446f52cc50"
dependencies = [
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "winapi"
version = "0.3.9"
@ -1385,13 +1486,37 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
dependencies = [
"windows-targets 0.42.2",
]
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets",
"windows-targets 0.48.1",
]
[[package]]
name = "windows-targets"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
dependencies = [
"windows_aarch64_gnullvm 0.42.2",
"windows_aarch64_msvc 0.42.2",
"windows_i686_gnu 0.42.2",
"windows_i686_msvc 0.42.2",
"windows_x86_64_gnu 0.42.2",
"windows_x86_64_gnullvm 0.42.2",
"windows_x86_64_msvc 0.42.2",
]
[[package]]
@ -1400,51 +1525,93 @@ version = "0.48.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
"windows_aarch64_gnullvm 0.48.0",
"windows_aarch64_msvc 0.48.0",
"windows_i686_gnu 0.48.0",
"windows_i686_msvc 0.48.0",
"windows_x86_64_gnu 0.48.0",
"windows_x86_64_gnullvm 0.48.0",
"windows_x86_64_msvc 0.48.0",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
[[package]]
name = "windows_i686_gnu"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
[[package]]
name = "windows_i686_gnu"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
[[package]]
name = "windows_i686_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
[[package]]
name = "windows_i686_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.0"

View File

@ -10,6 +10,9 @@ anyhow = "1.0.72"
bitflags = "2.4.0"
clap = { version = "4.3.21", features = ["derive"] }
ctap-hid-fido2 = "3.5.0"
rpassword = "7.2.0"
ctrlc = "3.4.0"
dialoguer = "0.10.4"
gethostname = "0.4.3"
ssh-encoding = { version = "0.2.0" }
ssh-key = { version = "0.6.0", features = ["ed25519"] }
whoami = "1.4.1"

View File

@ -1,7 +1,10 @@
use std::{
fmt::Display,
fs::Permissions,
io::Write,
os::unix::prelude::PermissionsExt,
path::{Path, PathBuf}, fmt::Display, io::Write,
path::{Path, PathBuf},
process,
};
use anyhow::anyhow;
@ -9,8 +12,10 @@ use bitflags::bitflags;
use clap::{Parser, ValueEnum};
use ctap_hid_fido2::{
fidokey::{CredentialSupportedKeyType, MakeCredentialArgsBuilder},
verifier, LibCfg, get_fidokey_devices, FidoKeyHid,
get_fidokey_devices, verifier, FidoKeyHid, LibCfg,
};
use dialoguer::{console, Confirm, Password, Select};
use gethostname::gethostname;
use ssh_encoding::{Decode, Encode, LineEnding};
use ssh_key::{private, PrivateKey};
@ -28,12 +33,9 @@ bitflags! {
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None, arg_required_else_help = true)]
struct Args {
/// SSH key comment
#[arg(short = 'c', long, default_value = "")]
comment: String,
/// Overwrite existing key files
#[arg(short = 'f', long)]
force: bool,
/// SSH key comment (default USER@HOSTNAME)
#[arg(short = 'c', long)]
comment: Option<String>,
/// Type of key to generate
#[arg(short = 't', long = "type")]
key_type: KeyTypeArg,
@ -81,44 +83,43 @@ fn main() -> anyhow::Result<()> {
let attest_info_path = PathBuf::from(format!("{}_attest.bin", &args.key_name));
let attest_challenge_path = PathBuf::from(format!("{}_attest_chall.bin", &args.key_name));
if !args.force && (privkey_path.exists() || pubkey_path.exists() || args.write_attestation && (attest_info_path.exists() || attest_challenge_path.exists())) {
return Err(anyhow!("Key files exist, use -f to overwrite."));
}
ctrlc::set_handler(move || {
let _ = console::Term::stdout().show_cursor();
println!();
process::exit(0);
})?;
println!("Generating public/private {} key pair", args.key_type);
if privkey_path.exists()
|| pubkey_path.exists()
|| (args.write_attestation && (attest_info_path.exists() || attest_challenge_path.exists()))
{
if !Confirm::new()
.with_prompt("Key files exist, overwrite?")
.default(false)
.interact()?
{
return Err(anyhow!("Generation aborted"));
}
}
let challenge = verifier::create_challenge();
let devices = get_fidokey_devices();
let devices = get_fidokey_devices();
let device = if devices.len() > 1 {
println!("Availible devices:");
for (i, device) in devices.iter().enumerate() {
println!("\t{}: {}", i + 1, device.product_string);
}
let mut buf = String::new();
loop {
print!("Device number: ");
std::io::stdout().flush()?;
buf.clear();
std::io::stdin().read_line(&mut buf)?;
if let Ok(num) = buf.trim().parse::<usize>() {
if num == 0 {
println!("Invalid number");
continue;
}
if let Some(device) = devices.get(num - 1) {
break device;
} else {
println!("Invalid number");
continue;
}
} else {
println!("Invalid number");
continue;
}
}
let idx = Select::new()
.with_prompt("Select FIDO2 key")
.items(
devices
.iter()
.map(|dev| format!("{}", dev.product_string))
.collect::<Vec<_>>()
.as_slice(),
)
.default(0)
.interact()?;
&devices[idx]
} else {
&devices[0]
};
@ -126,23 +127,28 @@ fn main() -> anyhow::Result<()> {
let mut libcfg = LibCfg::init();
libcfg.keep_alive_msg = "Touch the authenticator now.".into();
let device = FidoKeyHid::new(&[device.param.clone()], &libcfg)?;
let device_has_pin = device.get_info().map_or(false, |info| info.options.contains(&("clientPin".into(), true)));
let device_has_pin = device.get_info().map_or(false, |info| {
info.options.contains(&("clientPin".into(), true))
});
let pin = if device_has_pin {
rpassword::prompt_password("Enter FIDO2 PIN: ")?
Password::new()
.with_prompt("FIDO2 PIN")
.report(false)
.interact()?
} else {
String::new()
};
let make_credential_args = if device_has_pin {
MakeCredentialArgsBuilder::new("ssh:", &challenge)
.pin(&pin)
.key_type(args.key_type.into())
.build()
.pin(&pin)
.key_type(args.key_type.into())
.build()
} else {
MakeCredentialArgsBuilder::new("ssh:", &challenge)
.without_pin_and_uv()
.key_type(args.key_type.into())
.build()
.without_pin_and_uv()
.key_type(args.key_type.into())
.build()
};
let attestation = device.make_credential_with_args(&make_credential_args)?;
@ -165,14 +171,23 @@ fn main() -> anyhow::Result<()> {
privkey_bytes.push(flags.bits());
verify_result.credential_id.encode(&mut privkey_bytes)?;
"".encode(&mut privkey_bytes)?;
let comment = if let Some(comment) = args.comment {
comment
} else {
format!(
"{}@{}",
whoami::username(),
gethostname().to_string_lossy().into_owned()
)
};
let privkey = match args.key_type {
KeyTypeArg::EcdsaSk => PrivateKey::new(
private::SkEcdsaSha2NistP256::decode(&mut privkey_bytes.as_slice())?.into(),
args.comment,
comment,
)?,
KeyTypeArg::Ed25519Sk => PrivateKey::new(
private::SkEd25519::decode(&mut privkey_bytes.as_slice())?.into(),
args.comment,
comment,
)?,
};
@ -184,17 +199,28 @@ fn main() -> anyhow::Result<()> {
0u32.encode(&mut ssh_attest)?;
"".encode(&mut ssh_attest)?;
std::fs::write(&privkey_path, &*privkey.to_openssh(LineEnding::default())?)?;
std::fs::set_permissions(&privkey_path, Permissions::from_mode(0o600))?;
println!("Your identification has been saved in {}", privkey_path.to_string_lossy());
println!(
"Your identification has been saved in {}",
privkey_path.to_string_lossy()
);
std::fs::write(&pubkey_path, privkey.public_key().to_openssh()?)?;
println!("Your public key has been saved in {}", pubkey_path.to_string_lossy());
println!(
"Your public key has been saved in {}",
pubkey_path.to_string_lossy()
);
if args.write_attestation {
std::fs::write(&attest_info_path, &ssh_attest)?;
println!("Your FIDO attestation certificate has been saved in {}", attest_info_path.to_string_lossy());
println!(
"Your FIDO attestation certificate has been saved in {}",
attest_info_path.to_string_lossy()
);
std::fs::write(&attest_challenge_path, &challenge)?;
println!("Your FIDO attestation challenge has been saved in {}", attest_challenge_path.to_string_lossy());
println!(
"Your FIDO attestation challenge has been saved in {}",
attest_challenge_path.to_string_lossy()
);
}
Ok(())