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

Side by Side Diff: chrome/browser/chromeos/platform_keys/key_permissions.cc

Issue 1150373002: platformKeys: Add policy and corporate key tagging. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@key_perm
Patch Set: Rebased. 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 unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/chromeos/platform_keys/key_permissions.h" 5 #include "chrome/browser/chromeos/platform_keys/key_permissions.h"
6 6
7 #include "base/base64.h" 7 #include "base/base64.h"
8 #include "base/bind.h" 8 #include "base/bind.h"
9 #include "base/callback.h" 9 #include "base/callback.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/prefs/scoped_user_pref_update.h"
11 #include "base/values.h" 13 #include "base/values.h"
14 #include "chrome/common/pref_names.h"
15 #include "components/policy/core/common/policy_map.h"
16 #include "components/policy/core/common/policy_namespace.h"
17 #include "components/policy/core/common/policy_service.h"
18 #include "components/pref_registry/pref_registry_syncable.h"
12 #include "extensions/browser/state_store.h" 19 #include "extensions/browser/state_store.h"
20 #include "policy/policy_constants.h"
13 21
14 namespace chromeos { 22 namespace chromeos {
15 23
16 namespace { 24 namespace {
17 25
18 // The key at which platform key specific data is stored in each extension's 26 // The key at which platform key specific data is stored in each extension's
19 // state store. 27 // state store.
20 // 28 //
21 // From older versions of ChromeOS, this key can hold a list of base64 and 29 // From older versions of ChromeOS, this key can hold a list of base64 and
22 // DER-encoded SPKIs. A key can be used for signing at most once if it is part 30 // DER-encoded SPKIs. A key can be used for signing at most once if it is part
23 // of that list. 31 // of that list.
24 // 32 //
25 // The current format of data that is written to the PlatformKeys field is a 33 // The current format of data that is written to the PlatformKeys field is a
26 // list of serialized KeyEntry objects: 34 // list of serialized KeyEntry objects:
27 // { 'SPKI': string, 35 // { 'SPKI': string,
28 // 'signOnce': bool, // if not present, defaults to false 36 // 'signOnce': bool, // if not present, defaults to false
29 // 'signUnlimited': bool // if not present, defaults to false 37 // 'signUnlimited': bool // if not present, defaults to false
30 // } 38 // }
31 // 39 //
32 // Do not change this constant as clients will lose their existing state. 40 // Do not change this constant as clients will lose their existing state.
33 const char kStateStorePlatformKeys[] = "PlatformKeys"; 41 const char kStateStorePlatformKeys[] = "PlatformKeys";
34 const char kStateStoreSPKI[] = "SPKI"; 42 const char kStateStoreSPKI[] = "SPKI";
35 const char kStateStoreSignOnce[] = "signOnce"; 43 const char kStateStoreSignOnce[] = "signOnce";
36 const char kStateStoreSignUnlimited[] = "signUnlimited"; 44 const char kStateStoreSignUnlimited[] = "signUnlimited";
37 45
46 const char kPrefKeyUsage[] = "keyUsage";
battre 2015/06/17 15:11:47 Add an example how these are used like above?
pneubeck (no reviews) 2015/06/18 08:45:15 Done.
47 const char kPrefKeyUsageCorporate[] = "corporate";
48 const char kPolicyAllowCorporateKeyUsage[] = "allowCorporateKeyUsage";
49
38 } // namespace 50 } // namespace
39 51
40 struct KeyPermissions::PermissionsForExtension::KeyEntry { 52 struct KeyPermissions::PermissionsForExtension::KeyEntry {
41 explicit KeyEntry(const std::string& public_key_spki_der_b64) 53 explicit KeyEntry(const std::string& public_key_spki_der_b64)
42 : spki_b64(public_key_spki_der_b64) {} 54 : spki_b64(public_key_spki_der_b64) {}
43 55
44 // The base64-encoded DER of a X.509 Subject Public Key Info. 56 // The base64-encoded DER of a X.509 Subject Public Key Info.
45 std::string spki_b64; 57 std::string spki_b64;
46 58
47 // True if the key can be used once for singing. 59 // True if the key can be used once for singing.
48 // This permission is granted if an extension generated a key using the 60 // This permission is granted if an extension generated a key using the
49 // enterprise.platformKeys API, so that it can build a certification request. 61 // enterprise.platformKeys API, so that it can build a certification request.
50 // After the first signing operation this permission will be revoked. 62 // After the first signing operation this permission will be revoked.
51 bool sign_once = false; 63 bool sign_once = false;
52 64
53 // True if the key can be used for signing an unlimited number of times. 65 // True if the key can be used for signing an unlimited number of times.
54 // This permission is granted by the user or by policy to allow the extension 66 // This permission is granted by the user to allow the extension to use the
55 // to use the key for signing through the enterprise.platformKeys or 67 // key for signing through the enterprise.platformKeys or platformKeys API.
56 // platformKeys API.
57 // This permission is granted until revoked by the user or the policy. 68 // This permission is granted until revoked by the user or the policy.
58 bool sign_unlimited = false; 69 bool sign_unlimited = false;
59 }; 70 };
60 71
61 KeyPermissions::PermissionsForExtension::PermissionsForExtension( 72 KeyPermissions::PermissionsForExtension::PermissionsForExtension(
62 const std::string& extension_id, 73 const std::string& extension_id,
63 scoped_ptr<base::Value> state_store_value, 74 scoped_ptr<base::Value> state_store_value,
75 PrefService* profile_prefs,
76 policy::PolicyService* profile_policies,
64 KeyPermissions* key_permissions) 77 KeyPermissions* key_permissions)
65 : extension_id_(extension_id), key_permissions_(key_permissions) { 78 : extension_id_(extension_id),
79 profile_prefs_(profile_prefs),
80 profile_policies_(profile_policies),
81 key_permissions_(key_permissions) {
82 DCHECK(profile_prefs_);
83 DCHECK(profile_policies_);
66 DCHECK(key_permissions_); 84 DCHECK(key_permissions_);
67 if (state_store_value) 85 if (state_store_value)
68 KeyEntriesFromState(*state_store_value); 86 KeyEntriesFromState(*state_store_value);
69 } 87 }
70 88
71 KeyPermissions::PermissionsForExtension::~PermissionsForExtension() { 89 KeyPermissions::PermissionsForExtension::~PermissionsForExtension() {
72 } 90 }
73 91
74 bool KeyPermissions::PermissionsForExtension::CanUseKeyForSigning( 92 bool KeyPermissions::PermissionsForExtension::CanUseKeyForSigning(
75 const std::string& public_key_spki_der) { 93 const std::string& public_key_spki_der) {
76 std::string public_key_spki_der_b64; 94 std::string public_key_spki_der_b64;
77 base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64); 95 base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64);
78 96
79 KeyEntry* matching_entry = GetStateStoreEntry(public_key_spki_der_b64); 97 KeyEntry* matching_entry = GetStateStoreEntry(public_key_spki_der_b64);
98 // In any case, we allow the generating extension to use the generated key a
99 // single time for signing arbitrary data. The reason is, that the extension
100 // usually has to sign a certification request containing the public key in
101 // order to obtain a certificate for the key.
102 // That means, once a certificate authority generated a certificate for the
103 // key, the generating extension doesn't have access to the key anymore,
104 // except if explicitly permitted by the Administrator.
battre 2015/06/17 15:11:47 nit: administrator
pneubeck (no reviews) 2015/06/18 08:45:15 Done.
105 if (matching_entry->sign_once)
106 return true;
80 107
81 return matching_entry->sign_once || matching_entry->sign_unlimited; 108 // Usage of corporate keys is solely determined by policy. The user must not
109 // circumvent this decision.
110 if (key_permissions_->IsCorporateKey(public_key_spki_der_b64))
111 return PolicyAllowsCorporateKeyUsage();
112
113 // Only permissions for keys that are not designated for corporate usage are
114 // determined by user decisions.
115 return matching_entry->sign_unlimited;
82 } 116 }
83 117
84 void KeyPermissions::PermissionsForExtension::SetKeyUsedForSigning( 118 void KeyPermissions::PermissionsForExtension::SetKeyUsedForSigning(
85 const std::string& public_key_spki_der) { 119 const std::string& public_key_spki_der) {
86 std::string public_key_spki_der_b64; 120 std::string public_key_spki_der_b64;
87 base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64); 121 base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64);
88 122
89 KeyEntry* matching_entry = GetStateStoreEntry(public_key_spki_der_b64); 123 KeyEntry* matching_entry = GetStateStoreEntry(public_key_spki_der_b64);
90 124
91 if (!matching_entry->sign_once) { 125 if (!matching_entry->sign_once) {
(...skipping 15 matching lines...) Expand all
107 141
108 KeyEntry* matching_entry = GetStateStoreEntry(public_key_spki_der_b64); 142 KeyEntry* matching_entry = GetStateStoreEntry(public_key_spki_der_b64);
109 143
110 if (matching_entry->sign_once) { 144 if (matching_entry->sign_once) {
111 VLOG(1) << "Key is already allowed for signing, skipping."; 145 VLOG(1) << "Key is already allowed for signing, skipping.";
112 return; 146 return;
113 } 147 }
114 148
115 matching_entry->sign_once = true; 149 matching_entry->sign_once = true;
116 WriteToStateStore(); 150 WriteToStateStore();
151
152 DictionaryPrefUpdate update(profile_prefs_, prefs::kPlatformKeys);
153
154 scoped_ptr<base::DictionaryValue> new_pref_entry(new base::DictionaryValue);
155 new_pref_entry->SetStringWithoutPathExpansion(kPrefKeyUsage,
156 kPrefKeyUsageCorporate);
157
158 update->SetWithoutPathExpansion(public_key_spki_der_b64,
159 new_pref_entry.release());
117 } 160 }
118 161
119 void KeyPermissions::PermissionsForExtension::SetUserGrantedPermission( 162 void KeyPermissions::PermissionsForExtension::SetUserGrantedPermission(
120 const std::string& public_key_spki_der) { 163 const std::string& public_key_spki_der) {
164 if (!key_permissions_->CanUserGrantPermissionFor(public_key_spki_der)) {
165 LOG(WARNING) << "Tried to grant permission for a key although prohibited "
166 "(either key is a corporate key or this account is "
167 "managed).";
168 return;
169 }
170
121 std::string public_key_spki_der_b64; 171 std::string public_key_spki_der_b64;
122 base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64); 172 base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64);
123
124 KeyEntry* matching_entry = GetStateStoreEntry(public_key_spki_der_b64); 173 KeyEntry* matching_entry = GetStateStoreEntry(public_key_spki_der_b64);
125 174
126 if (matching_entry->sign_unlimited) { 175 if (matching_entry->sign_unlimited) {
127 VLOG(1) << "Key is already allowed for signing, skipping."; 176 VLOG(1) << "Key is already allowed for signing, skipping.";
128 return; 177 return;
129 } 178 }
130 179
131 matching_entry->sign_unlimited = true; 180 matching_entry->sign_unlimited = true;
132 WriteToStateStore(); 181 WriteToStateStore();
133 } 182 }
134 183
184 bool KeyPermissions::PermissionsForExtension::PolicyAllowsCorporateKeyUsage() {
185 const policy::PolicyMap& policies = profile_policies_->GetPolicies(
186 policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME, std::string()));
187 const base::Value* policy_value =
188 policies.GetValue(policy::key::kKeyPermissions);
189 if (!policy_value)
190 return false;
191
192 const base::DictionaryValue* key_permissions_map = nullptr;
193 policy_value->GetAsDictionary(&key_permissions_map);
194 if (!key_permissions_map) {
195 LOG(ERROR) << "Expected policy to be a dictionary.";
196 return false;
197 }
198
199 const base::DictionaryValue* key_permissions_for_ext = nullptr;
200 key_permissions_map->GetDictionaryWithoutPathExpansion(
201 extension_id_, &key_permissions_for_ext);
202 if (!key_permissions_for_ext)
203 return false;
204
205 bool allow_corporate_key_usage = false;
206 key_permissions_for_ext->GetBooleanWithoutPathExpansion(
207 kPolicyAllowCorporateKeyUsage, &allow_corporate_key_usage);
208
209 VLOG_IF(allow_corporate_key_usage, 2)
210 << "Policy allows usage of corporate keys by extension " << extension_id_;
211 return allow_corporate_key_usage;
212 }
213
135 void KeyPermissions::PermissionsForExtension::WriteToStateStore() { 214 void KeyPermissions::PermissionsForExtension::WriteToStateStore() {
136 key_permissions_->SetPlatformKeysOfExtension(extension_id_, 215 key_permissions_->SetPlatformKeysOfExtension(extension_id_,
137 KeyEntriesToState()); 216 KeyEntriesToState());
138 } 217 }
139 218
140 void KeyPermissions::PermissionsForExtension::KeyEntriesFromState( 219 void KeyPermissions::PermissionsForExtension::KeyEntriesFromState(
141 const base::Value& state) { 220 const base::Value& state) {
142 state_store_entries_.clear(); 221 state_store_entries_.clear();
143 222
144 const base::ListValue* entries = nullptr; 223 const base::ListValue* entries = nullptr;
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
208 // compare the DER (or its base64 encoding). 287 // compare the DER (or its base64 encoding).
209 if (entry.spki_b64 == public_key_spki_der_b64) 288 if (entry.spki_b64 == public_key_spki_der_b64)
210 return &entry; 289 return &entry;
211 } 290 }
212 291
213 state_store_entries_.push_back(KeyEntry(public_key_spki_der_b64)); 292 state_store_entries_.push_back(KeyEntry(public_key_spki_der_b64));
214 return &state_store_entries_.back(); 293 return &state_store_entries_.back();
215 } 294 }
216 295
217 KeyPermissions::KeyPermissions(bool profile_is_managed, 296 KeyPermissions::KeyPermissions(bool profile_is_managed,
297 PrefService* profile_prefs,
298 policy::PolicyService* profile_policies,
218 extensions::StateStore* extensions_state_store) 299 extensions::StateStore* extensions_state_store)
219 : profile_is_managed_(profile_is_managed), 300 : profile_is_managed_(profile_is_managed),
301 profile_prefs_(profile_prefs),
302 profile_policies_(profile_policies),
220 extensions_state_store_(extensions_state_store), 303 extensions_state_store_(extensions_state_store),
221 weak_factory_(this) { 304 weak_factory_(this) {
305 DCHECK(profile_prefs_);
306 DCHECK(extensions_state_store_);
307 DCHECK(!profile_is_managed_ || profile_policies_);
222 } 308 }
223 309
224 KeyPermissions::~KeyPermissions() { 310 KeyPermissions::~KeyPermissions() {
225 } 311 }
226 312
227 void KeyPermissions::GetPermissionsForExtension( 313 void KeyPermissions::GetPermissionsForExtension(
228 const std::string& extension_id, 314 const std::string& extension_id,
229 const PermissionsCallback& callback) { 315 const PermissionsCallback& callback) {
230 extensions_state_store_->GetExtensionValue( 316 extensions_state_store_->GetExtensionValue(
231 extension_id, kStateStorePlatformKeys, 317 extension_id, kStateStorePlatformKeys,
232 base::Bind(&KeyPermissions::CreatePermissionObjectAndPassToCallback, 318 base::Bind(&KeyPermissions::CreatePermissionObjectAndPassToCallback,
233 weak_factory_.GetWeakPtr(), extension_id, callback)); 319 weak_factory_.GetWeakPtr(), extension_id, callback));
234 } 320 }
235 321
236 bool KeyPermissions::CanUserGrantPermissionFor( 322 bool KeyPermissions::CanUserGrantPermissionFor(
237 const std::string& public_key_spki_der) { 323 const std::string& public_key_spki_der) {
238 // As keys cannot be tagged for non-corporate usage, the user can currently 324 // As keys cannot be tagged for non-corporate usage, the user can currently
239 // not grant any permissions if the profile is managed. 325 // not grant any permissions if the profile is managed.
240 return !profile_is_managed_; 326 if (profile_is_managed_)
327 return false;
328
329 std::string public_key_spki_der_b64;
330 base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64);
331
332 // If this profile is not managed but we find a corporate key, don't allow
333 // the user to grant permissions.
334 return !IsCorporateKey(public_key_spki_der_b64);
335 }
336
337 bool KeyPermissions::IsCorporateKey(
338 const std::string& public_key_spki_der_b64) {
339 const base::DictionaryValue* prefs_entry =
340 GetPrefsEntry(public_key_spki_der_b64);
341 if (prefs_entry) {
342 std::string key_usage;
343 prefs_entry->GetStringWithoutPathExpansion(kPrefKeyUsage, &key_usage);
344 return key_usage == kPrefKeyUsageCorporate;
345 }
346 return false;
347 }
348
349 void KeyPermissions::RegisterProfilePrefs(
350 user_prefs::PrefRegistrySyncable* registry) {
351 registry->RegisterDictionaryPref(prefs::kPlatformKeys);
352 }
353
354 void KeyPermissions::CreatePermissionObjectAndPassToCallback(
355 const std::string& extension_id,
356 const PermissionsCallback& callback,
357 scoped_ptr<base::Value> value) {
358 callback.Run(make_scoped_ptr(new PermissionsForExtension(
359 extension_id, value.Pass(), profile_prefs_, profile_policies_, this)));
241 } 360 }
242 361
243 void KeyPermissions::SetPlatformKeysOfExtension(const std::string& extension_id, 362 void KeyPermissions::SetPlatformKeysOfExtension(const std::string& extension_id,
244 scoped_ptr<base::Value> value) { 363 scoped_ptr<base::Value> value) {
245 extensions_state_store_->SetExtensionValue( 364 extensions_state_store_->SetExtensionValue(
246 extension_id, kStateStorePlatformKeys, value.Pass()); 365 extension_id, kStateStorePlatformKeys, value.Pass());
247 } 366 }
248 367
249 void KeyPermissions::CreatePermissionObjectAndPassToCallback( 368 const base::DictionaryValue* KeyPermissions::GetPrefsEntry(
250 const std::string& extension_id, 369 const std::string& public_key_spki_der_b64) {
251 const PermissionsCallback& callback, 370 const base::DictionaryValue* platform_keys =
252 scoped_ptr<base::Value> value) { 371 profile_prefs_->GetDictionary(prefs::kPlatformKeys);
253 callback.Run(make_scoped_ptr( 372
254 new PermissionsForExtension(extension_id, value.Pass(), this))); 373 const base::DictionaryValue* key_entry = nullptr;
374 platform_keys->GetDictionaryWithoutPathExpansion(public_key_spki_der_b64,
375 &key_entry);
376 return key_entry;
255 } 377 }
256 378
257 } // namespace chromeos 379 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698