This commit is contained in:
J.C. Jones 2020-08-17 16:03:55 -07:00
Родитель 10b1615903
Коммит 8c58b447bd
7 изменённых файлов: 171 добавлений и 3 удалений

Просмотреть файл

@ -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;