From 5b32c0ca91a155bc3f279008dd213dcbab8672e4 Mon Sep 17 00:00:00 2001 From: Michael Farrell Date: Thu, 26 Oct 2023 11:26:39 +1000 Subject: [PATCH] implement solokey random --- fido-key-manager/src/main.rs | 21 +++++++++++++++- .../src/ctap2/solokey.rs | 14 ++++++++--- .../src/transport/solokey.rs | 17 ++++++++++++- webauthn-authenticator-rs/src/usb/solokey.rs | 24 ++++++++++++++++++- 4 files changed, 70 insertions(+), 6 deletions(-) diff --git a/fido-key-manager/src/main.rs b/fido-key-manager/src/main.rs index 394476e1..d8f41276 100644 --- a/fido-key-manager/src/main.rs +++ b/fido-key-manager/src/main.rs @@ -201,8 +201,11 @@ pub enum Opt { /// Updates user information for a discoverable credential on this token. UpdateCredentialUser(UpdateCredentialUserOpt), #[cfg(feature = "solokey")] - /// Gets info about a connected SoloKey. + /// Gets info about a connected SoloKey 2 or Trussed device. SoloKeyInfo(InfoOpt), + #[cfg(feature = "solokey")] + /// Gets some random bytes from a connected SoloKey 2 or Trussed device. + SoloKeyRandom, } #[derive(Debug, clap::Parser)] @@ -689,6 +692,7 @@ async fn main() { #[cfg(feature = "solokey")] Opt::SoloKeyInfo(o) => { + println!("Looking for SoloKey 2 or Trussed devices..."); while let Some(event) = stream.next().await { match event { TokenEvent::Added(t) => { @@ -697,6 +701,7 @@ async fn main() { None => continue, }; + // TODO: filter this to just SoloKey devices in a safe way let uuid = match authenticator.get_solokey_uuid().await { Ok(v) => v, Err(WebauthnCError::NotSupported) @@ -751,5 +756,19 @@ async fn main() { } } } + + #[cfg(feature = "solokey")] + Opt::SoloKeyRandom => { + // TODO: filter this to just SoloKey devices in a safe way + println!("Insert a SoloKey 2 or Trussed device..."); + let mut token: CtapAuthenticator = + select_one_device(stream, &ui).await.unwrap(); + + let r = token + .get_solokey_random() + .await + .expect("Error getting random data"); + println!("Random bytes: {}", hex::encode(r)); + } } } diff --git a/webauthn-authenticator-rs/src/ctap2/solokey.rs b/webauthn-authenticator-rs/src/ctap2/solokey.rs index 6a44d9d7..d3bee9f2 100644 --- a/webauthn-authenticator-rs/src/ctap2/solokey.rs +++ b/webauthn-authenticator-rs/src/ctap2/solokey.rs @@ -19,13 +19,16 @@ use super::Ctap20Authenticator; /// Protocol notes are in [`crate::transport::solokey`]. #[async_trait] pub trait SoloKeyAuthenticator { - /// Gets the device's lock (secure boot) status. + /// Gets a SoloKey's lock (secure boot) status. async fn get_solokey_lock(&mut self) -> Result; - /// Gets the device-specific UUID of a SoloKey token. + /// Gets some random bytes from a SoloKey. + async fn get_solokey_random(&mut self) -> Result<[u8; 57], WebauthnCError>; + + /// Gets a SoloKey's UUID. async fn get_solokey_uuid(&mut self) -> Result; - /// Gets the version of a SoloKey token. + /// Gets a SoloKey's firmware version. async fn get_solokey_version(&mut self) -> Result; } @@ -38,6 +41,11 @@ impl<'a, T: Token + SoloKeyToken, U: UiCallback> SoloKeyAuthenticator self.token.get_solokey_lock().await } + #[inline] + async fn get_solokey_random(&mut self) -> Result<[u8; 57], WebauthnCError> { + self.token.get_solokey_random().await + } + #[inline] async fn get_solokey_uuid(&mut self) -> Result { self.token.get_solokey_uuid().await diff --git a/webauthn-authenticator-rs/src/transport/solokey.rs b/webauthn-authenticator-rs/src/transport/solokey.rs index 60028736..97e0042f 100644 --- a/webauthn-authenticator-rs/src/transport/solokey.rs +++ b/webauthn-authenticator-rs/src/transport/solokey.rs @@ -33,7 +33,7 @@ use crate::prelude::WebauthnCError; use super::AnyToken; #[cfg(all(feature = "usb", feature = "vendor-solokey"))] -pub const CMD_RAND: u8 = super::TYPE_INIT | 0x60; +pub const CMD_RANDOM: u8 = super::TYPE_INIT | 0x60; #[cfg(all(feature = "usb", feature = "vendor-solokey"))] pub const CMD_VERSION: u8 = super::TYPE_INIT | 0x61; @@ -50,6 +50,9 @@ pub trait SoloKeyToken { /// See [`SoloKeyAuthenticator::get_solokey_lock()`](crate::ctap2::SoloKeyAuthenticator::get_solokey_lock). async fn get_solokey_lock(&mut self) -> Result; + /// See [`SoloKeyAuthenticator::get_solokey_random()`](crate::ctap2::SoloKeyAuthenticator::get_solokey_random). + async fn get_solokey_random(&mut self) -> Result<[u8; 57], WebauthnCError>; + /// See [`SoloKeyAuthenticator::get_solokey_version()`](crate::ctap2::SoloKeyAuthenticator::get_solokey_version). async fn get_solokey_version(&mut self) -> Result; @@ -71,6 +74,18 @@ impl SoloKeyToken for AnyToken { } } + async fn get_solokey_random(&mut self) -> Result<[u8; 57], 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_random().await, + } + } + async fn get_solokey_version(&mut self) -> Result { match self { AnyToken::Stub => unimplemented!(), diff --git a/webauthn-authenticator-rs/src/usb/solokey.rs b/webauthn-authenticator-rs/src/usb/solokey.rs index d5f1697c..7bbb0607 100644 --- a/webauthn-authenticator-rs/src/usb/solokey.rs +++ b/webauthn-authenticator-rs/src/usb/solokey.rs @@ -4,7 +4,7 @@ use uuid::Uuid; use crate::{ prelude::WebauthnCError, transport::{ - solokey::{SoloKeyToken, CMD_LOCK, CMD_UUID, CMD_VERSION}, + solokey::{SoloKeyToken, CMD_LOCK, CMD_RANDOM, CMD_UUID, CMD_VERSION}, types::{U2FError, U2FHID_ERROR}, }, usb::framing::U2FHIDFrame, @@ -39,6 +39,28 @@ impl SoloKeyToken for USBToken { } } + async fn get_solokey_random(&mut self) -> Result<[u8; 57], WebauthnCError> { + let cmd = U2FHIDFrame { + cid: self.cid, + cmd: CMD_RANDOM, + len: 0, + data: vec![], + }; + self.send_one(&cmd).await?; + + let r = self.recv_one().await?; + match r.cmd { + CMD_RANDOM => r + .data + .try_into() + .map_err(|_| WebauthnCError::InvalidMessageLength), + + U2FHID_ERROR => Err(U2FError::from(r.data.as_slice()).into()), + + _ => Err(WebauthnCError::UnexpectedState), + } + } + async fn get_solokey_version(&mut self) -> Result { let cmd = U2FHIDFrame { cid: self.cid,