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

Side by Side Diff: chrome/browser/mac/keychain_reauthorize.cc

Issue 10344009: Implement Keychain reauthorization (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 7 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 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 #include <Security/Security.h>
8
9 #include <algorithm>
10 #include <string>
11 #include <vector>
12
13 #include "base/basictypes.h"
14 #include "base/mac/foundation_util.h"
15 #include "base/mac/scoped_cftyperef.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "base/stringprintf.h"
18 #include "base/sys_string_conversions.h"
19 #include "chrome/browser/mac/security_wrappers.h"
20
21 namespace chrome {
22 namespace browser {
23 namespace mac {
24
25 void KeychainReauthorize() {
26 // See the designated requirement for a signed released build:
27 // codesign -d -r- "Google Chrome.app"
28 //
29 // Export the certificates from a signed released build:
30 // codesign -v --extract-certificates=/tmp/cert. "Google Chrome.app"
31 // (The extracted leaf certificate is at /tmp/cert.0; intermediates and root
32 // are at successive numbers.)
33 //
34 // Show some information about the exported certificates:
35 // openssl x509 -inform DER -in /tmp/cert.0 -noout -text -fingerprint
36 // (The "SHA1 Fingerprint" value printed by -fingerprint should match the
37 // hash used in a codesign designated requirement after allowing for obvious
38 // formatting differences.)
39
40 const char* const kIdentifierMatches[] = {
41 #if defined(GOOGLE_CHROME_BUILD)
42 "com.google.Chrome",
43 "com.google.Chrome.canary",
44 #else
45 "org.chromium.Chromium",
46 #endif
47 };
48
49 const char* const kLeafCertificateHashMatches[] = {
50 // Only official released builds of Google Chrome have ever been signed
51 // (with a certificate that anyone knows about or cares about).
52 #if defined(GOOGLE_CHROME_BUILD)
53 // This is the new certificate that has not yet been used to sign Chrome,
54 // but will be. Once used, the reauthorization code will become obsolete
55 // until it's needed for some other purpose in the future.
56 // Subject: UID=EQHXZ8M8AV, CN=Developer ID Application: Google Inc.,
57 // OU=EQHXZ8M8AV, O=Google Inc., C=US
58 // Issuer: CN=Developer ID Certification Authority,
59 // OU=Apple Certification Authority, O=Apple Inc., C=US
60 // Validity: 2012-04-26 14:10:10 UTC to 2017-04-27 14:10:10 UTC
61 // "85cee8254216185620ddc8851c7a9fc4dfe120ef",
62
63 // This certificate was used on 2011-12-20 and 2011-12-21, but the one
64 // below was restored afterwards as an interim fix to the Keychain
stuartmorgan 2012/05/10 06:50:54 "the one below" is ambiguous, especially since it
65 // authorization problem.
stuartmorgan 2012/05/10 06:50:54 Worth a bug ref? I'm guessing there are about thre
66 // Subject: C=US, ST=California, L=Mountain View, O=Google Inc,
67 // OU=Digital ID Class 3 - Java Object Signing, CN=Google Inc
68 // Issuer: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network,
69 // OU=Terms of use at https://www.verisign.com/rpa (c)10,
70 // CN=VeriSign Class 3 Code Signing 2010 CA
71 // Validity: 2011-11-14 00:00:00 UTC to 2014-11-13 23:59:59 UTC
72 "06c92bec3bbf32068cb9208563d004169448ee21",
73
74 // This certificate has been used since 2010-07-19, except for the brief
75 // period when the certificate above was used.
76 // Subject: C=US, ST=California, L=Mountain View, O=Google Inc,
77 // OU=Digital ID Class 3 - Java Object Signing, CN=Google Inc
78 // Issuer: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network,
79 // OU=Terms of use at https://www.verisign.com/rpa (c)09,
80 // CN=VeriSign Class 3 Code Signing 2009-2 CA
81 // Validity: 2010-02-22 00:00:00 UTC to 2012-02-22 23:59:59 UTC
82 "9481882581d8178db8b1649c0eaa4f9eb11288f0",
83
84 // This certificate was used for all public Chrome releases prior to
85 // 2010-07-19.
86 // Subject: C=US, ST=California, L=Mountain View, O=Google Inc,
87 // OU=Digital ID Class 3 - Netscape Object Signing, CN=Google Inc
88 // Issuer: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network,
89 // OU=Terms of use at https://www.verisign.com/rpa (c)04,
90 // CN=VeriSign Class 3 Code Signing 2004 CA
91 // Validity: 2007-06-19 00:00:00 UTC to 2010-06-18 23:59:59 UTC
92 "fe5008fe0da7a2033816752d6eafe95214f5a7e1",
93 #endif
94 };
95
96 std::vector<std::string> requirement_matches;
97 requirement_matches.reserve(arraysize(kIdentifierMatches) *
98 ARRAYSIZE_UNSAFE(kLeafCertificateHashMatches));
99
100 for (size_t identifier_index = 0;
101 identifier_index < arraysize(kIdentifierMatches);
102 ++identifier_index) {
103 for (size_t leaf_certificate_hash_index = 0;
104 leaf_certificate_hash_index <
105 ARRAYSIZE_UNSAFE(kLeafCertificateHashMatches);
106 ++leaf_certificate_hash_index) {
107 requirement_matches.push_back(base::StringPrintf(
108 "identifier \"%s\" and certificate leaf = H\"%s\"",
109 kIdentifierMatches[identifier_index],
110 kLeafCertificateHashMatches[leaf_certificate_hash_index]));
111 }
112 }
113
114 ScopedSecKeychainSetUserInteractionAllowed user_interaction_allowed(FALSE);
115
116 // Apple's documentation (Keychain Services Reference, Constants/Mac OS X
117 // Keychain Services API Constants/Keychain Item Class Constants) says to
118 // use CSSM_DL_DB_RECORD_ALL_KEYS, but that doesn't work.
119 // CSSM_DL_DB_RECORD_ANY (as used by SecurityTool's keychain-dump) does
120 // work.
121 base::mac::ScopedCFTypeRef<SecKeychainSearchRef> search(
122 CrSKeychainSearchCreateFromAttributes(NULL,
123 CSSM_DL_DB_RECORD_ANY,
124 NULL));
125
126 base::mac::ScopedCFTypeRef<SecTrustedApplicationRef> this_application;
127
128 std::vector<CrSKeychainItemAndAccess> items;
129
130 base::mac::ScopedCFTypeRef<SecKeychainItemRef> item;
131 while (item.reset(CrSKeychainSearchCopyNext(search)), item) {
132 if (!CrSKeychainItemTestAccess(item)) {
133 continue;
134 }
stuartmorgan 2012/05/10 06:50:54 Chromium style discourages single-line braces; it
135
136 base::mac::ScopedCFTypeRef<SecAccessRef> access(
137 CrSKeychainItemCopyAccess(item));
138 base::mac::ScopedCFTypeRef<CFArrayRef> acl_list(
139 CrSAccessCopyACLList(access));
140 if (!acl_list) {
141 continue;
142 }
143
144 bool acl_list_modified = false;
145
146 CFIndex acl_count = CFArrayGetCount(acl_list);
147 for (CFIndex acl_index = 0; acl_index < acl_count; ++acl_index) {
stuartmorgan 2012/05/10 06:50:54 The layers of if statements in a double for-loop i
148 SecACLRef acl = base::mac::CFCast<SecACLRef>(
149 CFArrayGetValueAtIndex(acl_list, acl_index));
150 scoped_ptr<CrSACLSimpleContents> acl_simple_contents(
151 CrSACLCopySimpleContents(acl));
152 if (!acl_simple_contents.get() ||
153 !acl_simple_contents->application_list) {
154 continue;
155 }
156
157 CFMutableArrayRef application_list_mutable = NULL;
158 bool added_this_application = false;
159
160 CFIndex application_count =
161 CFArrayGetCount(acl_simple_contents->application_list);
162 for (CFIndex application_index = 0;
163 application_index < application_count;
164 ++application_index) {
165 SecTrustedApplicationRef application =
166 base::mac::CFCast<SecTrustedApplicationRef>(
167 CFArrayGetValueAtIndex(acl_simple_contents->application_list,
168 application_index));
169 base::mac::ScopedCFTypeRef<SecRequirementRef> requirement(
170 CrSTrustedApplicationCopyRequirement(application));
171 base::mac::ScopedCFTypeRef<CFStringRef> requirement_string_cf(
172 CrSRequirementCopyString(requirement, kSecCSDefaultFlags));
173 if (!requirement_string_cf) {
174 continue;
175 }
176
177 std::string requirement_string =
178 base::SysCFStringRefToUTF8(requirement_string_cf);
179 if (std::find(requirement_matches.begin(),
180 requirement_matches.end(),
181 requirement_string) != requirement_matches.end()) {
182 if (!application_list_mutable) {
183 application_list_mutable =
184 CFArrayCreateMutableCopy(NULL,
185 application_count,
186 acl_simple_contents->application_list);
187 acl_simple_contents->application_list.reset(
188 application_list_mutable);
189 }
190
191 if (!this_application) {
192 this_application.reset(CrSTrustedApplicationCreateFromPath(NULL));
stuartmorgan 2012/05/10 06:50:54 Is it really expensive enough to do this (and unli
193 }
194
195 if (!added_this_application) {
stuartmorgan 2012/05/10 06:50:54 I find if (!foo) else to generally be less rea
Mark Mentovai 2012/05/14 21:28:45 stuartmorgan wrote:
196 CFArraySetValueAtIndex(application_list_mutable,
197 application_index,
198 this_application);
199 added_this_application = true;
200 } else {
201 // Even though it's more bookkeeping to walk a list in the forward
202 // direction when there are removals, it's done here anyway to
203 // keep this_application at the position of the first match.
204 CFArrayRemoveValueAtIndex(application_list_mutable,
205 application_index);
206 --application_index;
207 --application_count;
208 }
209 }
210 }
211
212 if (application_list_mutable) {
213 if (!CrSACLSetSimpleContents(acl, *acl_simple_contents.get())) {
214 continue;
215 }
216
217 acl_list_modified = true;
218 }
219 }
220
221 if (acl_list_modified) {
222 items.push_back(CrSKeychainItemAndAccess(item, access));
223 }
224 }
225
226 for (std::vector<CrSKeychainItemAndAccess>::const_iterator iterator =
227 items.begin();
228 iterator != items.end();
229 ++iterator) {
230 SecKeychainItemRef old_item = iterator->item();
231 base::mac::ScopedCFTypeRef<SecKeychainRef> keychain(
232 CrSKeychainItemCopyKeychain(old_item));
233
234 ScopedCrSKeychainItemAttributesAndData old_attributes_and_data(
235 CrSKeychainItemCopyAttributesAndData(keychain, old_item));
236 if (!old_attributes_and_data.get()) {
237 continue;
238 }
239
240 // SecKeychainItemCreateFromContent fails if any attribute is zero-length,
241 // but old_attributes_and_data can contain zero-length attributes. Create
242 // a new attribute list devoid of zero-length attributes.
stuartmorgan 2012/05/10 06:50:54 Could this whole step be a helper function?
243 UInt32 old_attribute_count =
244 old_attributes_and_data.attribute_list()->count;
245 std::vector<SecKeychainAttribute> new_attributes;
246 new_attributes.reserve(old_attribute_count);
247 for (UInt32 old_attribute_index = 0;
248 old_attribute_index < old_attribute_count;
249 ++old_attribute_index) {
250 SecKeychainAttribute* attribute =
251 &old_attributes_and_data.attribute_list()->attr[old_attribute_index];
252 if (attribute->length) {
253 new_attributes.push_back(*attribute);
254 }
255 }
256
257 SecKeychainAttributeList new_attribute_list;
258 new_attribute_list.count = new_attributes.size();
259 new_attribute_list.attr =
260 new_attribute_list.count ? &new_attributes[0] : NULL;
261
262 CrSKeychainItemAttributesAndData new_attributes_and_data =
263 *old_attributes_and_data.get();
264 new_attributes_and_data.attribute_list = &new_attribute_list;
265
266 // Delete the item last, to give everything else above a chance to bail
267 // out early, and to ensure that the old item is still present while it
268 // may still be used by the above code.
269 if (!CrSKeychainItemDelete(old_item)) {
270 continue;
271 }
272
273 base::mac::ScopedCFTypeRef<SecKeychainItemRef> new_item(
274 CrSKeychainItemCreateFromContent(new_attributes_and_data,
275 keychain,
276 iterator->access()));
277 }
278 }
279
280 } // namespace mac
281 } // namespace browser
282 } // namespace chrome
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698