blob: 6d871cdf3e7c798922e19053dc28b274d1dd45d6 [file] [log] [blame]
// Copyright (c) 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "device/fido/mac/authenticator.h"
#include <algorithm>
#import <LocalAuthentication/LocalAuthentication.h>
#include "base/bind.h"
#include "base/feature_list.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/optional.h"
#include "base/stl_util.h"
#include "base/strings/string_piece.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "device/base/features.h"
#include "device/fido/authenticator_supported_options.h"
#include "device/fido/ctap_get_assertion_request.h"
#include "device/fido/ctap_make_credential_request.h"
#include "device/fido/fido_constants.h"
#include "device/fido/mac/get_assertion_operation.h"
#include "device/fido/mac/make_credential_operation.h"
#include "device/fido/mac/util.h"
namespace device {
namespace fido {
namespace mac {
// static
bool TouchIdAuthenticator::IsAvailable() {
if (__builtin_available(macOS 10.12.2, *)) {
return TouchIdContext::TouchIdAvailable();
}
return false;
}
// static
std::unique_ptr<TouchIdAuthenticator> TouchIdAuthenticator::CreateIfAvailable(
std::string keychain_access_group,
std::string metadata_secret) {
// N.B. IsAvailable also checks for the feature flag being set.
return IsAvailable() ? base::WrapUnique(new TouchIdAuthenticator(
std::move(keychain_access_group),
std::move(metadata_secret)))
: nullptr;
}
// static
std::unique_ptr<TouchIdAuthenticator> TouchIdAuthenticator::CreateForTesting(
std::string keychain_access_group,
std::string metadata_secret) {
return base::WrapUnique(new TouchIdAuthenticator(
std::move(keychain_access_group), std::move(metadata_secret)));
}
TouchIdAuthenticator::~TouchIdAuthenticator() = default;
bool TouchIdAuthenticator::HasCredentialForGetAssertionRequest(
const CtapGetAssertionRequest& request) {
if (__builtin_available(macOS 10.12.2, *)) {
std::set<std::vector<uint8_t>> allow_list_credential_ids;
// Extract applicable credential IDs from the allowList, if the request has
// one. If not, any credential matching the RP works.
if (request.allow_list()) {
for (const auto& credential_descriptor : *request.allow_list()) {
if (credential_descriptor.credential_type() !=
CredentialType::kPublicKey)
continue;
if (!credential_descriptor.transports().empty() &&
!base::ContainsKey(credential_descriptor.transports(),
FidoTransportProtocol::kInternal))
continue;
allow_list_credential_ids.insert(credential_descriptor.id());
}
}
return FindCredentialInKeychain(keychain_access_group_, metadata_secret_,
request.rp_id(), allow_list_credential_ids,
nullptr /* LAContext */) != base::nullopt;
}
NOTREACHED();
return false;
}
void TouchIdAuthenticator::InitializeAuthenticator(base::OnceClosure callback) {
base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
std::move(callback));
}
void TouchIdAuthenticator::MakeCredential(CtapMakeCredentialRequest request,
MakeCredentialCallback callback) {
if (__builtin_available(macOS 10.12.2, *)) {
DCHECK(!operation_);
operation_ = std::make_unique<MakeCredentialOperation>(
std::move(request), metadata_secret_, keychain_access_group_,
std::move(callback));
operation_->Run();
return;
}
NOTREACHED();
}
void TouchIdAuthenticator::GetAssertion(CtapGetAssertionRequest request,
GetAssertionCallback callback) {
if (__builtin_available(macOS 10.12.2, *)) {
DCHECK(!operation_);
operation_ = std::make_unique<GetAssertionOperation>(
std::move(request), metadata_secret_, keychain_access_group_,
std::move(callback));
operation_->Run();
return;
}
NOTREACHED();
}
void TouchIdAuthenticator::Cancel() {
// If there is an operation pending, delete it, which will clean up any
// pending callbacks, e.g. if the operation is waiting for a response from
// the Touch ID prompt. Note that we cannot cancel the actual prompt once it
// has been shown.
operation_.reset();
}
std::string TouchIdAuthenticator::GetId() const {
return "TouchIdAuthenticator";
}
base::string16 TouchIdAuthenticator::GetDisplayName() const {
return base::string16();
}
base::Optional<FidoTransportProtocol>
TouchIdAuthenticator::AuthenticatorTransport() const {
return FidoTransportProtocol::kInternal;
}
namespace {
AuthenticatorSupportedOptions TouchIdAuthenticatorOptions() {
AuthenticatorSupportedOptions options;
options.is_platform_device = true;
options.supports_resident_key = true;
options.user_verification_availability = AuthenticatorSupportedOptions::
UserVerificationAvailability::kSupportedAndConfigured;
options.supports_user_presence = true;
return options;
}
} // namespace
const base::Optional<AuthenticatorSupportedOptions>&
TouchIdAuthenticator::Options() const {
static const base::Optional<AuthenticatorSupportedOptions> options =
TouchIdAuthenticatorOptions();
return options;
}
bool TouchIdAuthenticator::IsInPairingMode() const {
return false;
}
bool TouchIdAuthenticator::IsPaired() const {
return false;
}
base::WeakPtr<FidoAuthenticator> TouchIdAuthenticator::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
TouchIdAuthenticator::TouchIdAuthenticator(std::string keychain_access_group,
std::string metadata_secret)
: keychain_access_group_(std::move(keychain_access_group)),
metadata_secret_(std::move(metadata_secret)),
weak_factory_(this) {}
} // namespace mac
} // namespace fido
} // namespace device