Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/browser/mac/keychain_reauthorize.h" | |
| 6 | |
| 7 #import <Foundation/Foundation.h> | |
| 8 #include <Security/Security.h> | |
| 9 | |
| 10 #include <string.h> | |
| 11 | |
| 12 #include "base/logging.h" | |
| 13 #include "base/mac/foundation_util.h" | |
| 14 #include "base/mac/scoped_cftyperef.h" | |
| 15 #include "base/metrics/histogram.h" | |
| 16 #include "base/metrics/histogram_macros.h" | |
| 17 #include "base/scoped_generic.h" | |
| 18 #include "components/os_crypt/keychain_password_mac.h" | |
| 19 #include "crypto/apple_keychain.h" | |
| 20 | |
| 21 namespace chrome { | |
| 22 | |
| 23 namespace { | |
| 24 | |
| 25 // Reauthorizes the Safe Storage keychain item, which protects the randomly | |
| 26 // generated password that encrypts the user's saved passwords. This reads out | |
| 27 // the keychain item, deletes it, and re-adds it to the keychain. This works | |
| 28 // 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.
| |
| 29 // 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.
| |
| 30 // access the item), but using a designated requirement that accepts the current | |
| 31 // and new certificates as valid. | |
| 32 bool KeychainReauthorize() { | |
| 33 base::ScopedCFTypeRef<SecKeychainItemRef> storage_item; | |
| 34 UInt32 pw_length = 0; | |
| 35 void* password_data = nullptr; | |
| 36 | |
| 37 crypto::AppleKeychain keychain; | |
| 38 OSStatus error = keychain.FindGenericPassword( | |
| 39 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.
| |
| 40 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.
| |
| 41 KeychainPassword::account_name, &pw_length, &password_data, | |
| 42 storage_item.InitializeInto()); | |
| 43 | |
| 44 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.
| |
| 45 std::string(static_cast<char*>(password_data), pw_length); | |
| 46 if (password_data) { | |
| 47 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
| |
| 48 keychain.ItemFreeContent(nullptr, password_data); | |
| 49 } | |
| 50 | |
| 51 if (error != noErr) | |
| 52 return false; | |
|
Mark Mentovai
2017/03/01 22:00:30
Wanna say something about this?
Greg K
2017/03/02 01:28:27
Done.
| |
| 53 | |
| 54 if (keychain.ItemDelete(storage_item) != noErr) { | |
| 55 LOG(ERROR) << "KeychainReauthorize failed. Cannot delete item."; | |
|
Mark Mentovai
2017/03/01 22:00:31
Aha! Whenever you’re logging something about an OS
| |
| 56 return false; | |
| 57 } | |
| 58 | |
| 59 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.
| |
| 60 NULL, strlen(KeychainPassword::service_name), | |
| 61 KeychainPassword::service_name, strlen(KeychainPassword::account_name), | |
| 62 KeychainPassword::account_name, password.size(), password.data(), NULL); | |
| 63 | |
| 64 if (error != noErr) { | |
| 65 LOG(ERROR) << "Failed to re-add storage password."; | |
| 66 return false; | |
| 67 } | |
| 68 return true; | |
| 69 } | |
| 70 | |
| 71 } // namespace | |
| 72 | |
| 73 void KeychainReauthorizeIfNeeded(NSString* pref_key, int max_tries) { | |
| 74 NSUserDefaults* user_defaults = [NSUserDefaults standardUserDefaults]; | |
| 75 [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.
| |
| 76 int pref_value = [user_defaults integerForKey:pref_key]; | |
| 77 | |
| 78 if (pref_value >= max_tries) | |
| 79 return; | |
| 80 | |
| 81 BOOL success_value = | |
| 82 [user_defaults boolForKey:[pref_key stringByAppendingString:@"Success"]]; | |
| 83 if (success_value) | |
| 84 return; | |
| 85 | |
| 86 if (pref_value > 0) { | |
| 87 // Logs the number of previous tries that didn't complete. | |
| 88 if (base::mac::AmIBundled()) { | |
| 89 UMA_HISTOGRAM_COUNTS("OSX.KeychainReauthorizeIfNeeded", pref_value); | |
| 90 } else { | |
| 91 UMA_HISTOGRAM_COUNTS("OSX.KeychainReauthorizeIfNeededAtUpdate", | |
| 92 pref_value); | |
| 93 } | |
| 94 } | |
| 95 | |
| 96 bool success = KeychainReauthorize(); | |
| 97 | |
| 98 ++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.
| |
| 99 [user_defaults setInteger:pref_value forKey:pref_key]; | |
| 100 [user_defaults synchronize]; | |
| 101 | |
| 102 if (!success) | |
| 103 return; | |
| 104 | |
| 105 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.
| |
| 106 [user_defaults setBool:YES forKey:success_pref_key]; | |
| 107 [user_defaults synchronize]; | |
| 108 | |
| 109 // Logs the try number (1, 2) that succeeded. | |
| 110 if (base::mac::AmIBundled()) { | |
| 111 UMA_HISTOGRAM_COUNTS("OSX.KeychainReauthorizeIfNeededSuccess", pref_value); | |
| 112 } else { | |
| 113 UMA_HISTOGRAM_COUNTS("OSX.KeychainReauthorizeIfNeededAtUpdateSuccess", | |
| 114 pref_value); | |
| 115 } | |
| 116 } | |
| 117 | |
| 118 } // namespace chrome | |
| OLD | NEW |