Chromium Code Reviews| Index: chrome/browser/mac/keychain_reauthorize.mm |
| diff --git a/chrome/browser/mac/keychain_reauthorize.mm b/chrome/browser/mac/keychain_reauthorize.mm |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..4bf5bca20d71eaf18901d01cfc5ac034d57dca39 |
| --- /dev/null |
| +++ b/chrome/browser/mac/keychain_reauthorize.mm |
| @@ -0,0 +1,118 @@ |
| +// Copyright 2017 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 "chrome/browser/mac/keychain_reauthorize.h" |
| + |
| +#import <Foundation/Foundation.h> |
| +#include <Security/Security.h> |
| + |
| +#include <string.h> |
| + |
| +#include "base/logging.h" |
| +#include "base/mac/foundation_util.h" |
| +#include "base/mac/scoped_cftyperef.h" |
| +#include "base/metrics/histogram.h" |
| +#include "base/metrics/histogram_macros.h" |
| +#include "base/scoped_generic.h" |
| +#include "components/os_crypt/keychain_password_mac.h" |
| +#include "crypto/apple_keychain.h" |
| + |
| +namespace chrome { |
| + |
| +namespace { |
| + |
| +// Reauthorizes the Safe Storage keychain item, which protects the randomly |
| +// generated password that encrypts the user's saved passwords. This reads out |
| +// the keychain item, deletes it, and re-adds it to the keychain. This works |
| +// because the keychain uses an apps designated requirement as the default ACL |
|
Mark Mentovai
2017/03/01 22:00:30
“default ACL for”→“ACL for reading”
Mark Mentovai
2017/03/01 22:00:31
app’s
Greg K
2017/03/02 01:28:27
Done.
Greg K
2017/03/02 01:28:27
Done.
|
| +// for an item. We are signing Chrome with the current certificate (so it can |
|
Mark Mentovai
2017/03/01 22:00:31
Don’t say “we.” Also, the bit about signing will b
Greg K
2017/03/02 01:28:27
Done.
|
| +// access the item), but using a designated requirement that accepts the current |
| +// and new certificates as valid. |
| +bool KeychainReauthorize() { |
| + base::ScopedCFTypeRef<SecKeychainItemRef> storage_item; |
| + UInt32 pw_length = 0; |
| + void* password_data = nullptr; |
| + |
| + crypto::AppleKeychain keychain; |
| + OSStatus error = keychain.FindGenericPassword( |
| + NULL, strlen(KeychainPassword::service_name), |
|
Mark Mentovai
2017/03/01 22:00:31
Use nullptr now in new code. Hooray for C++11!
Greg K
2017/03/02 01:28:27
Done.
|
| + KeychainPassword::service_name, strlen(KeychainPassword::account_name), |
|
Mark Mentovai
2017/03/01 22:00:31
If git cl format formatted this, then it’s fine be
Greg K
2017/03/02 01:28:27
Done.
|
| + KeychainPassword::account_name, &pw_length, &password_data, |
| + storage_item.InitializeInto()); |
| + |
| + std::string password = |
|
Mark Mentovai
2017/03/01 22:00:30
One of the sanitizers may not like this if !passwo
Greg K
2017/03/02 01:28:27
Done.
|
| + std::string(static_cast<char*>(password_data), pw_length); |
| + if (password_data) { |
| + memset(password_data, 0xAA, pw_length); |
|
Mark Mentovai
2017/03/01 22:00:31
This is good. memset_s() would be even better. But
Greg K
2017/03/02 01:28:27
memset_s requires some LIBC extension, but let's d
|
| + keychain.ItemFreeContent(nullptr, password_data); |
| + } |
| + |
| + if (error != noErr) |
| + return false; |
|
Mark Mentovai
2017/03/01 22:00:30
Wanna say something about this?
Greg K
2017/03/02 01:28:27
Done.
|
| + |
| + if (keychain.ItemDelete(storage_item) != noErr) { |
| + LOG(ERROR) << "KeychainReauthorize failed. Cannot delete item."; |
|
Mark Mentovai
2017/03/01 22:00:31
Aha! Whenever you’re logging something about an OS
|
| + return false; |
| + } |
| + |
| + error = keychain.AddGenericPassword( |
|
Mark Mentovai
2017/03/01 22:00:31
I’m pretty sure that the answer is no, but we can’
Greg K
2017/03/02 01:28:27
Definitely good to test, but it failed.
|
| + NULL, strlen(KeychainPassword::service_name), |
| + KeychainPassword::service_name, strlen(KeychainPassword::account_name), |
| + KeychainPassword::account_name, password.size(), password.data(), NULL); |
| + |
| + if (error != noErr) { |
| + LOG(ERROR) << "Failed to re-add storage password."; |
| + return false; |
| + } |
| + return true; |
| +} |
| + |
| +} // namespace |
| + |
| +void KeychainReauthorizeIfNeeded(NSString* pref_key, int max_tries) { |
| + NSUserDefaults* user_defaults = [NSUserDefaults standardUserDefaults]; |
| + [user_defaults synchronize]; |
|
Mark Mentovai
2017/03/01 22:00:31
I don’t believe that this one will do anything, be
Greg K
2017/03/02 01:28:27
Done.
|
| + int pref_value = [user_defaults integerForKey:pref_key]; |
| + |
| + if (pref_value >= max_tries) |
| + return; |
| + |
| + BOOL success_value = |
| + [user_defaults boolForKey:[pref_key stringByAppendingString:@"Success"]]; |
| + if (success_value) |
| + return; |
| + |
| + if (pref_value > 0) { |
| + // Logs the number of previous tries that didn't complete. |
| + if (base::mac::AmIBundled()) { |
| + UMA_HISTOGRAM_COUNTS("OSX.KeychainReauthorizeIfNeeded", pref_value); |
| + } else { |
| + UMA_HISTOGRAM_COUNTS("OSX.KeychainReauthorizeIfNeededAtUpdate", |
| + pref_value); |
| + } |
| + } |
| + |
| + bool success = KeychainReauthorize(); |
| + |
| + ++pref_value; |
|
Mark Mentovai
2017/03/01 22:00:31
The comment in the header was explicit that this w
Greg K
2017/03/02 01:28:27
That makes sense, I didn't think about that.
|
| + [user_defaults setInteger:pref_value forKey:pref_key]; |
| + [user_defaults synchronize]; |
| + |
| + if (!success) |
| + return; |
| + |
| + NSString* success_pref_key = [pref_key stringByAppendingString:@"Success"]; |
|
Mark Mentovai
2017/03/01 22:00:31
You already computed this above, on line 82. You s
Greg K
2017/03/02 01:28:27
Done.
|
| + [user_defaults setBool:YES forKey:success_pref_key]; |
| + [user_defaults synchronize]; |
| + |
| + // Logs the try number (1, 2) that succeeded. |
| + if (base::mac::AmIBundled()) { |
| + UMA_HISTOGRAM_COUNTS("OSX.KeychainReauthorizeIfNeededSuccess", pref_value); |
| + } else { |
| + UMA_HISTOGRAM_COUNTS("OSX.KeychainReauthorizeIfNeededAtUpdateSuccess", |
| + pref_value); |
| + } |
| +} |
| + |
| +} // namespace chrome |