blob: acf005dd15f325714b152e294ae913095db79ae9 [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"
#import <LocalAuthentication/LocalAuthentication.h>
#include "base/feature_list.h"
#include "base/memory/ptr_util.h"
#include "base/optional.h"
#include "base/strings/string_piece.h"
#include "device/base/features.h"
#include "device/fido/authenticator_selection_criteria.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 (base::FeatureList::IsEnabled(device::kWebAuthTouchId)) {
if (__builtin_available(macOS 10.12.2, *)) {
base::scoped_nsobject<LAContext> context([[LAContext alloc] init]);
return [context
canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
error:nil];
}
}
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;
void TouchIdAuthenticator::MakeCredential(
AuthenticatorSelectionCriteria authenticator_selection_criteria,
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";
}
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)) {}
} // namespace mac
} // namespace fido
} // namespace device