blob: d6be983953dfe7697eaa913f6f329ac225587339 [file] [log] [blame]
// Copyright 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 "components/os_crypt/encryption_key_creation_util_mac.h"
#include "base/bind.h"
#include "base/feature_list.h"
#include "base/logging.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/user_metrics.h"
#include "base/single_thread_task_runner.h"
#include "components/os_crypt/keychain_password_mac.h"
#include "components/os_crypt/os_crypt_pref_names_mac.h"
#include "components/prefs/pref_service.h"
#include "crypto/apple_keychain.h"
namespace os_crypt {
using GetKeyAction = EncryptionKeyCreationUtil::GetKeyAction;
namespace {
void LogGetEncryptionKeyActionMetric(
EncryptionKeyCreationUtil::GetKeyAction action) {
UMA_HISTOGRAM_ENUMERATION("OSCrypt.GetEncryptionKeyAction", action);
}
} // namespace
EncryptionKeyCreationUtilMac::EncryptionKeyCreationUtilMac(
PrefService* local_state,
scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner)
: local_state_(local_state),
main_thread_task_runner_(main_thread_task_runner),
key_already_created_(local_state_->GetBoolean(prefs::kKeyCreated)) {}
EncryptionKeyCreationUtilMac::~EncryptionKeyCreationUtilMac() = default;
void EncryptionKeyCreationUtilMac::OnKeyWasFound() {
if (key_already_created_) {
LogGetEncryptionKeyActionMetric(GetKeyAction::kKeyFound);
} else {
LogGetEncryptionKeyActionMetric(GetKeyAction::kKeyFoundFirstTime);
}
UpdateKeyCreationPreference();
}
void EncryptionKeyCreationUtilMac::OnKeyNotFound(
const crypto::AppleKeychain& keychain) {
if (!key_already_created_)
return;
// Make another request to the Keychain without decrypting the password value.
// It should succeed even if the user locked the Keychain.
SecKeychainItemRef item_ref = 0;
OSStatus error = keychain.FindGenericPassword(
strlen(KeychainPassword::service_name), KeychainPassword::service_name,
strlen(KeychainPassword::account_name), KeychainPassword::account_name,
nullptr, nullptr, &item_ref);
if (item_ref)
CFRelease(item_ref);
FindPasswordResult result = FindPasswordResult::kOtherError;
if (error == noErr)
result = FindPasswordResult::kFound;
else if (error == errSecItemNotFound)
result = FindPasswordResult::kNotFound;
UMA_HISTOGRAM_ENUMERATION("OSCrypt.FindPasswordAgain", result);
}
void EncryptionKeyCreationUtilMac::OnKeyStored(bool new_key_stored) {
if (key_already_created_) {
if (new_key_stored)
LogGetEncryptionKeyActionMetric(GetKeyAction::kKeyPotentiallyOverwritten);
else
LogGetEncryptionKeyActionMetric(GetKeyAction::kKeyOverwriteFailed);
} else {
if (new_key_stored) {
LogGetEncryptionKeyActionMetric(GetKeyAction::kNewKeyAddedToKeychain);
UpdateKeyCreationPreference();
} else {
LogGetEncryptionKeyActionMetric(GetKeyAction::kNewKeyAddError);
}
}
}
void EncryptionKeyCreationUtilMac::OnKeychainLookupFailed(int error) {
LogGetEncryptionKeyActionMetric(GetKeyAction::kKeychainLookupFailed);
base::UmaHistogramSparse("OSCrypt.EncryptionKeyLookupError", error);
}
void EncryptionKeyCreationUtilMac::UpdateKeyCreationPreference() {
if (key_already_created_)
return;
key_already_created_ = true;
main_thread_task_runner_->PostTask(
FROM_HERE, base::BindOnce(
[](PrefService* local_state) {
local_state->SetBoolean(prefs::kKeyCreated, true);
},
local_state_));
}
} // namespace os_crypt