Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4014)

Unified Diff: chrome/browser/password_manager/password_store_mac.cc

Issue 1207373002: Implement Mac Keychain migration algorithm. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Ilya's comments Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/password_manager/password_store_mac.cc
diff --git a/chrome/browser/password_manager/password_store_mac.cc b/chrome/browser/password_manager/password_store_mac.cc
index 13ceae02d4991cf0dd38976bee75bc2e15dc9fb7..ca4253612c156a6e83ef81e5477be40fb1920d37 100644
--- a/chrome/browser/password_manager/password_store_mac.cc
+++ b/chrome/browser/password_manager/password_store_mac.cc
@@ -16,10 +16,12 @@
#include "base/mac/foundation_util.h"
#include "base/mac/mac_logging.h"
#include "base/message_loop/message_loop.h"
+#include "base/metrics/histogram_macros.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/mac/security_wrappers.h"
+#include "components/os_crypt/os_crypt.h"
#include "components/password_manager/core/browser/affiliation_utils.h"
#include "components/password_manager/core/browser/login_database.h"
#include "components/password_manager/core/browser/password_store_change.h"
@@ -435,6 +437,36 @@ bool FillPasswordFormFromKeychainItem(const AppleKeychain& keychain,
return true;
}
+bool HasChromeCreatorCode(const AppleKeychain& keychain,
+ const SecKeychainItemRef& keychain_item) {
+ SecKeychainAttributeInfo attr_info;
+ UInt32 tags[] = {kSecCreatorItemAttr};
+ attr_info.count = arraysize(tags);
+ attr_info.tag = tags;
+ attr_info.format = nullptr;
+
+ SecKeychainAttributeList* attr_list;
+ UInt32 password_length;
+ OSStatus result = keychain.ItemCopyAttributesAndData(
+ keychain_item, &attr_info, nullptr, &attr_list,
+ &password_length, nullptr);
+ if (result != noErr)
+ return false;
+ OSType creator_code = 0;
+ for (unsigned int i = 0; i < attr_list->count; i++) {
+ SecKeychainAttribute attr = attr_list->attr[i];
+ if (!attr.data) {
+ continue;
+ }
+ if (attr.tag == kSecCreatorItemAttr) {
+ creator_code = *(static_cast<FourCharCode*>(attr.data));
+ break;
+ }
+ }
+ keychain.ItemFreeAttributesAndData(attr_list, nullptr);
+ return creator_code && creator_code == base::mac::CreatorCodeForApplication();
+}
+
bool FormsMatchForMerge(const PasswordForm& form_a,
const PasswordForm& form_b,
FormMatchStrictness strictness) {
@@ -922,7 +954,7 @@ PasswordStoreMac::PasswordStoreMac(
: password_manager::PasswordStore(main_thread_runner, db_thread_runner),
keychain_(keychain.Pass()),
login_metadata_db_(login_db) {
- DCHECK(keychain_.get());
+ DCHECK(keychain_);
login_metadata_db_->set_clear_password_values(true);
}
@@ -934,6 +966,89 @@ void PasswordStoreMac::InitWithTaskRunner(
db_thread_runner_ = background_task_runner;
}
+PasswordStoreMac::MigrationResult PasswordStoreMac::ImportFromKeychain() {
+ DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
+ if (!login_metadata_db_)
+ return LOGIN_DB_UNAVAILABLE;
+
+ ScopedVector<PasswordForm> database_forms;
+ if (!login_metadata_db_->GetAutofillableLogins(&database_forms))
+ return LOGIN_DB_FAILURE;
+
+ ScopedVector<PasswordForm> uninteresting_forms;
+ internal_keychain_helpers::ExtractNonKeychainForms(&database_forms,
+ &uninteresting_forms);
+ // If there are no passwords to lookup in the Keychain then we're done.
+ if (database_forms.empty())
+ return MIGRATION_OK;
+
+ // Make sure that the encryption key is retrieved from the Keychain so the
+ // encryption can be done.
+ std::string ciphertext;
+ if (!OSCrypt::EncryptString("test", &ciphertext))
+ return ENCRYPTOR_FAILURE;
+
+ // Mute the Keychain.
+ chrome::ScopedSecKeychainSetUserInteractionAllowed user_interaction_allowed(
+ false);
+
+ // Retrieve the passwords.
+ // Get all the password attributes first.
+ std::vector<SecKeychainItemRef> keychain_items;
+ std::vector<internal_keychain_helpers::ItemFormPair> item_form_pairs =
+ internal_keychain_helpers::
+ ExtractAllKeychainItemAttributesIntoPasswordForms(&keychain_items,
+ *keychain_);
+
+ // Next, compare the attributes of the PasswordForms in |database_forms|
+ // against those in |item_form_pairs|, and extract password data for each
+ // matching PasswordForm using its corresponding SecKeychainItemRef.
+ size_t unmerged_forms_count = 0;
+ size_t chrome_owned_locked_forms_count = 0;
+ for (PasswordForm* form : database_forms) {
+ ScopedVector<autofill::PasswordForm> keychain_matches =
+ internal_keychain_helpers::ExtractPasswordsMergeableWithForm(
+ *keychain_, item_form_pairs, *form);
+
+ const PasswordForm* best_match =
+ BestKeychainFormForForm(*form, keychain_matches.get());
+ if (best_match) {
+ form->password_value = best_match->password_value;
+ } else {
+ unmerged_forms_count++;
+ // Check if any corresponding keychain items are created by Chrome.
+ for (const auto& item_form_pair : item_form_pairs) {
+ if (internal_keychain_helpers::FormIsValidAndMatchesOtherForm(
+ *form, *item_form_pair.second) &&
+ internal_keychain_helpers::HasChromeCreatorCode(
+ *keychain_, *item_form_pair.first))
+ chrome_owned_locked_forms_count++;
+ }
+ }
+ }
+ STLDeleteContainerPairSecondPointers(item_form_pairs.begin(),
+ item_form_pairs.end());
+ for (SecKeychainItemRef item : keychain_items)
+ keychain_->Free(item);
+
+ if (unmerged_forms_count) {
+ UMA_HISTOGRAM_COUNTS(
+ "PasswordManager.KeychainMigration.NumPasswordsOnFailure",
+ database_forms.size());
+ UMA_HISTOGRAM_COUNTS("PasswordManager.KeychainMigration.NumFailedPasswords",
+ unmerged_forms_count);
+ UMA_HISTOGRAM_COUNTS(
+ "PasswordManager.KeychainMigration.NumChromeOwnedInaccessiblePasswords",
+ chrome_owned_locked_forms_count);
+ return KEYCHAIN_BLOCKED;
+ }
+ // Now all the passwords are available. It's time to update LoginDatabase.
+ login_metadata_db_->set_clear_password_values(false);
+ for (PasswordForm* form : database_forms)
+ login_metadata_db_->UpdateLogin(*form);
+ return MIGRATION_OK;
+}
+
bool PasswordStoreMac::Init(
const syncer::SyncableService::StartSyncFlare& flare) {
// The class should be used inside PasswordStoreProxyMac only.
« no previous file with comments | « chrome/browser/password_manager/password_store_mac.h ('k') | chrome/browser/password_manager/password_store_mac_internal.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698