Skip to content

Commit

Permalink
//device/fido: add TouchIdAuthenticator behind a feature flag
Browse files Browse the repository at this point in the history
This adds the WebAuthenticationTouchId feature flag (default disabled).
If enabled, the FidoRequestHandler tries to instantiate a
TouchIdAuthenticator on supported platforms for the current request.

Bug: 678128
Change-Id: Iddc4ea00b3247b6ffbe875e280e1bf30488ca81f
Reviewed-on: https://chromium-review.googlesource.com/1064921
Commit-Queue: Martin Kreichgauer <martinkr@google.com>
Reviewed-by: Camille Lamy <clamy@chromium.org>
Reviewed-by: Balazs Engedy <engedy@chromium.org>
Reviewed-by: Jan Wilken Dörrie <jdoerrie@chromium.org>
Cr-Commit-Position: refs/heads/master@{#561605}
  • Loading branch information
kreichgauer authored and Commit Bot committed May 24, 2018
1 parent 447cc3f commit fc901c2
Show file tree
Hide file tree
Showing 11 changed files with 103 additions and 29 deletions.
27 changes: 9 additions & 18 deletions content/browser/webauth/authenticator_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "base/logging.h"
#include "base/rand_util.h"
#include "base/timer/timer.h"
#include "build/build_config.h"
#include "content/browser/bad_message.h"
#include "content/browser/webauth/authenticator_type_converters.h"
#include "content/public/browser/content_browser_client.h"
Expand Down Expand Up @@ -335,24 +336,9 @@ std::string Base64UrlEncode(const base::span<const uint8_t> input) {
} // namespace

AuthenticatorImpl::AuthenticatorImpl(RenderFrameHost* render_frame_host)
: WebContentsObserver(WebContents::FromRenderFrameHost(render_frame_host)),
render_frame_host_(render_frame_host),
timer_(std::make_unique<base::OneShotTimer>()),
binding_(this),
weak_factory_(this) {
DCHECK(render_frame_host_);
DCHECK(timer_);

protocols_.insert(device::FidoTransportProtocol::kUsbHumanInterfaceDevice);
if (base::FeatureList::IsEnabled(features::kWebAuthBle)) {
protocols_.insert(device::FidoTransportProtocol::kBluetoothLowEnergy);
}

if (base::FeatureList::IsEnabled(features::kWebAuthCable)) {
protocols_.insert(
device::FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy);
}
}
: AuthenticatorImpl(render_frame_host,
nullptr /* connector */,
std::make_unique<base::OneShotTimer>()) {}

AuthenticatorImpl::AuthenticatorImpl(RenderFrameHost* render_frame_host,
service_manager::Connector* connector,
Expand All @@ -375,6 +361,11 @@ AuthenticatorImpl::AuthenticatorImpl(RenderFrameHost* render_frame_host,
protocols_.insert(
device::FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy);
}
#if defined(OS_MACOSX)
if (base::FeatureList::IsEnabled(features::kWebAuthTouchId)) {
protocols_.insert(device::FidoTransportProtocol::kInternal);
}
#endif
}

AuthenticatorImpl::~AuthenticatorImpl() {}
Expand Down
5 changes: 5 additions & 0 deletions content/public/common/content_features.cc
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,11 @@ const base::Feature kIOSurfaceCapturer{"IOSurfaceCapturer",
// entire life of the process.
const base::Feature kMacV2Sandbox{"MacV2Sandbox",
base::FEATURE_DISABLED_BY_DEFAULT};

// Controls whether the CTAP2 implementation should use a built-in platform
// authenticator, where available.
const base::Feature kWebAuthTouchId{"WebAuthenticationTouchId",
base::FEATURE_DISABLED_BY_DEFAULT};
#endif // defined(OS_MACOSX)

bool IsVideoCaptureServiceEnabledForOutOfProcess() {
Expand Down
3 changes: 2 additions & 1 deletion content/public/common/content_features.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,9 @@ CONTENT_EXPORT extern const base::Feature kWebAssemblyBaseline;
CONTENT_EXPORT extern const base::Feature kWebAssemblyTrapHandler;
CONTENT_EXPORT extern const base::Feature kWebAuth;
CONTENT_EXPORT extern const base::Feature kWebAuthBle;
CONTENT_EXPORT extern const base::Feature kWebContentsOcclusion;
CONTENT_EXPORT extern const base::Feature kWebAuthCtap2;
CONTENT_EXPORT extern const base::Feature kWebAuthCable;
CONTENT_EXPORT extern const base::Feature kWebContentsOcclusion;
CONTENT_EXPORT extern const base::Feature kWebGLImageChromium;
CONTENT_EXPORT extern const base::Feature kWebPayments;
CONTENT_EXPORT extern const base::Feature kWebRtcAecBoundedErlSetup;
Expand Down Expand Up @@ -152,6 +152,7 @@ CONTENT_EXPORT extern const char kWebXrRenderPathParamValueSharedBuffer[];
CONTENT_EXPORT extern const base::Feature kDeviceMonitorMac;
CONTENT_EXPORT extern const base::Feature kIOSurfaceCapturer;
CONTENT_EXPORT extern const base::Feature kMacV2Sandbox;
CONTENT_EXPORT extern const base::Feature kWebAuthTouchId;
#endif // defined(OS_MACOSX)

// DON'T ADD RANDOM STUFF HERE. Put it in the main section above in
Expand Down
3 changes: 3 additions & 0 deletions device/fido/fake_fido_discovery.cc
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ ScopedFakeFidoDiscoveryFactory::CreateFidoDiscovery(
return std::move(next_ble_discovery_);
case FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy:
return std::move(next_cable_discovery_);
case FidoTransportProtocol::kInternal:
NOTREACHED() << "Internal authenticators should be handled separately.";
return nullptr;
}
NOTREACHED();
return nullptr;
Expand Down
5 changes: 4 additions & 1 deletion device/fido/fido_discovery.cc
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,11 @@ std::unique_ptr<FidoDiscovery> CreateFidoDiscoveryImpl(
case FidoTransportProtocol::kNearFieldCommunication:
// TODO(https://crbug.com/825949): Add NFC support.
return nullptr;
case FidoTransportProtocol::kInternal:
NOTREACHED() << "Internal authenticators should be handled separately.";
return nullptr;
}
NOTREACHED();
NOTREACHED() << "Unhandled transport type";
return nullptr;
}

Expand Down
40 changes: 35 additions & 5 deletions device/fido/fido_request_handler_base.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,15 @@
#include <utility>

#include "base/strings/string_piece.h"
#include "build/build_config.h"
#include "device/fido/fido_device.h"
#include "device/fido/fido_task.h"
#include "services/service_manager/public/cpp/connector.h"

#if defined(OS_MACOSX)
#include "device/fido/mac/authenticator.h"
#endif

namespace device {

FidoRequestHandlerBase::FidoRequestHandlerBase(
Expand All @@ -22,6 +27,11 @@ FidoRequestHandlerBase::FidoRequestHandlerBase(
if (transport == FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy)
continue;

if (transport == FidoTransportProtocol::kInternal) {
use_platform_authenticator_ = true;
continue;
}

auto discovery = FidoDiscovery::Create(transport, connector);
if (discovery == nullptr) {
// This can occur in tests when a ScopedVirtualU2fDevice is in effect and
Expand Down Expand Up @@ -54,6 +64,21 @@ void FidoRequestHandlerBase::Start() {
for (const auto& discovery : discoveries_) {
discovery->Start();
}
if (use_platform_authenticator_) {
MaybeAddPlatformAuthenticator();
}
}

void FidoRequestHandlerBase::MaybeAddPlatformAuthenticator() {
#if defined(OS_MACOSX)
if (__builtin_available(macOS 10.12.2, *)) {
auto authenticator = fido::mac::TouchIdAuthenticator::CreateIfAvailable();
if (!authenticator) {
return;
}
AddAuthenticator(std::move(authenticator));
}
#endif
}

void FidoRequestHandlerBase::DiscoveryStarted(FidoDiscovery* discovery,
Expand All @@ -66,11 +91,7 @@ void FidoRequestHandlerBase::DeviceAdded(FidoDiscovery* discovery,
// AuthenticatorGetInfo command is sent to all connected devices. If device
// errors out, then it is assumed to support U2F protocol.
device->set_supported_protocol(ProtocolVersion::kCtap);
auto* authenticator =
active_authenticators_
.emplace(device->GetId(), CreateAuthenticatorFromDevice(device))
.first->second.get();
DispatchRequest(authenticator);
AddAuthenticator(CreateAuthenticatorFromDevice(device));
}

std::unique_ptr<FidoDeviceAuthenticator>
Expand All @@ -88,4 +109,13 @@ void FidoRequestHandlerBase::DeviceRemoved(FidoDiscovery* discovery,
active_authenticators_.erase(device->GetId());
}

void FidoRequestHandlerBase::AddAuthenticator(
std::unique_ptr<FidoAuthenticator> authenticator) {
DCHECK(!base::ContainsKey(active_authenticators(), authenticator->GetId()));
FidoAuthenticator* authenticator_ptr = authenticator.get();
active_authenticators_.emplace(authenticator->GetId(),
std::move(authenticator));
DispatchRequest(authenticator_ptr);
}

} // namespace device
9 changes: 9 additions & 0 deletions device/fido/fido_request_handler_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,18 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoRequestHandlerBase
void DeviceAdded(FidoDiscovery* discovery, FidoDevice* device) final;
void DeviceRemoved(FidoDiscovery* discovery, FidoDevice* device) final;

void AddAuthenticator(std::unique_ptr<FidoAuthenticator> authenticator);

void MaybeAddPlatformAuthenticator();

AuthenticatorMap active_authenticators_;
std::vector<std::unique_ptr<FidoDiscovery>> discoveries_;

// If set to true at any point before calling Start(), the request handler
// will try to create a platform authenticator to handle the request
// (currently only TouchIdAuthenticator on macOS).
bool use_platform_authenticator_ = false;

DISALLOW_COPY_AND_ASSIGN(FidoRequestHandlerBase);
};

Expand Down
1 change: 1 addition & 0 deletions device/fido/fido_transport_protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ enum class FidoTransportProtocol {
kNearFieldCommunication,
kBluetoothLowEnergy,
kCloudAssistedBluetoothLowEnergy,
kInternal,
};

} // namespace device
Expand Down
11 changes: 10 additions & 1 deletion device/fido/mac/authenticator.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,14 @@ namespace mac {
class API_AVAILABLE(macosx(10.12.2)) TouchIdAuthenticator
: public FidoAuthenticator {
public:
TouchIdAuthenticator();
// IsAvailable returns true iff Touch ID is enabled and enrolled on the
// current device.
static bool IsAvailable();

// CreateIfAvailable returns a TouchIdAuthenticator if IsAvailable() returns
// true and nullptr otherwise.
static std::unique_ptr<TouchIdAuthenticator> CreateIfAvailable();

~TouchIdAuthenticator() override;

// TouchIdAuthenticator
Expand All @@ -33,6 +40,8 @@ class API_AVAILABLE(macosx(10.12.2)) TouchIdAuthenticator
std::string GetId() const override;

private:
TouchIdAuthenticator();

// The profile ID identifies the user profile from which the request
// originates. It is used to scope credentials to the profile under which they
// were created.
Expand Down
24 changes: 23 additions & 1 deletion device/fido/mac/authenticator.mm
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

#include "device/fido/mac/authenticator.h"

#import <LocalAuthentication/LocalAuthentication.h>

#include "base/memory/ptr_util.h"
#include "base/optional.h"
#include "base/strings/string_piece.h"
#include "device/fido/authenticator_selection_criteria.h"
Expand All @@ -17,7 +20,24 @@
namespace fido {
namespace mac {

TouchIdAuthenticator::TouchIdAuthenticator() = default;
// static
// NOTE(martinkr): This is currently only called from |CreateIfAvailable| but
// will also be needed for the implementation of
// IsUserVerifyingPlatformAuthenticatorAvailable() (see
// https://www.w3.org/TR/webauthn/#isUserVerifyingPlatformAuthenticatorAvailable).
bool TouchIdAuthenticator::IsAvailable() {
base::scoped_nsobject<LAContext> context([[LAContext alloc] init]);
return
[context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
error:nil];
}

// static
std::unique_ptr<TouchIdAuthenticator>
TouchIdAuthenticator::CreateIfAvailable() {
return IsAvailable() ? base::WrapUnique(new TouchIdAuthenticator()) : nullptr;
}

TouchIdAuthenticator::~TouchIdAuthenticator() = default;

void TouchIdAuthenticator::MakeCredential(
Expand Down Expand Up @@ -52,6 +72,8 @@
return "TouchIdAuthenticator";
}

TouchIdAuthenticator::TouchIdAuthenticator() = default;

base::StringPiece TouchIdAuthenticator::GetOrInitializeProfileId() {
// TODO(martinkr): Implement.
return "TODO";
Expand Down
4 changes: 2 additions & 2 deletions device/fido/mac/touch_id_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ namespace device {
namespace fido {
namespace mac {

// TouchIdContext wraps a Touch ID consent prompt for signing with a secure
// enclave key.
// TouchIdContext wraps a macOS Touch ID consent prompt for signing with a
// secure enclave key.
class API_AVAILABLE(macosx(10.12.2)) TouchIdContext {
public:
// The callback is invoked when the Touch ID prompt completes. It receives a
Expand Down

0 comments on commit fc901c2

Please sign in to comment.