Skip to content

Commit

Permalink
add solokey lock state, merge info commands
Browse files Browse the repository at this point in the history
  • Loading branch information
micolous committed Oct 25, 2023
1 parent da72ad5 commit 1c14942
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 37 deletions.
70 changes: 34 additions & 36 deletions fido-key-manager/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,11 +201,8 @@ pub enum Opt {
/// Updates user information for a discoverable credential on this token.
UpdateCredentialUser(UpdateCredentialUserOpt),
#[cfg(feature = "solokey")]
/// Gets a SoloKey's UUID.
SoloKeyUuid(InfoOpt),
#[cfg(feature = "solokey")]
/// Gets a SoloKey's version.
SoloKeyVersion(InfoOpt),
/// Gets info about a connected SoloKey.
SoloKeyInfo(InfoOpt),
}

#[derive(Debug, clap::Parser)]
Expand Down Expand Up @@ -691,7 +688,7 @@ async fn main() {
}

#[cfg(feature = "solokey")]
Opt::SoloKeyUuid(o) => {
Opt::SoloKeyInfo(o) => {
while let Some(event) = stream.next().await {
match event {
TokenEvent::Added(t) => {
Expand All @@ -700,46 +697,47 @@ async fn main() {
None => continue,
};

match authenticator.get_solokey_uuid().await {
Ok(uuid) => println!("SoloKey UUID: {uuid}"),
let uuid = match authenticator.get_solokey_uuid().await {
Ok(v) => v,
Err(WebauthnCError::NotSupported)
| Err(WebauthnCError::U2F(_))
| Err(WebauthnCError::InvalidMessageLength) => {
println!("Device is not a SoloKey!")
println!("Device is not a SoloKey!");
continue;
}
Err(e) => panic!("could not get SoloKey UUID: {e:?}"),
}
}
TokenEvent::EnumerationComplete => {
if o.watch {
println!("Initial enumeration completed, watching for more devices...");
println!("Press Ctrl + C to stop watching.");
} else {
break;
}
}
_ => (),
}
}
}

#[cfg(feature = "solokey")]
Opt::SoloKeyVersion(o) => {
while let Some(event) = stream.next().await {
match event {
TokenEvent::Added(t) => {
let mut authenticator = match CtapAuthenticator::new(t, &ui).await {
Some(a) => a,
None => continue,
};

match authenticator.get_solokey_version().await {
Ok(ver) => println!("SoloKey version: {ver:#x}"),
let version = match authenticator.get_solokey_version().await {
Ok(v) => v,
Err(WebauthnCError::NotSupported)
| Err(WebauthnCError::U2F(_))
| Err(WebauthnCError::InvalidMessageLength) => {
println!("Device is not a SoloKey!")
println!("Device is not a SoloKey!");
continue;
}
Err(e) => panic!("could not get SoloKey version: {e:?}"),
}
};

let secure_boot = if match authenticator.get_solokey_lock().await {
Ok(v) => v,
Err(WebauthnCError::NotSupported)
| Err(WebauthnCError::U2F(_))
| Err(WebauthnCError::InvalidMessageLength) => {
println!("Device is not a SoloKey!");
continue;
}
Err(e) => panic!("could not get SoloKey lock state: {e:?}"),
} {
"enabled"
} else {
"disabled"
};

println!("SoloKey info:");
println!(" Device UUID: {uuid}");
println!(" Version: {version:#x}");
println!(" Secure boot: {secure_boot}");
}
TokenEvent::EnumerationComplete => {
if o.watch {
Expand Down
8 changes: 8 additions & 0 deletions webauthn-authenticator-rs/src/ctap2/solokey.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ use super::Ctap20Authenticator;
/// Protocol notes are in [`crate::transport::solokey`].
#[async_trait]
pub trait SoloKeyAuthenticator {
/// Gets the device's lock (secure boot) status.
async fn get_solokey_lock(&mut self) -> Result<bool, WebauthnCError>;

/// Gets the device-specific UUID of a SoloKey token.
async fn get_solokey_uuid(&mut self) -> Result<Uuid, WebauthnCError>;

Expand All @@ -30,6 +33,11 @@ pub trait SoloKeyAuthenticator {
impl<'a, T: Token + SoloKeyToken, U: UiCallback> SoloKeyAuthenticator
for Ctap20Authenticator<'a, T, U>
{
#[inline]
async fn get_solokey_lock(&mut self) -> Result<bool, WebauthnCError> {
self.token.get_solokey_lock().await
}

#[inline]
async fn get_solokey_uuid(&mut self) -> Result<Uuid, WebauthnCError> {
self.token.get_solokey_uuid().await
Expand Down
18 changes: 18 additions & 0 deletions webauthn-authenticator-rs/src/transport/solokey.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,15 @@ pub const CMD_VERSION: u8 = super::TYPE_INIT | 0x61;
#[cfg(all(feature = "usb", feature = "vendor-solokey"))]
pub const CMD_UUID: u8 = super::TYPE_INIT | 0x62;

#[cfg(all(feature = "usb", feature = "vendor-solokey"))]
pub const CMD_LOCK: u8 = super::TYPE_INIT | 0x63;

/// See [`SoloKeyAuthenticator`](crate::ctap2::SoloKeyAuthenticator).
#[async_trait]
pub trait SoloKeyToken {
/// See [`SoloKeyAuthenticator::get_solokey_lock()`](crate::ctap2::SoloKeyAuthenticator::get_solokey_lock).
async fn get_solokey_lock(&mut self) -> Result<bool, WebauthnCError>;

/// See [`SoloKeyAuthenticator::get_solokey_version()`](crate::ctap2::SoloKeyAuthenticator::get_solokey_version).
async fn get_solokey_version(&mut self) -> Result<u32, WebauthnCError>;

Expand All @@ -53,6 +59,18 @@ pub trait SoloKeyToken {

#[async_trait]
impl SoloKeyToken for AnyToken {
async fn get_solokey_lock(&mut self) -> Result<bool, WebauthnCError> {
match self {
AnyToken::Stub => unimplemented!(),
#[cfg(feature = "bluetooth")]
AnyToken::Bluetooth(_) => Err(WebauthnCError::NotSupported),
#[cfg(feature = "nfc")]
AnyToken::Nfc(_) => Err(WebauthnCError::NotSupported),
#[cfg(feature = "usb")]
AnyToken::Usb(u) => u.get_solokey_lock().await,
}
}

async fn get_solokey_version(&mut self) -> Result<u32, WebauthnCError> {
match self {
AnyToken::Stub => unimplemented!(),
Expand Down
27 changes: 26 additions & 1 deletion webauthn-authenticator-rs/src/usb/solokey.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use uuid::Uuid;
use crate::{
prelude::WebauthnCError,
transport::{
solokey::{SoloKeyToken, CMD_UUID, CMD_VERSION},
solokey::{SoloKeyToken, CMD_LOCK, CMD_UUID, CMD_VERSION},
types::{U2FError, U2FHID_ERROR},
},
usb::framing::U2FHIDFrame,
Expand All @@ -14,6 +14,31 @@ use super::{USBToken, USBTransport};

#[async_trait]
impl SoloKeyToken for USBToken {
async fn get_solokey_lock(&mut self) -> Result<bool, WebauthnCError> {
let cmd = U2FHIDFrame {
cid: self.cid,
cmd: CMD_LOCK,
len: 0,
data: vec![],
};
self.send_one(&cmd).await?;

let r = self.recv_one().await?;
match r.cmd {
CMD_LOCK => {
if r.len != 1 || r.data.len() != 1 {
return Err(WebauthnCError::InvalidMessageLength);
}

Ok(r.data[0] != 0)
}

U2FHID_ERROR => Err(U2FError::from(r.data.as_slice()).into()),

_ => Err(WebauthnCError::UnexpectedState),
}
}

async fn get_solokey_version(&mut self) -> Result<u32, WebauthnCError> {
let cmd = U2FHIDFrame {
cid: self.cid,
Expand Down

0 comments on commit 1c14942

Please sign in to comment.