webauthn: remove macOS 10.12 checks
The minimum is 10.13 now. Bug: 1322548 Change-Id: I6e600827733fb24644b5a7a54c22afb8b94df2c4 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3644698 Commit-Queue: Martin Kreichgauer <martinkr@google.com> Auto-Submit: Martin Kreichgauer <martinkr@google.com> Reviewed-by: Nina Satragno <nsatragno@chromium.org> Cr-Commit-Position: refs/heads/main@{#1004521}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
3aaabf4d3a
commit
c25bdf4500
content/browser/webauth
device/fido
cable
mac
authenticator.mmbrowsing_data_deletion_unittest.mmcredential_store.hcredential_store.mmfake_keychain.hfake_touch_id_context.hget_assertion_operation.hget_assertion_operation_unittest_mac.mmkeychain.hkeychain.mmmake_credential_operation.hmake_credential_operation_unittest_mac.mmscoped_touch_id_test_environment.hscoped_touch_id_test_environment.mmtouch_id_context.htouch_id_context.mmutil.hutil.mm
@ -8169,7 +8169,6 @@ TEST_F(TouchIdAuthenticatorImplTest, IsUVPAA) {
|
||||
NavigateAndCommit(GURL(kTestOrigin1));
|
||||
mojo::Remote<blink::mojom::Authenticator> authenticator =
|
||||
ConnectToAuthenticator();
|
||||
|
||||
for (const bool touch_id_available : {false, true}) {
|
||||
SCOPED_TRACE(::testing::Message()
|
||||
<< "touch_id_available=" << touch_id_available);
|
||||
|
@ -275,19 +275,12 @@ void FidoCableDiscovery::OnGetAdapter(scoped_refptr<BluetoothAdapter> adapter) {
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
// TODO(crbug.com/1314404): turn this into a user-visible UI if we believe
|
||||
// that it's a good signal.
|
||||
|
||||
switch (fido::mac::ProcessIsSigned()) {
|
||||
case fido::mac::CodeSigningState::kUnknown:
|
||||
FIDO_LOG(DEBUG) << "Cannot determine whether build is signed. Assuming "
|
||||
"Bluetooth permission is granted.";
|
||||
break;
|
||||
|
||||
case fido::mac::CodeSigningState::kSigned:
|
||||
FIDO_LOG(DEBUG) << "Bluetooth authorized: "
|
||||
<< (adapter_->GetOsPermissionStatus() !=
|
||||
BluetoothAdapter::PermissionStatus::kDenied);
|
||||
break;
|
||||
|
||||
case fido::mac::CodeSigningState::kNotSigned:
|
||||
FIDO_LOG(DEBUG)
|
||||
<< "Build not signed. Assuming Bluetooth permission is granted.";
|
||||
|
@ -36,11 +36,7 @@ namespace mac {
|
||||
void TouchIdAuthenticator::IsAvailable(
|
||||
AuthenticatorConfig config,
|
||||
base::OnceCallback<void(bool is_available)> callback) {
|
||||
if (__builtin_available(macOS 10.12.2, *)) {
|
||||
TouchIdContext::TouchIdAvailable(std::move(config), std::move(callback));
|
||||
return;
|
||||
}
|
||||
std::move(callback).Run(false);
|
||||
TouchIdContext::TouchIdAvailable(std::move(config), std::move(callback));
|
||||
}
|
||||
|
||||
// static
|
||||
@ -61,84 +57,65 @@ void TouchIdAuthenticator::InitializeAuthenticator(base::OnceClosure callback) {
|
||||
void TouchIdAuthenticator::GetCredentialInformationForRequest(
|
||||
const CtapGetAssertionRequest& request,
|
||||
GetCredentialInformationForRequestCallback callback) {
|
||||
if (__builtin_available(macOS 10.12.2, *)) {
|
||||
if (!request.allow_list.empty()) {
|
||||
// Non resident credentials request.
|
||||
absl::optional<std::list<Credential>> credentials =
|
||||
credential_store_.FindCredentialsFromCredentialDescriptorList(
|
||||
request.rp_id, request.allow_list);
|
||||
if (!credentials) {
|
||||
FIDO_LOG(ERROR)
|
||||
<< "FindCredentialsFromCredentialDescriptorList() failed";
|
||||
std::move(callback).Run(/*credentials=*/{}, /*has_credentials=*/false);
|
||||
return;
|
||||
}
|
||||
std::move(callback).Run(/*credentials=*/{},
|
||||
/*has_credentials=*/!credentials->empty());
|
||||
return;
|
||||
}
|
||||
|
||||
// Resident credentials request.
|
||||
absl::optional<std::list<Credential>> resident_credentials =
|
||||
credential_store_.FindResidentCredentials(request.rp_id);
|
||||
if (!resident_credentials) {
|
||||
FIDO_LOG(ERROR) << "GetResidentCredentialsForRequest() failed";
|
||||
if (!request.allow_list.empty()) {
|
||||
// Non resident credentials request.
|
||||
absl::optional<std::list<Credential>> credentials =
|
||||
credential_store_.FindCredentialsFromCredentialDescriptorList(
|
||||
request.rp_id, request.allow_list);
|
||||
if (!credentials) {
|
||||
FIDO_LOG(ERROR) << "FindCredentialsFromCredentialDescriptorList() failed";
|
||||
std::move(callback).Run(/*credentials=*/{}, /*has_credentials=*/false);
|
||||
return;
|
||||
}
|
||||
std::vector<DiscoverableCredentialMetadata> result;
|
||||
for (const auto& credential : *resident_credentials) {
|
||||
absl::optional<CredentialMetadata> metadata =
|
||||
credential_store_.UnsealMetadata(request.rp_id, credential);
|
||||
if (!metadata) {
|
||||
FIDO_LOG(ERROR) << "Could not unseal metadata from resident credential";
|
||||
continue;
|
||||
}
|
||||
result.emplace_back(DiscoverableCredentialMetadata(
|
||||
credential.credential_id,
|
||||
metadata->ToPublicKeyCredentialUserEntity()));
|
||||
}
|
||||
std::move(callback).Run(std::move(result), !resident_credentials->empty());
|
||||
std::move(callback).Run(/*credentials=*/{},
|
||||
/*has_credentials=*/!credentials->empty());
|
||||
return;
|
||||
}
|
||||
NOTREACHED();
|
||||
std::move(callback).Run(/*credentials=*/{}, /*has_credentials=*/false);
|
||||
|
||||
// Resident credentials request.
|
||||
absl::optional<std::list<Credential>> resident_credentials =
|
||||
credential_store_.FindResidentCredentials(request.rp_id);
|
||||
if (!resident_credentials) {
|
||||
FIDO_LOG(ERROR) << "GetResidentCredentialsForRequest() failed";
|
||||
std::move(callback).Run(/*credentials=*/{}, /*has_credentials=*/false);
|
||||
return;
|
||||
}
|
||||
std::vector<DiscoverableCredentialMetadata> result;
|
||||
for (const auto& credential : *resident_credentials) {
|
||||
absl::optional<CredentialMetadata> metadata =
|
||||
credential_store_.UnsealMetadata(request.rp_id, credential);
|
||||
if (!metadata) {
|
||||
FIDO_LOG(ERROR) << "Could not unseal metadata from resident credential";
|
||||
continue;
|
||||
}
|
||||
result.emplace_back(DiscoverableCredentialMetadata(
|
||||
credential.credential_id, metadata->ToPublicKeyCredentialUserEntity()));
|
||||
}
|
||||
std::move(callback).Run(std::move(result), !resident_credentials->empty());
|
||||
}
|
||||
|
||||
void TouchIdAuthenticator::MakeCredential(CtapMakeCredentialRequest request,
|
||||
MakeCredentialOptions options,
|
||||
MakeCredentialCallback callback) {
|
||||
if (__builtin_available(macOS 10.12.2, *)) {
|
||||
DCHECK(!operation_);
|
||||
operation_ = std::make_unique<MakeCredentialOperation>(
|
||||
std::move(request), &credential_store_, std::move(callback));
|
||||
operation_->Run();
|
||||
return;
|
||||
}
|
||||
NOTREACHED();
|
||||
DCHECK(!operation_);
|
||||
operation_ = std::make_unique<MakeCredentialOperation>(
|
||||
std::move(request), &credential_store_, std::move(callback));
|
||||
operation_->Run();
|
||||
}
|
||||
|
||||
void TouchIdAuthenticator::GetAssertion(CtapGetAssertionRequest request,
|
||||
CtapGetAssertionOptions options,
|
||||
GetAssertionCallback callback) {
|
||||
if (__builtin_available(macOS 10.12.2, *)) {
|
||||
DCHECK(!operation_);
|
||||
operation_ = std::make_unique<GetAssertionOperation>(
|
||||
std::move(request), &credential_store_, std::move(callback));
|
||||
operation_->Run();
|
||||
return;
|
||||
}
|
||||
NOTREACHED();
|
||||
DCHECK(!operation_);
|
||||
operation_ = std::make_unique<GetAssertionOperation>(
|
||||
std::move(request), &credential_store_, std::move(callback));
|
||||
operation_->Run();
|
||||
}
|
||||
|
||||
void TouchIdAuthenticator::GetNextAssertion(GetAssertionCallback callback) {
|
||||
if (__builtin_available(macOS 10.12.2, *)) {
|
||||
DCHECK(operation_);
|
||||
reinterpret_cast<GetAssertionOperation*>(operation_.get())
|
||||
->GetNextAssertion(std::move(callback));
|
||||
return;
|
||||
}
|
||||
NOTREACHED();
|
||||
DCHECK(operation_);
|
||||
reinterpret_cast<GetAssertionOperation*>(operation_.get())
|
||||
->GetNextAssertion(std::move(callback));
|
||||
}
|
||||
|
||||
void TouchIdAuthenticator::Cancel() {
|
||||
|
@ -71,22 +71,18 @@ base::ScopedCFTypeRef<CFMutableDictionaryRef> BaseQuery() {
|
||||
// profile they are associated with. May return a null reference if an error
|
||||
// occurred.
|
||||
base::ScopedCFTypeRef<CFArrayRef> QueryAllCredentials() {
|
||||
if (__builtin_available(macOS 10.12.2, *)) {
|
||||
base::ScopedCFTypeRef<CFArrayRef> items;
|
||||
OSStatus status = Keychain::GetInstance().ItemCopyMatching(
|
||||
BaseQuery(), reinterpret_cast<CFTypeRef*>(items.InitializeInto()));
|
||||
if (status == errSecItemNotFound) {
|
||||
// The API returns null, but we should return an empty array instead to
|
||||
// distinguish from real errors.
|
||||
items = base::ScopedCFTypeRef<CFArrayRef>(
|
||||
CFArrayCreate(nullptr, nullptr, 0, nullptr));
|
||||
} else if (status != errSecSuccess) {
|
||||
OSSTATUS_DLOG(ERROR, status);
|
||||
}
|
||||
return items;
|
||||
base::ScopedCFTypeRef<CFArrayRef> items;
|
||||
OSStatus status = Keychain::GetInstance().ItemCopyMatching(
|
||||
BaseQuery(), reinterpret_cast<CFTypeRef*>(items.InitializeInto()));
|
||||
if (status == errSecItemNotFound) {
|
||||
// The API returns null, but we should return an empty array instead to
|
||||
// distinguish from real errors.
|
||||
items = base::ScopedCFTypeRef<CFArrayRef>(
|
||||
CFArrayCreate(nullptr, nullptr, 0, nullptr));
|
||||
} else if (status != errSecSuccess) {
|
||||
OSSTATUS_DLOG(ERROR, status);
|
||||
}
|
||||
NOTREACHED();
|
||||
return base::ScopedCFTypeRef<CFArrayRef>(nullptr);
|
||||
return items;
|
||||
}
|
||||
|
||||
// Returns the number of WebAuthn credentials in the keychain (for all
|
||||
@ -97,16 +93,12 @@ ssize_t KeychainItemCount() {
|
||||
}
|
||||
|
||||
bool ResetKeychain() {
|
||||
if (__builtin_available(macOS 10.12.2, *)) {
|
||||
OSStatus status = Keychain::GetInstance().ItemDelete(BaseQuery());
|
||||
if (status != errSecSuccess && status != errSecItemNotFound) {
|
||||
OSSTATUS_DLOG(ERROR, status);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
OSStatus status = Keychain::GetInstance().ItemDelete(BaseQuery());
|
||||
if (status != errSecSuccess && status != errSecItemNotFound) {
|
||||
OSSTATUS_DLOG(ERROR, status);
|
||||
return false;
|
||||
}
|
||||
NOTREACHED();
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
class BrowsingDataDeletionTest : public testing::Test {
|
||||
|
@ -72,7 +72,6 @@ class COMPONENT_EXPORT(DEVICE_FIDO) TouchIdCredentialStore
|
||||
// CreateCredential inserts a new credential into the keychain. It returns
|
||||
// the new credential and its public key, or absl::nullopt if an error
|
||||
// occurred.
|
||||
API_AVAILABLE(macosx(10.12.2))
|
||||
absl::optional<std::pair<Credential, base::ScopedCFTypeRef<SecKeyRef>>>
|
||||
CreateCredential(const std::string& rp_id,
|
||||
const PublicKeyCredentialUserEntity& user,
|
||||
@ -85,7 +84,6 @@ class COMPONENT_EXPORT(DEVICE_FIDO) TouchIdCredentialStore
|
||||
// FidoTransportProtocol::kInternal, and if its id() is the credential ID.
|
||||
// The returned credentials may be resident or non-resident. If any
|
||||
// unexpected keychain API error occurs, absl::nullopt is returned instead.
|
||||
API_AVAILABLE(macosx(10.12.2))
|
||||
absl::optional<std::list<Credential>>
|
||||
FindCredentialsFromCredentialDescriptorList(
|
||||
const std::string& rp_id,
|
||||
@ -93,13 +91,11 @@ class COMPONENT_EXPORT(DEVICE_FIDO) TouchIdCredentialStore
|
||||
|
||||
// FindResidentCredentials returns the resident credentials for the given
|
||||
// |rp_id|, or base::nulltopt if an error occurred.
|
||||
API_AVAILABLE(macosx(10.12.2))
|
||||
absl::optional<std::list<Credential>> FindResidentCredentials(
|
||||
const std::string& rp_id) const;
|
||||
|
||||
// UnsealMetadata returns the CredentialMetadata for the given credential's
|
||||
// ID if it was encoded for the given RP ID, or absl::nullopt otherwise.
|
||||
API_AVAILABLE(macosx(10.12.2))
|
||||
absl::optional<CredentialMetadata> UnsealMetadata(
|
||||
const std::string& rp_id,
|
||||
const Credential& credential) const;
|
||||
@ -107,7 +103,6 @@ class COMPONENT_EXPORT(DEVICE_FIDO) TouchIdCredentialStore
|
||||
// DeleteCredentialsForUserId deletes all (resident or non-resident)
|
||||
// credentials for the given RP and user ID. Returns true if deleting
|
||||
// succeeded or no matching credential exists, and false otherwise.
|
||||
API_AVAILABLE(macosx(10.12.2))
|
||||
bool DeleteCredentialsForUserId(const std::string& rp_id,
|
||||
base::span<const uint8_t> user_id) const;
|
||||
|
||||
@ -129,7 +124,6 @@ class COMPONENT_EXPORT(DEVICE_FIDO) TouchIdCredentialStore
|
||||
base::Time created_not_after);
|
||||
|
||||
private:
|
||||
API_AVAILABLE(macosx(10.12.2))
|
||||
absl::optional<std::list<Credential>> FindCredentialsImpl(
|
||||
const std::string& rp_id,
|
||||
const std::set<std::vector<uint8_t>>& credential_ids) const;
|
||||
|
@ -72,8 +72,7 @@ absl::optional<std::vector<base::ScopedCFTypeRef<CFDictionaryRef>>>
|
||||
QueryKeychainItemsForProfile(const std::string& keychain_access_group,
|
||||
const std::string& metadata_secret,
|
||||
base::Time created_not_before,
|
||||
base::Time created_not_after)
|
||||
API_AVAILABLE(macosx(10.12.2)) {
|
||||
base::Time created_not_after) {
|
||||
// Query the keychain for all items tagged with the given access group, which
|
||||
// should in theory yield all WebAuthentication credentials (for all
|
||||
// profiles). Sadly, the kSecAttrAccessGroup filter doesn't quite work, and
|
||||
@ -149,69 +148,6 @@ QueryKeychainItemsForProfile(const std::string& keychain_access_group,
|
||||
return result;
|
||||
}
|
||||
|
||||
bool DoDeleteWebAuthnCredentials(const std::string& keychain_access_group,
|
||||
const std::string& metadata_secret,
|
||||
base::Time created_not_before,
|
||||
base::Time created_not_after)
|
||||
API_AVAILABLE(macosx(10.12.2)) {
|
||||
bool result = true;
|
||||
absl::optional<std::vector<base::ScopedCFTypeRef<CFDictionaryRef>>>
|
||||
keychain_items =
|
||||
QueryKeychainItemsForProfile(keychain_access_group, metadata_secret,
|
||||
created_not_before, created_not_after);
|
||||
if (!keychain_items) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The sane way to delete this item would be to build a query that has the
|
||||
// kSecMatchItemList field set to a list of SecKeyRef objects that need
|
||||
// deleting. Sadly, on macOS that appears to work only if you also set
|
||||
// kSecAttrNoLegacy (which is an internal symbol); otherwise it appears to
|
||||
// only search the "legacy" keychain and return errSecItemNotFound. What
|
||||
// does work however, is to look up and delete by the (unique)
|
||||
// kSecAttrApplicationLabel (which stores the credential id). So we clumsily
|
||||
// do this for each item instead.
|
||||
for (const base::ScopedCFTypeRef<CFDictionaryRef>& attributes :
|
||||
*keychain_items) {
|
||||
CFDataRef sec_attr_app_label = base::mac::GetValueFromDictionary<CFDataRef>(
|
||||
attributes.get(), kSecAttrApplicationLabel);
|
||||
if (!sec_attr_app_label) {
|
||||
DLOG(ERROR) << "missing application label";
|
||||
continue;
|
||||
}
|
||||
base::ScopedCFTypeRef<CFMutableDictionaryRef> delete_query(
|
||||
CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
|
||||
&kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks));
|
||||
CFDictionarySetValue(delete_query, kSecClass, kSecClassKey);
|
||||
CFDictionarySetValue(delete_query, kSecAttrApplicationLabel,
|
||||
sec_attr_app_label);
|
||||
OSStatus status = Keychain::GetInstance().ItemDelete(delete_query);
|
||||
if (status != errSecSuccess) {
|
||||
OSSTATUS_DLOG(ERROR, status) << "SecItemDelete failed";
|
||||
result = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t DoCountWebAuthnCredentials(const std::string& keychain_access_group,
|
||||
const std::string& metadata_secret,
|
||||
base::Time created_not_before,
|
||||
base::Time created_not_after)
|
||||
API_AVAILABLE(macosx(10.12.2)) {
|
||||
absl::optional<std::vector<base::ScopedCFTypeRef<CFDictionaryRef>>>
|
||||
keychain_items =
|
||||
QueryKeychainItemsForProfile(keychain_access_group, metadata_secret,
|
||||
created_not_before, created_not_after);
|
||||
if (!keychain_items) {
|
||||
DLOG(ERROR) << "Failed to query credentials in keychain";
|
||||
return 0;
|
||||
}
|
||||
|
||||
return keychain_items->size();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
Credential::Credential(base::ScopedCFTypeRef<SecKeyRef> private_key_,
|
||||
@ -366,28 +302,62 @@ void TouchIdCredentialStore::CountCredentials(
|
||||
bool TouchIdCredentialStore::DeleteCredentialsSync(
|
||||
base::Time created_not_before,
|
||||
base::Time created_not_after) {
|
||||
// Touch ID uses macOS APIs available in 10.12.2 or newer. No need to check
|
||||
// for credentials in lower OS versions.
|
||||
if (__builtin_available(macos 10.12.2, *)) {
|
||||
return DoDeleteWebAuthnCredentials(config_.keychain_access_group,
|
||||
config_.metadata_secret,
|
||||
created_not_before, created_not_after);
|
||||
absl::optional<std::vector<base::ScopedCFTypeRef<CFDictionaryRef>>>
|
||||
keychain_items = QueryKeychainItemsForProfile(
|
||||
config_.keychain_access_group, config_.metadata_secret,
|
||||
created_not_before, created_not_after);
|
||||
if (!keychain_items) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
// The sane way to delete this item would be to build a query that has the
|
||||
// kSecMatchItemList field set to a list of SecKeyRef objects that need
|
||||
// deleting. Sadly, on macOS that appears to work only if you also set
|
||||
// kSecAttrNoLegacy (which is an internal symbol); otherwise it appears to
|
||||
// only search the "legacy" keychain and return errSecItemNotFound. What
|
||||
// does work however, is to look up and delete by the (unique)
|
||||
// kSecAttrApplicationLabel (which stores the credential id). So we clumsily
|
||||
// do this for each item instead.
|
||||
bool result = true;
|
||||
for (const base::ScopedCFTypeRef<CFDictionaryRef>& attributes :
|
||||
*keychain_items) {
|
||||
CFDataRef sec_attr_app_label = base::mac::GetValueFromDictionary<CFDataRef>(
|
||||
attributes.get(), kSecAttrApplicationLabel);
|
||||
if (!sec_attr_app_label) {
|
||||
DLOG(ERROR) << "missing application label";
|
||||
continue;
|
||||
}
|
||||
base::ScopedCFTypeRef<CFMutableDictionaryRef> delete_query(
|
||||
CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
|
||||
&kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks));
|
||||
CFDictionarySetValue(delete_query, kSecClass, kSecClassKey);
|
||||
CFDictionarySetValue(delete_query, kSecAttrApplicationLabel,
|
||||
sec_attr_app_label);
|
||||
OSStatus status = Keychain::GetInstance().ItemDelete(delete_query);
|
||||
if (status != errSecSuccess) {
|
||||
// Indicate failure but keep deleting remaining items.
|
||||
OSSTATUS_DLOG(ERROR, status) << "SecItemDelete failed";
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t TouchIdCredentialStore::CountCredentialsSync(
|
||||
base::Time created_not_before,
|
||||
base::Time created_not_after) {
|
||||
if (__builtin_available(macos 10.12.2, *)) {
|
||||
return DoCountWebAuthnCredentials(config_.keychain_access_group,
|
||||
config_.metadata_secret,
|
||||
created_not_before, created_not_after);
|
||||
absl::optional<std::vector<base::ScopedCFTypeRef<CFDictionaryRef>>>
|
||||
keychain_items = QueryKeychainItemsForProfile(
|
||||
config_.keychain_access_group, config_.metadata_secret,
|
||||
created_not_before, created_not_after);
|
||||
if (!keychain_items) {
|
||||
DLOG(ERROR) << "Failed to query credentials in keychain";
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
return keychain_items->size();
|
||||
}
|
||||
|
||||
API_AVAILABLE(macosx(10.12.2))
|
||||
absl::optional<std::list<Credential>>
|
||||
TouchIdCredentialStore::FindCredentialsImpl(
|
||||
const std::string& rp_id,
|
||||
|
@ -15,7 +15,7 @@ namespace device {
|
||||
namespace fido {
|
||||
namespace mac {
|
||||
|
||||
class API_AVAILABLE(macos(10.12.2)) FakeKeychain : public Keychain {
|
||||
class FakeKeychain : public Keychain {
|
||||
public:
|
||||
struct Item {
|
||||
Item();
|
||||
|
@ -12,8 +12,7 @@ namespace device {
|
||||
namespace fido {
|
||||
namespace mac {
|
||||
|
||||
class API_AVAILABLE(macosx(10.12.2)) FakeTouchIdContext
|
||||
: public TouchIdContext {
|
||||
class FakeTouchIdContext : public TouchIdContext {
|
||||
public:
|
||||
FakeTouchIdContext(const FakeTouchIdContext&) = delete;
|
||||
FakeTouchIdContext& operator=(const FakeTouchIdContext&) = delete;
|
||||
|
@ -28,8 +28,7 @@ namespace mac {
|
||||
//
|
||||
// For documentation on the keychain item metadata, see
|
||||
// |MakeCredentialOperation|.
|
||||
class API_AVAILABLE(macosx(10.12.2))
|
||||
COMPONENT_EXPORT(DEVICE_FIDO) GetAssertionOperation : public Operation {
|
||||
class COMPONENT_EXPORT(DEVICE_FIDO) GetAssertionOperation : public Operation {
|
||||
public:
|
||||
using Callback = base::OnceCallback<void(
|
||||
CtapDeviceResponseCode,
|
||||
|
@ -36,7 +36,7 @@ CtapGetAssertionRequest MakeTestRequest() {
|
||||
return CtapGetAssertionRequest(kRpId, test_data::kClientDataJson);
|
||||
}
|
||||
|
||||
bool MakeCredential() API_AVAILABLE(macos(10.12.2)) {
|
||||
bool MakeCredential() {
|
||||
TestCallbackReceiver<CtapDeviceResponseCode,
|
||||
absl::optional<AuthenticatorMakeCredentialResponse>>
|
||||
callback_receiver;
|
||||
@ -62,8 +62,7 @@ bool MakeCredential() API_AVAILABLE(macos(10.12.2)) {
|
||||
// For demo purposes only. This test does a Touch ID user prompt. It will fail
|
||||
// on incompatible hardware and crash if not code signed or lacking the
|
||||
// keychain-access-group entitlement.
|
||||
TEST(GetAssertionOperationTest, DISABLED_TestRun)
|
||||
API_AVAILABLE(macos(10.12.2)) {
|
||||
TEST(GetAssertionOperationTest, DISABLED_TestRun) {
|
||||
base::test::TaskEnvironment task_environment;
|
||||
ASSERT_TRUE(MakeCredential());
|
||||
|
||||
|
@ -25,7 +25,7 @@ namespace mac {
|
||||
// keychain-access-group entitlements, and therefore requires code signing with
|
||||
// a real Apple developer ID. We therefore group these function here, so they
|
||||
// can be mocked out in testing.
|
||||
class COMPONENT_EXPORT(DEVICE_FIDO) API_AVAILABLE(macos(10.12.2)) Keychain {
|
||||
class COMPONENT_EXPORT(DEVICE_FIDO) Keychain {
|
||||
public:
|
||||
static Keychain& GetInstance();
|
||||
|
||||
|
@ -10,8 +10,7 @@ namespace device {
|
||||
namespace fido {
|
||||
namespace mac {
|
||||
|
||||
static API_AVAILABLE(macos(10.12.2)) Keychain* g_keychain_instance_override =
|
||||
nullptr;
|
||||
static Keychain* g_keychain_instance_override = nullptr;
|
||||
|
||||
// static
|
||||
Keychain& Keychain::GetInstance() {
|
||||
|
@ -45,8 +45,7 @@ namespace mac {
|
||||
// (keychain_access_group_), so that they are logically
|
||||
// separate from any other data that Chrome may store in the keychain in
|
||||
// the future.
|
||||
class API_AVAILABLE(macosx(10.12.2))
|
||||
COMPONENT_EXPORT(DEVICE_FIDO) MakeCredentialOperation : public Operation {
|
||||
class COMPONENT_EXPORT(DEVICE_FIDO) MakeCredentialOperation : public Operation {
|
||||
public:
|
||||
using Callback = base::OnceCallback<void(
|
||||
CtapDeviceResponseCode,
|
||||
|
@ -43,8 +43,7 @@ CtapMakeCredentialRequest MakeTestRequest() {
|
||||
// For demo purposes only. This test does a Touch ID user prompt. It will fail
|
||||
// on incompatible hardware and crash if not code signed or lacking the
|
||||
// keychain-access-group entitlement.
|
||||
TEST(MakeCredentialOperationTest, DISABLED_TestRun)
|
||||
API_AVAILABLE(macosx(10.12.2)) {
|
||||
TEST(MakeCredentialOperationTest, DISABLED_TestRun) {
|
||||
base::test::TaskEnvironment task_environment;
|
||||
TestCallbackReceiver<CtapDeviceResponseCode,
|
||||
absl::optional<AuthenticatorMakeCredentialResponse>>
|
||||
|
@ -27,8 +27,7 @@ class TouchIdContext;
|
||||
// - allows faking TouchIdContext instances returned by TouchIdContext to stub
|
||||
// out Touch ID fingerprint prompts.
|
||||
// Overrides are reset when the instance is destroyed.
|
||||
class COMPONENT_EXPORT(DEVICE_FIDO)
|
||||
API_AVAILABLE(macosx(10.12.2)) ScopedTouchIdTestEnvironment {
|
||||
class COMPONENT_EXPORT(DEVICE_FIDO) ScopedTouchIdTestEnvironment {
|
||||
public:
|
||||
ScopedTouchIdTestEnvironment();
|
||||
|
||||
|
@ -18,8 +18,7 @@ namespace device {
|
||||
namespace fido {
|
||||
namespace mac {
|
||||
|
||||
static API_AVAILABLE(macosx(10.12.2))
|
||||
ScopedTouchIdTestEnvironment* g_current_environment = nullptr;
|
||||
static ScopedTouchIdTestEnvironment* g_current_environment = nullptr;
|
||||
|
||||
ScopedTouchIdTestEnvironment::ScopedTouchIdTestEnvironment()
|
||||
: keychain_(std::make_unique<FakeKeychain>()) {
|
||||
|
@ -32,8 +32,7 @@ struct AuthenticatorConfig;
|
||||
// cancel any other pending evaluations with an error. Deleting an instance
|
||||
// will invalidate any pending evaluation prompts (i.e. the dialog will
|
||||
// disappear and evaluation will fail with an error).
|
||||
class COMPONENT_EXPORT(DEVICE_FIDO)
|
||||
API_AVAILABLE(macosx(10.12.2)) TouchIdContext {
|
||||
class COMPONENT_EXPORT(DEVICE_FIDO) TouchIdContext {
|
||||
public:
|
||||
// The callback is invoked when the local user authentication prompt
|
||||
// completes. It receives a boolean indicating whether obtaining the
|
||||
|
@ -29,7 +29,6 @@ namespace mac {
|
||||
|
||||
namespace {
|
||||
|
||||
API_AVAILABLE(macosx(10.12.2))
|
||||
base::ScopedCFTypeRef<SecAccessControlRef> DefaultAccessControl() {
|
||||
// The default access control policy used for WebAuthn credentials stored by
|
||||
// the Touch ID platform authenticator.
|
||||
@ -70,7 +69,6 @@ bool ExecutableHasKeychainAccessGroupEntitlement(
|
||||
|
||||
// Returns whether creating a key pair in the secure enclave succeeds. Keys are
|
||||
// not persisted to the keychain.
|
||||
API_AVAILABLE(macosx(10.12.2))
|
||||
bool CanCreateSecureEnclaveKeyPairBlocking() {
|
||||
base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
|
||||
base::BlockingType::MAY_BLOCK);
|
||||
|
@ -50,23 +50,20 @@ AuthenticatorData MakeAuthenticatorData(
|
||||
absl::optional<std::vector<uint8_t>> GenerateSignature(
|
||||
const AuthenticatorData& authenticator_data,
|
||||
base::span<const uint8_t, kClientDataHashLength> client_data_hash,
|
||||
SecKeyRef private_key) API_AVAILABLE(macosx(10.12.2));
|
||||
SecKeyRef private_key);
|
||||
|
||||
// SecKeyRefToECPublicKey converts a SecKeyRef for a public key into an
|
||||
// equivalent |PublicKey| instance. It returns |nullptr| if the key cannot
|
||||
// be converted.
|
||||
std::unique_ptr<PublicKey> SecKeyRefToECPublicKey(SecKeyRef public_key_ref)
|
||||
API_AVAILABLE(macosx(10.12.2));
|
||||
std::unique_ptr<PublicKey> SecKeyRefToECPublicKey(SecKeyRef public_key_ref);
|
||||
|
||||
enum class CodeSigningState {
|
||||
kSigned,
|
||||
kNotSigned,
|
||||
kUnknown,
|
||||
};
|
||||
|
||||
// ProcessIsSigned returns `kSigned` if the current process has been code
|
||||
// signed, `kNotSigned` if not, or `kUnknown` if the signing status cannot be
|
||||
// determined. (The latter will always happen on macOS < 10.12.)
|
||||
// ProcessIsSigned returns whether the current process has been code
|
||||
// signed.
|
||||
CodeSigningState ProcessIsSigned();
|
||||
|
||||
} // namespace mac
|
||||
|
@ -102,7 +102,7 @@ AuthenticatorData MakeAuthenticatorData(
|
||||
absl::optional<std::vector<uint8_t>> GenerateSignature(
|
||||
const AuthenticatorData& authenticator_data,
|
||||
base::span<const uint8_t, kClientDataHashLength> client_data_hash,
|
||||
SecKeyRef private_key) API_AVAILABLE(macosx(10.12.2)) {
|
||||
SecKeyRef private_key) {
|
||||
const std::vector<uint8_t> serialized_authenticator_data =
|
||||
authenticator_data.SerializeToByteArray();
|
||||
size_t capacity =
|
||||
@ -130,8 +130,7 @@ absl::optional<std::vector<uint8_t>> GenerateSignature(
|
||||
// SecKeyRefToECPublicKey converts a SecKeyRef for a public key into an
|
||||
// equivalent |PublicKey| instance. It returns |nullptr| if the key cannot
|
||||
// be converted.
|
||||
std::unique_ptr<PublicKey> SecKeyRefToECPublicKey(SecKeyRef public_key_ref)
|
||||
API_AVAILABLE(macosx(10.12.2)) {
|
||||
std::unique_ptr<PublicKey> SecKeyRefToECPublicKey(SecKeyRef public_key_ref) {
|
||||
CHECK(public_key_ref);
|
||||
ScopedCFTypeRef<CFErrorRef> err;
|
||||
ScopedCFTypeRef<CFDataRef> data_ref(
|
||||
@ -153,22 +152,9 @@ std::unique_ptr<PublicKey> SecKeyRefToECPublicKey(SecKeyRef public_key_ref)
|
||||
}
|
||||
|
||||
CodeSigningState ProcessIsSigned() {
|
||||
// SecTaskCopySigningIdentifier is not decorated with availability attributes
|
||||
// in the header, but it was only introduced in 10.12. For prior versions,
|
||||
// `nullopt` is returned to indicate that the signing status of the process
|
||||
// is unknown.
|
||||
//
|
||||
// `@available` cannot be negated, so the code is a little awkward around
|
||||
// that.
|
||||
|
||||
base::ScopedCFTypeRef<SecTaskRef> task;
|
||||
if (@available(macOS 10.12, *)) {
|
||||
task.reset(SecTaskCreateFromSelf(nullptr));
|
||||
if (!task) {
|
||||
return CodeSigningState::kNotSigned;
|
||||
}
|
||||
} else {
|
||||
return CodeSigningState::kUnknown;
|
||||
base::ScopedCFTypeRef<SecTaskRef> task(SecTaskCreateFromSelf(nullptr));
|
||||
if (!task) {
|
||||
return CodeSigningState::kNotSigned;
|
||||
}
|
||||
|
||||
base::ScopedCFTypeRef<CFStringRef> sign_id(
|
||||
|
Reference in New Issue
Block a user