MacOS TouchID token WIP
This commit is contained in:
Родитель
10b1615903
Коммит
8c58b447bd
|
@ -15,7 +15,7 @@ maintenance = { status = "actively-developed" }
|
|||
|
||||
[features]
|
||||
binding-recompile = ["bindgen"]
|
||||
webdriver = ["base64", "warp", "tokio", "serde"]
|
||||
webdriver = ["warp", "tokio", "serde"]
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
libudev = "^0.2"
|
||||
|
@ -25,6 +25,7 @@ devd-rs = "0.3"
|
|||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
core-foundation = "0.9"
|
||||
keychain-services = "0.1.1"
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies.winapi]
|
||||
version = "^0.3"
|
||||
|
@ -45,13 +46,12 @@ log = "0.4"
|
|||
libc = "0.2"
|
||||
runloop = "0.1.0"
|
||||
bitflags = "1.0"
|
||||
base64 = "^0.10"
|
||||
tokio = { version = "0.2", optional = true, features = ["macros"] }
|
||||
warp = { version = "0.2.2", optional = true }
|
||||
serde = { version = "1.0", optional = true, features = ["derive"] }
|
||||
base64 = { version = "^0.10", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
sha2 = "^0.8.2"
|
||||
base64 = "^0.10"
|
||||
env_logger = "^0.6"
|
||||
getopts = "^0.2"
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.application-identifier</key>
|
||||
<string>com.mozilla.authenticator-rs</string>
|
||||
<key>keychain-access-groups</key>
|
||||
<array>
|
||||
<string>com.mozilla.authenticator-rs</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
|
@ -40,6 +40,8 @@ fn main() {
|
|||
|
||||
let mut opts = Options::new();
|
||||
opts.optflag("x", "no-u2f-usb-hid", "do not enable u2f-usb-hid platforms");
|
||||
#[cfg(target_os = "macos")]
|
||||
opts.optflag("t", "touchid", "enable MacOS touchID device");
|
||||
#[cfg(feature = "webdriver")]
|
||||
opts.optflag("w", "webdriver", "enable WebDriver virtual bus");
|
||||
|
||||
|
@ -60,6 +62,13 @@ fn main() {
|
|||
manager.add_u2f_usb_hid_platform_transports();
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
if matches.opt_present("touchid") {
|
||||
manager.add_macos_touchid_virtual_device();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "webdriver")]
|
||||
{
|
||||
if matches.opt_present("webdriver") {
|
||||
|
|
|
@ -70,6 +70,9 @@ impl AuthenticatorService {
|
|||
/// Add any detected platform transports
|
||||
pub fn add_detected_transports(&mut self) {
|
||||
self.add_u2f_usb_hid_platform_transports();
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
self.add_macos_touchid_virtual_device();
|
||||
}
|
||||
|
||||
fn add_transport(&mut self, boxed_token: Box<dyn AuthenticatorTransport + Send>) {
|
||||
|
@ -83,6 +86,14 @@ impl AuthenticatorService {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn add_macos_touchid_virtual_device(&mut self) {
|
||||
match crate::virtualdevices::macos_touchid::TouchIDToken::new() {
|
||||
Ok(token) => self.add_transport(Box::new(token)),
|
||||
Err(e) => error!("Could not add MacOS TouchID virtual device: {}", e),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "webdriver")]
|
||||
pub fn add_webdriver_virtual_bus(&mut self) {
|
||||
match crate::virtualdevices::webdriver::VirtualManager::new() {
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
mod touchid_token;
|
||||
pub use touchid_token::TouchIDToken;
|
|
@ -0,0 +1,127 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use crate::authenticatorservice::AuthenticatorTransport;
|
||||
use crate::statecallback::StateCallback;
|
||||
use crate::virtualdevices::software_u2f::SoftwareU2FToken;
|
||||
use crate::{AppId, KeyHandle, RegisterFlags, RegisterResult, SignFlags, SignResult, StatusUpdate};
|
||||
use base64;
|
||||
use keychain_services::*;
|
||||
use rand::{thread_rng, RngCore};
|
||||
use std::sync::mpsc::Sender;
|
||||
use std::{io, thread};
|
||||
|
||||
const TOUCHID_APP_TAG: [u8; 4] = [0xff, 0xff, 0xff, 0xff];
|
||||
|
||||
pub struct TouchIDToken {
|
||||
pub u2f_impl: SoftwareU2FToken,
|
||||
// pub secret: PasswordData,
|
||||
}
|
||||
|
||||
fn map_to_ioerr<T, U>(x: Result<T, U>) -> Result<T, io::Error>
|
||||
where
|
||||
U: std::fmt::Display,
|
||||
{
|
||||
x.map_err(|e| io::Error::new(io::ErrorKind::Other, format!("{}", e)))
|
||||
}
|
||||
|
||||
impl TouchIDToken {
|
||||
pub fn new() -> io::Result<Self> {
|
||||
let service = "example.com";
|
||||
let account = "example";
|
||||
|
||||
let keychain = map_to_ioerr(Keychain::find_default())?;
|
||||
|
||||
let mut flags = AccessControlFlags::new();
|
||||
flags.add(AccessConstraint::BiometryCurrentSet);
|
||||
flags.add(AccessOption::PrivateKeyUsage);
|
||||
|
||||
let ac = map_to_ioerr(AccessControl::create_with_flags(
|
||||
AttrAccessible::WhenPasscodeSetThisDeviceOnly,
|
||||
flags,
|
||||
))?;
|
||||
|
||||
let params = KeyPairGenerateParams::new(AttrKeyType::EcSecPrimeRandom, 256)
|
||||
.application_tag(AttrApplicationTag::new(&TOUCHID_APP_TAG))
|
||||
.access_control(&ac)
|
||||
.token_id(AttrTokenId::SecureEnclave)
|
||||
// .permanent(true)
|
||||
;
|
||||
|
||||
let keypair = KeyPair::generate(params).unwrap();
|
||||
|
||||
let public_key_bytes = keypair.public_key.to_external_representation().unwrap();
|
||||
println!("pubkey: {}", &base64::encode(&public_key_bytes));
|
||||
|
||||
// let secret = match GenericPassword::find(&keychain, &service, &account) {
|
||||
// Ok(recovered_secret) => recovered_secret,
|
||||
// Err(_) => {
|
||||
// let mut keymat = [0u8; 32];
|
||||
// thread_rng().fill_bytes(&mut keymat);
|
||||
// map_to_ioerr(GenericPassword::create(&keychain, &service, &account, &base64::encode(&keymat)))?
|
||||
// }
|
||||
// };
|
||||
|
||||
// println!("password: {}", &base64::encode(&map_to_ioerr(secret.password())?));
|
||||
|
||||
Ok(Self {
|
||||
u2f_impl: SoftwareU2FToken::new(),
|
||||
// secret: map_to_ioerr(secret.password())?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl AuthenticatorTransport for TouchIDToken {
|
||||
fn register(
|
||||
&mut self,
|
||||
flags: RegisterFlags,
|
||||
timeout: u64,
|
||||
challenge: Vec<u8>,
|
||||
application: AppId,
|
||||
key_handles: Vec<KeyHandle>,
|
||||
status: Sender<StatusUpdate>,
|
||||
callback: StateCallback<Result<RegisterResult, crate::Error>>,
|
||||
) -> Result<(), crate::Error> {
|
||||
let result = self
|
||||
.u2f_impl
|
||||
.register(flags, timeout, challenge, application, key_handles);
|
||||
status
|
||||
.send(StatusUpdate::Success {
|
||||
dev_info: self.u2f_impl.dev_info(),
|
||||
})
|
||||
.map_err(|_| crate::Error::Unknown)?;
|
||||
thread::spawn(move || {
|
||||
callback.call(result);
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn sign(
|
||||
&mut self,
|
||||
flags: SignFlags,
|
||||
timeout: u64,
|
||||
challenge: Vec<u8>,
|
||||
app_ids: Vec<AppId>,
|
||||
key_handles: Vec<KeyHandle>,
|
||||
status: Sender<StatusUpdate>,
|
||||
callback: StateCallback<Result<SignResult, crate::Error>>,
|
||||
) -> Result<(), crate::Error> {
|
||||
let result = self
|
||||
.u2f_impl
|
||||
.sign(flags, timeout, challenge, app_ids, key_handles);
|
||||
status
|
||||
.send(StatusUpdate::Success {
|
||||
dev_info: self.u2f_impl.dev_info(),
|
||||
})
|
||||
.map_err(|_| crate::Error::Unknown)?;
|
||||
thread::spawn(move || {
|
||||
callback.call(result);
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn cancel(&mut self) -> Result<(), crate::Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -2,6 +2,9 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub mod macos_touchid;
|
||||
|
||||
#[cfg(feature = "webdriver")]
|
||||
pub mod webdriver;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче