Index: chrome/browser/mac/keychain_reauthorize.mm |
diff --git a/chrome/browser/mac/keychain_reauthorize.mm b/chrome/browser/mac/keychain_reauthorize.mm |
deleted file mode 100644 |
index 24d046db710f7e682dba897e217e780cfec9225b..0000000000000000000000000000000000000000 |
--- a/chrome/browser/mac/keychain_reauthorize.mm |
+++ /dev/null |
@@ -1,526 +0,0 @@ |
-// Copyright (c) 2012 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 <algorithm> |
-#include <string> |
-#include <vector> |
- |
-#include "base/basictypes.h" |
-#include "base/mac/foundation_util.h" |
-#include "base/mac/scoped_cftyperef.h" |
-#include "base/memory/scoped_ptr.h" |
-#include "base/metrics/histogram.h" |
-#include "base/strings/stringprintf.h" |
-#include "base/strings/sys_string_conversions.h" |
-#include "chrome/browser/mac/security_wrappers.h" |
- |
-namespace chrome { |
- |
-namespace { |
- |
-// Returns the requirement string embedded within a SecTrustedApplicationRef, |
-// or an empty string on error. |
-std::string RequirementStringForApplication( |
- SecTrustedApplicationRef application); |
- |
-// Returns the set of requirement strings that ought to be reauthorized. In a |
-// bundled application, the requirement string from |application| will also be |
-// added to the hard-coded list. This allows an at-launch reauthorization to |
-// re-reauthorize anything done by a previous at-update reauthorization. |
-// Although items reauthorized during the at-update step will work properly in |
-// every way, they contain a reference to the missing reauthorization stub |
-// executable from the disk image in the Keychain, resulting in no icon and |
-// a weird name like "com.google" (non-Canary) or "com.google.Chrome" |
-// (Canary). Because reauthorization is controlled by a preference that limits |
-// it to a single successful run at update and a single successful run at |
-// launch, protection already exists against perpetually reauthorizing items. |
-// This addition exists simply to make the Keychain Access UI match |
-// expectations. |
-std::vector<std::string> GetRequirementMatches( |
- SecTrustedApplicationRef application); |
- |
-// Reauthorizes an ACL by examining all of the applications it names, and upon |
-// finding any whose requirement matches any element of requirement_matches, |
-// replaces them with this_application. At most one instance of |
-// this_application will be added to the ACL. Subsequent applications whose |
-// requirement matches any element of requirement_matches will be removed from |
-// the ACL. Only the ACL is changed, nothing is written to disk. Returns true |
-// if any reauthorization is performed and thus acl is modified, and false |
-// otherwise. |
-bool ReauthorizeACL( |
- SecACLRef acl, |
- const std::vector<std::string>& requirement_matches, |
- SecTrustedApplicationRef this_application); |
- |
-// Reauthorizes a list of ACLs by calling ReauthorizeACL for each ACL in the |
-// list. Only the ACL list is changed, nothing is written to disk. Returns |
-// true if ReauthorizeTrue returns true for any ACL in acl_list, indicating |
-// that at least one ACL in acl_list was modified and thus at least one child |
-// child of acl_list was reauthorized. |
-bool ReauthorizeACLList( |
- CFArrayRef acl_list, |
- const std::vector<std::string>& requirement_matches, |
- SecTrustedApplicationRef this_application); |
- |
-// Reauthorizes a SecKeychainItemRef by calling ReauthorizeACLList to perform |
-// reauthorization on all ACLs that it contains. Nothing is written to disk. |
-// If any reauthorization was performed, returns a CrSKeychainItemAndAccess |
-// object containing the item and its access information. Otherwise, returns |
-// NULL. |
-CrSKeychainItemAndAccess* KCItemToKCItemAndReauthorizedAccess( |
- SecKeychainItemRef item, |
- const std::vector<std::string>& requirement_matches, |
- SecTrustedApplicationRef this_application); |
- |
-// Reauthorizes multiple Keychain items by calling |
-// KCItemToKCItemAndReauthorizedAccess for each item returned by a Keychain |
-// search. Nothing is written to disk. Reauthorized items are returned. |
-std::vector<CrSKeychainItemAndAccess> KCSearchToKCItemsAndReauthorizedAccesses( |
- SecKeychainSearchRef search, |
- const std::vector<std::string>& requirement_matches, |
- SecTrustedApplicationRef this_application); |
- |
-// Given a SecKeychainAttributeList, strips out any zero-length attributes and |
-// returns a vector containing the remaining attributes. |
-std::vector<SecKeychainAttribute> KCAttributesWithoutZeroLength( |
- SecKeychainAttributeList* old_attribute_list); |
- |
-// Given a CrSKeychainItemAndAccess that has had its access field |
-// reauthorized, places the reauthorized form into the Keychain by deleting |
-// the old item and replacing it with a new one whose access policy matches |
-// the reauthorized form. The new item is written to disk and becomes part of |
-// the Keychain, replacing what had been there previously. |
-void WriteKCItemAndReauthorizedAccess( |
- const CrSKeychainItemAndAccess& item_and_reauthorized_access); |
- |
-// Given a vector of CrSKeychainItemAndAccess objects, places the reauthorized |
-// forms of all of them into the Keychain by calling |
-// WriteKCItemAndReauthorizedAccess for each. The new items are written to |
-// disk and become part of the Keychain, replacing what had been there |
-// previously. |
-void WriteKCItemsAndReauthorizedAccesses( |
- const std::vector<CrSKeychainItemAndAccess>& |
- items_and_reauthorized_accesses); |
- |
-} // namespace |
- |
-void KeychainReauthorize() { |
- ScopedSecKeychainSetUserInteractionAllowed user_interaction_allowed(FALSE); |
- |
- // Apple's documentation (Keychain Services Reference, Constants/Mac OS X |
- // Keychain Services API Constants/Keychain Item Class Constants) says to |
- // use CSSM_DL_DB_RECORD_ALL_KEYS, but that doesn't work. |
- // CSSM_DL_DB_RECORD_ANY (as used by SecurityTool's keychain-dump) does |
- // work. |
- base::ScopedCFTypeRef<SecKeychainSearchRef> search( |
- CrSKeychainSearchCreateFromAttributes(NULL, CSSM_DL_DB_RECORD_ANY, NULL)); |
- |
- base::ScopedCFTypeRef<SecTrustedApplicationRef> this_application( |
- CrSTrustedApplicationCreateFromPath(NULL)); |
- |
- std::vector<std::string> requirement_matches = |
- GetRequirementMatches(this_application); |
- |
- std::vector<CrSKeychainItemAndAccess> items_and_reauthorized_accesses = |
- KCSearchToKCItemsAndReauthorizedAccesses(search, |
- requirement_matches, |
- this_application); |
- |
- WriteKCItemsAndReauthorizedAccesses(items_and_reauthorized_accesses); |
-} |
- |
-void KeychainReauthorizeIfNeeded(NSString* pref_key, int max_tries) { |
- NSUserDefaults* user_defaults = [NSUserDefaults standardUserDefaults]; |
- int pref_value = [user_defaults integerForKey:pref_key]; |
- |
- if (pref_value < max_tries) { |
- 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); |
- } |
- } |
- |
- ++pref_value; |
- [user_defaults setInteger:pref_value forKey:pref_key]; |
- [user_defaults synchronize]; |
- |
- KeychainReauthorize(); |
- |
- [user_defaults setInteger:max_tries forKey:pref_key]; |
- NSString* success_pref_key = [pref_key stringByAppendingString:@"Success"]; |
- [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 { |
- |
-std::string RequirementStringForApplication( |
- SecTrustedApplicationRef application) { |
- base::ScopedCFTypeRef<SecRequirementRef> requirement( |
- CrSTrustedApplicationCopyRequirement(application)); |
- base::ScopedCFTypeRef<CFStringRef> requirement_string_cf( |
- CrSRequirementCopyString(requirement, kSecCSDefaultFlags)); |
- if (!requirement_string_cf) { |
- return std::string(); |
- } |
- |
- std::string requirement_string = |
- base::SysCFStringRefToUTF8(requirement_string_cf); |
- |
- return requirement_string; |
-} |
- |
-std::vector<std::string> GetRequirementMatches( |
- SecTrustedApplicationRef application) { |
- // See the designated requirement for a signed released build: |
- // codesign -d -r- "Google Chrome.app" |
- // |
- // Export the certificates from a signed released build: |
- // codesign -v --extract-certificates=/tmp/cert. "Google Chrome.app" |
- // (The extracted leaf certificate is at /tmp/cert.0; intermediates and root |
- // are at successive numbers.) |
- // |
- // Show some information about the exported certificates: |
- // openssl x509 -inform DER -in /tmp/cert.0 -noout -text -fingerprint |
- // (The "SHA1 Fingerprint" value printed by -fingerprint should match the |
- // hash used in a codesign designated requirement after allowing for obvious |
- // formatting differences.) |
- |
- const char* const kIdentifierMatches[] = { |
-#if defined(GOOGLE_CHROME_BUILD) |
- "com.google.Chrome", |
- "com.google.Chrome.canary", |
-#else |
- "org.chromium.Chromium", |
-#endif |
- }; |
- |
- const char* const kLeafCertificateHashMatches[] = { |
- // Only official released builds of Google Chrome have ever been signed |
- // (with a certificate that anyone knows about or cares about). |
-#if defined(GOOGLE_CHROME_BUILD) |
- // This is the new certificate that has not yet been used to sign Chrome, |
- // but will be. Once used, the reauthorization code will become obsolete |
- // until it's needed for some other purpose in the future. |
- // Subject: UID=EQHXZ8M8AV, CN=Developer ID Application: Google Inc., |
- // OU=EQHXZ8M8AV, O=Google Inc., C=US |
- // Issuer: CN=Developer ID Certification Authority, |
- // OU=Apple Certification Authority, O=Apple Inc., C=US |
- // Validity: 2012-04-26 14:10:10 UTC to 2017-04-27 14:10:10 UTC |
- // "85cee8254216185620ddc8851c7a9fc4dfe120ef", |
- |
- // This certificate was used on 2011-12-20 and 2011-12-21, but the "since |
- // 2010-07-19" one below was restored afterwards as an interim fix to the |
- // Keychain authorization problem. See http://crbug.com/108238 and |
- // http://crbug.com/62605. |
- // Subject: C=US, ST=California, L=Mountain View, O=Google Inc, |
- // OU=Digital ID Class 3 - Java Object Signing, CN=Google Inc |
- // Issuer: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, |
- // OU=Terms of use at https://www.verisign.com/rpa (c)10, |
- // CN=VeriSign Class 3 Code Signing 2010 CA |
- // Validity: 2011-11-14 00:00:00 UTC to 2014-11-13 23:59:59 UTC |
- "06c92bec3bbf32068cb9208563d004169448ee21", |
- |
- // This certificate has been used since 2010-07-19, except for the brief |
- // period when the certificate above was used. |
- // Subject: C=US, ST=California, L=Mountain View, O=Google Inc, |
- // OU=Digital ID Class 3 - Java Object Signing, CN=Google Inc |
- // Issuer: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, |
- // OU=Terms of use at https://www.verisign.com/rpa (c)09, |
- // CN=VeriSign Class 3 Code Signing 2009-2 CA |
- // Validity: 2010-02-22 00:00:00 UTC to 2012-02-22 23:59:59 UTC |
- "9481882581d8178db8b1649c0eaa4f9eb11288f0", |
- |
- // This certificate was used for all public Chrome releases prior to |
- // 2010-07-19. |
- // Subject: C=US, ST=California, L=Mountain View, O=Google Inc, |
- // OU=Digital ID Class 3 - Netscape Object Signing, CN=Google Inc |
- // Issuer: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, |
- // OU=Terms of use at https://www.verisign.com/rpa (c)04, |
- // CN=VeriSign Class 3 Code Signing 2004 CA |
- // Validity: 2007-06-19 00:00:00 UTC to 2010-06-18 23:59:59 UTC |
- "fe5008fe0da7a2033816752d6eafe95214f5a7e1", |
-#endif |
- }; |
- |
- std::vector<std::string> requirement_matches; |
- requirement_matches.reserve(arraysize(kIdentifierMatches) * |
- ARRAYSIZE_UNSAFE(kLeafCertificateHashMatches)); |
- |
- for (size_t identifier_index = 0; |
- identifier_index < arraysize(kIdentifierMatches); |
- ++identifier_index) { |
- for (size_t leaf_certificate_hash_index = 0; |
- leaf_certificate_hash_index < |
- ARRAYSIZE_UNSAFE(kLeafCertificateHashMatches); |
- ++leaf_certificate_hash_index) { |
- requirement_matches.push_back(base::StringPrintf( |
- "identifier \"%s\" and certificate leaf = H\"%s\"", |
- kIdentifierMatches[identifier_index], |
- kLeafCertificateHashMatches[leaf_certificate_hash_index])); |
- } |
- } |
- |
- if (application && base::mac::AmIBundled()) { |
- std::string application_requirement = |
- RequirementStringForApplication(application); |
- requirement_matches.push_back(application_requirement); |
- } |
- |
- return requirement_matches; |
-} |
- |
-std::vector<CrSKeychainItemAndAccess> KCSearchToKCItemsAndReauthorizedAccesses( |
- SecKeychainSearchRef search, |
- const std::vector<std::string>& requirement_matches, |
- SecTrustedApplicationRef this_application) { |
- std::vector<CrSKeychainItemAndAccess> items_and_accesses; |
- |
- base::ScopedCFTypeRef<SecKeychainItemRef> item; |
- while (item.reset(CrSKeychainSearchCopyNext(search)), item) { |
- scoped_ptr<CrSKeychainItemAndAccess> item_and_access( |
- KCItemToKCItemAndReauthorizedAccess(item, |
- requirement_matches, |
- this_application)); |
- |
- if (item_and_access.get()) { |
- items_and_accesses.push_back(*item_and_access); |
- } |
- } |
- |
- return items_and_accesses; |
-} |
- |
-CrSKeychainItemAndAccess* KCItemToKCItemAndReauthorizedAccess( |
- SecKeychainItemRef item, |
- const std::vector<std::string>& requirement_matches, |
- SecTrustedApplicationRef this_application) { |
- if (!CrSKeychainItemTestAccess(item)) { |
- return NULL; |
- } |
- |
- base::ScopedCFTypeRef<SecAccessRef> access(CrSKeychainItemCopyAccess(item)); |
- base::ScopedCFTypeRef<CFArrayRef> acl_list(CrSAccessCopyACLList(access)); |
- if (!acl_list) { |
- return NULL; |
- } |
- |
- bool acl_list_modified = ReauthorizeACLList(acl_list, |
- requirement_matches, |
- this_application); |
- if (!acl_list_modified) { |
- return NULL; |
- } |
- |
- return new CrSKeychainItemAndAccess(item, access); |
-} |
- |
-bool ReauthorizeACLList( |
- CFArrayRef acl_list, |
- const std::vector<std::string>& requirement_matches, |
- SecTrustedApplicationRef this_application) { |
- bool acl_list_modified = false; |
- |
- CFIndex acl_count = CFArrayGetCount(acl_list); |
- for (CFIndex acl_index = 0; acl_index < acl_count; ++acl_index) { |
- SecACLRef acl = base::mac::CFCast<SecACLRef>( |
- CFArrayGetValueAtIndex(acl_list, acl_index)); |
- if (!acl) { |
- continue; |
- } |
- |
- if (ReauthorizeACL(acl, requirement_matches, this_application)) { |
- acl_list_modified = true; |
- } |
- } |
- |
- return acl_list_modified; |
-} |
- |
-bool ReauthorizeACL( |
- SecACLRef acl, |
- const std::vector<std::string>& requirement_matches, |
- SecTrustedApplicationRef this_application) { |
- scoped_ptr<CrSACLSimpleContents> acl_simple_contents( |
- CrSACLCopySimpleContents(acl)); |
- if (!acl_simple_contents.get() || |
- !acl_simple_contents->application_list) { |
- return false; |
- } |
- |
- CFMutableArrayRef application_list_mutable = NULL; |
- bool added_this_application = false; |
- |
- CFIndex application_count = |
- CFArrayGetCount(acl_simple_contents->application_list); |
- for (CFIndex application_index = 0; |
- application_index < application_count; |
- ++application_index) { |
- SecTrustedApplicationRef application = |
- base::mac::CFCast<SecTrustedApplicationRef>( |
- CFArrayGetValueAtIndex(acl_simple_contents->application_list, |
- application_index)); |
- std::string requirement_string = |
- RequirementStringForApplication(application); |
- if (requirement_string.empty()) { |
- continue; |
- } |
- |
- if (std::find(requirement_matches.begin(), |
- requirement_matches.end(), |
- requirement_string) != requirement_matches.end()) { |
- if (!application_list_mutable) { |
- application_list_mutable = |
- CFArrayCreateMutableCopy(NULL, |
- application_count, |
- acl_simple_contents->application_list); |
- acl_simple_contents->application_list.reset( |
- application_list_mutable); |
- } |
- |
- if (!added_this_application) { |
- CFArraySetValueAtIndex(application_list_mutable, |
- application_index, |
- this_application); |
- added_this_application = true; |
- } else { |
- // Even though it's more bookkeeping to walk a list in the forward |
- // direction when there are removals, it's done here anyway to |
- // keep this_application at the position of the first match. |
- CFArrayRemoveValueAtIndex(application_list_mutable, |
- application_index); |
- --application_index; |
- --application_count; |
- } |
- } |
- } |
- |
- if (!application_list_mutable) { |
- return false; |
- } |
- |
- if (!CrSACLSetSimpleContents(acl, *acl_simple_contents.get())) { |
- return false; |
- } |
- |
- return true; |
-} |
- |
-void WriteKCItemsAndReauthorizedAccesses( |
- const std::vector<CrSKeychainItemAndAccess>& |
- items_and_reauthorized_accesses) { |
- for (std::vector<CrSKeychainItemAndAccess>::const_iterator iterator = |
- items_and_reauthorized_accesses.begin(); |
- iterator != items_and_reauthorized_accesses.end(); |
- ++iterator) { |
- WriteKCItemAndReauthorizedAccess(*iterator); |
- } |
-} |
- |
-void WriteKCItemAndReauthorizedAccess( |
- const CrSKeychainItemAndAccess& item_and_reauthorized_access) { |
- SecKeychainItemRef old_item = item_and_reauthorized_access.item(); |
- base::ScopedCFTypeRef<SecKeychainRef> keychain( |
- CrSKeychainItemCopyKeychain(old_item)); |
- |
- ScopedCrSKeychainItemAttributesAndData old_attributes_and_data( |
- CrSKeychainItemCopyAttributesAndData(keychain, old_item)); |
- if (!old_attributes_and_data.get()) { |
- return; |
- } |
- |
- // CrSKeychainItemCreateFromContent (SecKeychainItemCreateFromContent) |
- // returns errKCNoSuchAttr (errSecNoSuchAttr) when asked to add an item of |
- // type kSecPrivateKeyItemClass. This would happen after the original |
- // private key was deleted, resulting in data loss. I can't figure out how |
- // SecKeychainItemCreateFromContent wants private keys added. Skip them, |
- // only doing the reauthorization for Keychain item types known to work, |
- // the item types expected to be used by most users and those that are |
- // synced. See http://crbug.com/130738 and |
- // http://lists.apple.com/archives/apple-cdsa/2006/Jan/msg00025.html . |
- switch (old_attributes_and_data.item_class()) { |
- case kSecInternetPasswordItemClass: |
- case kSecGenericPasswordItemClass: |
- break; |
- default: |
- return; |
- } |
- |
- // SecKeychainItemCreateFromContent fails if any attribute is zero-length, |
- // but old_attributes_and_data can contain zero-length attributes. Create |
- // a new attribute list devoid of zero-length attributes. |
- // |
- // This is awkward: only the logic to build the |
- // std::vector<SecKeychainAttribute> is in KCAttributesWithoutZeroLength |
- // because the storage used for the new attribute list (the vector) needs to |
- // persist through the lifetime of this function. |
- // KCAttributesWithoutZeroLength doesn't return a |
- // CrSKeychainItemAttributesAndData (which could be held here in a |
- // ScopedCrSKeychainItemAttributesAndData) because it's more convenient to |
- // build the attribute list using std::vector and point the data at the copy |
- // in old_attributes_and_data, thus making nothing in new_attributes a |
- // strongly-held reference. |
- std::vector<SecKeychainAttribute> new_attributes = |
- KCAttributesWithoutZeroLength(old_attributes_and_data.attribute_list()); |
- SecKeychainAttributeList new_attribute_list; |
- new_attribute_list.count = new_attributes.size(); |
- new_attribute_list.attr = |
- new_attribute_list.count ? &new_attributes[0] : NULL; |
- CrSKeychainItemAttributesAndData new_attributes_and_data = |
- *old_attributes_and_data.get(); |
- new_attributes_and_data.attribute_list = &new_attribute_list; |
- |
- // Delete the item last, to give everything else above a chance to bail |
- // out early, and to ensure that the old item is still present while it |
- // may still be used by the above code. |
- if (!CrSKeychainItemDelete(old_item)) { |
- return; |
- } |
- |
- base::ScopedCFTypeRef<SecKeychainItemRef> new_item( |
- CrSKeychainItemCreateFromContent(new_attributes_and_data, |
- keychain, |
- item_and_reauthorized_access.access())); |
-} |
- |
-std::vector<SecKeychainAttribute> KCAttributesWithoutZeroLength( |
- SecKeychainAttributeList* old_attribute_list) { |
- UInt32 old_attribute_count = old_attribute_list->count; |
- std::vector<SecKeychainAttribute> new_attributes; |
- new_attributes.reserve(old_attribute_count); |
- for (UInt32 old_attribute_index = 0; |
- old_attribute_index < old_attribute_count; |
- ++old_attribute_index) { |
- SecKeychainAttribute* attribute = |
- &old_attribute_list->attr[old_attribute_index]; |
- if (attribute->length) { |
- new_attributes.push_back(*attribute); |
- } |
- } |
- |
- return new_attributes; |
-} |
- |
-} // namespace |
- |
-} // namespace chrome |