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

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 // The profile pref prefs::kPlatformKeys stores a dictionary mapping from
47 // public key (base64 encoding of an DER-encoded SPKI) to key properties. The
48 // currently only key property is the key usage, which can either be undefined
49 // or "corporate". If a key is not present in the pref, the default for the key
50 // usage is undefined, which in particular means "not for corporate usage".
51 // E.g. the entry in the profile pref might look like:
52 // "platform_keys" : {
53 // "ABCDEF123" : {
54 // "keyUsage" : "corporate"
55 // },
56 // "abcdef567" : {
57 // "keyUsage" : "corporate"
58 // }
59 // }
60 const char kPrefKeyUsage[] = "keyUsage";
61 const char kPrefKeyUsageCorporate[] = "corporate";
62
63 const char kPolicyAllowCorporateKeyUsage[] = "allowCorporateKeyUsage";
64
38 } // namespace 65 } // namespace
39 66
40 struct KeyPermissions::PermissionsForExtension::KeyEntry { 67 struct KeyPermissions::PermissionsForExtension::KeyEntry {
41 explicit KeyEntry(const std::string& public_key_spki_der_b64) 68 explicit KeyEntry(const std::string& public_key_spki_der_b64)
42 : spki_b64(public_key_spki_der_b64) {} 69 : spki_b64(public_key_spki_der_b64) {}
43 70
44 // The base64-encoded DER of a X.509 Subject Public Key Info. 71 // The base64-encoded DER of a X.509 Subject Public Key Info.
45 std::string spki_b64; 72 std::string spki_b64;
46 73
47 // True if the key can be used once for singing. 74 // True if the key can be used once for singing.
48 // This permission is granted if an extension generated a key using the 75 // This permission is granted if an extension generated a key using the
49 // enterprise.platformKeys API, so that it can build a certification request. 76 // enterprise.platformKeys API, so that it can build a certification request.
50 // After the first signing operation this permission will be revoked. 77 // After the first signing operation this permission will be revoked.
51 bool sign_once = false; 78 bool sign_once = false;
52 79
53 // True if the key can be used for signing an unlimited number of times. 80 // 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 81 // 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 82 // 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. 83 // This permission is granted until revoked by the user or the policy.
58 bool sign_unlimited = false; 84 bool sign_unlimited = false;
59 }; 85 };
60 86
61 KeyPermissions::PermissionsForExtension::PermissionsForExtension( 87 KeyPermissions::PermissionsForExtension::PermissionsForExtension(
62 const std::string& extension_id, 88 const std::string& extension_id,
63 scoped_ptr<base::Value> state_store_value, 89 scoped_ptr<base::Value> state_store_value,
90 PrefService* profile_prefs,
91 policy::PolicyService* profile_policies,
64 KeyPermissions* key_permissions) 92 KeyPermissions* key_permissions)
65 : extension_id_(extension_id), key_permissions_(key_permissions) { 93 : extension_id_(extension_id),
94 profile_prefs_(profile_prefs),
95 profile_policies_(profile_policies),
96 key_permissions_(key_permissions) {
97 DCHECK(profile_prefs_);
98 DCHECK(profile_policies_);
66 DCHECK(key_permissions_); 99 DCHECK(key_permissions_);
67 if (state_store_value) 100 if (state_store_value)
68 KeyEntriesFromState(*state_store_value); 101 KeyEntriesFromState(*state_store_value);
69 } 102 }
70 103
71 KeyPermissions::PermissionsForExtension::~PermissionsForExtension() { 104 KeyPermissions::PermissionsForExtension::~PermissionsForExtension() {
72 } 105 }
73 106
74 bool KeyPermissions::PermissionsForExtension::CanUseKeyForSigning( 107 bool KeyPermissions::PermissionsForExtension::CanUseKeyForSigning(
75 const std::string& public_key_spki_der) { 108 const std::string& public_key_spki_der) {
76 std::string public_key_spki_der_b64; 109 std::string public_key_spki_der_b64;
77 base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64); 110 base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64);
78 111
79 KeyEntry* matching_entry = GetStateStoreEntry(public_key_spki_der_b64); 112 KeyEntry* matching_entry = GetStateStoreEntry(public_key_spki_der_b64);
80 113
81 return matching_entry->sign_once || matching_entry->sign_unlimited; 114 // In any case, we allow the generating extension to use the generated key a
115 // single time for signing arbitrary data. The reason is, that the extension
116 // usually has to sign a certification request containing the public key in
117 // order to obtain a certificate for the key.
118 // That means, once a certificate authority generated a certificate for the
119 // key, the generating extension doesn't have access to the key anymore,
120 // except if explicitly permitted by the administrator.
121 if (matching_entry->sign_once)
122 return true;
123
124 // Usage of corporate keys is solely determined by policy. The user must not
125 // circumvent this decision.
126 if (key_permissions_->IsCorporateKey(public_key_spki_der_b64))
127 return PolicyAllowsCorporateKeyUsage();
128
129 // Only permissions for keys that are not designated for corporate usage are
130 // determined by user decisions.
131 return matching_entry->sign_unlimited;
82 } 132 }
83 133
84 void KeyPermissions::PermissionsForExtension::SetKeyUsedForSigning( 134 void KeyPermissions::PermissionsForExtension::SetKeyUsedForSigning(
85 const std::string& public_key_spki_der) { 135 const std::string& public_key_spki_der) {
86 std::string public_key_spki_der_b64; 136 std::string public_key_spki_der_b64;
87 base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64); 137 base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64);
88 138
89 KeyEntry* matching_entry = GetStateStoreEntry(public_key_spki_der_b64); 139 KeyEntry* matching_entry = GetStateStoreEntry(public_key_spki_der_b64);
90 140
91 if (!matching_entry->sign_once) { 141 if (!matching_entry->sign_once) {
(...skipping 15 matching lines...) Expand all
107 157
108 KeyEntry* matching_entry = GetStateStoreEntry(public_key_spki_der_b64); 158 KeyEntry* matching_entry = GetStateStoreEntry(public_key_spki_der_b64);
109 159
110 if (matching_entry->sign_once) { 160 if (matching_entry->sign_once) {
111 VLOG(1) << "Key is already allowed for signing, skipping."; 161 VLOG(1) << "Key is already allowed for signing, skipping.";
112 return; 162 return;
113 } 163 }
114 164
115 matching_entry->sign_once = true; 165 matching_entry->sign_once = true;
116 WriteToStateStore(); 166 WriteToStateStore();
167
168 DictionaryPrefUpdate update(profile_prefs_, prefs::kPlatformKeys);
169
170 scoped_ptr<base::DictionaryValue> new_pref_entry(new base::DictionaryValue);
171 new_pref_entry->SetStringWithoutPathExpansion(kPrefKeyUsage,
172 kPrefKeyUsageCorporate);
173
174 update->SetWithoutPathExpansion(public_key_spki_der_b64,
175 new_pref_entry.release());
117 } 176 }
118 177
119 void KeyPermissions::PermissionsForExtension::SetUserGrantedPermission( 178 void KeyPermissions::PermissionsForExtension::SetUserGrantedPermission(
120 const std::string& public_key_spki_der) { 179 const std::string& public_key_spki_der) {
180 if (!key_permissions_->CanUserGrantPermissionFor(public_key_spki_der)) {
181 LOG(WARNING) << "Tried to grant permission for a key although prohibited "
182 "(either key is a corporate key or this account is "
183 "managed).";
184 return;
185 }
186
121 std::string public_key_spki_der_b64; 187 std::string public_key_spki_der_b64;
122 base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64); 188 base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64);
123
124 KeyEntry* matching_entry = GetStateStoreEntry(public_key_spki_der_b64); 189 KeyEntry* matching_entry = GetStateStoreEntry(public_key_spki_der_b64);
125 190
126 if (matching_entry->sign_unlimited) { 191 if (matching_entry->sign_unlimited) {
127 VLOG(1) << "Key is already allowed for signing, skipping."; 192 VLOG(1) << "Key is already allowed for signing, skipping.";
128 return; 193 return;
129 } 194 }
130 195
131 matching_entry->sign_unlimited = true; 196 matching_entry->sign_unlimited = true;
132 WriteToStateStore(); 197 WriteToStateStore();
133 } 198 }
134 199
200 bool KeyPermissions::PermissionsForExtension::PolicyAllowsCorporateKeyUsage()
201 const {
202 const policy::PolicyMap& policies = profile_policies_->GetPolicies(
203 policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME, std::string()));
204 const base::Value* policy_value =
205 policies.GetValue(policy::key::kKeyPermissions);
206 if (!policy_value)
207 return false;
208
209 const base::DictionaryValue* key_permissions_map = nullptr;
210 policy_value->GetAsDictionary(&key_permissions_map);
211 if (!key_permissions_map) {
212 LOG(ERROR) << "Expected policy to be a dictionary.";
213 return false;
214 }
215
216 const base::DictionaryValue* key_permissions_for_ext = nullptr;
217 key_permissions_map->GetDictionaryWithoutPathExpansion(
218 extension_id_, &key_permissions_for_ext);
219 if (!key_permissions_for_ext)
220 return false;
221
222 bool allow_corporate_key_usage = false;
223 key_permissions_for_ext->GetBooleanWithoutPathExpansion(
224 kPolicyAllowCorporateKeyUsage, &allow_corporate_key_usage);
225
226 VLOG_IF(allow_corporate_key_usage, 2)
227 << "Policy allows usage of corporate keys by extension " << extension_id_;
228 return allow_corporate_key_usage;
229 }
230
135 void KeyPermissions::PermissionsForExtension::WriteToStateStore() { 231 void KeyPermissions::PermissionsForExtension::WriteToStateStore() {
136 key_permissions_->SetPlatformKeysOfExtension(extension_id_, 232 key_permissions_->SetPlatformKeysOfExtension(extension_id_,
137 KeyEntriesToState()); 233 KeyEntriesToState());
138 } 234 }
139 235
140 void KeyPermissions::PermissionsForExtension::KeyEntriesFromState( 236 void KeyPermissions::PermissionsForExtension::KeyEntriesFromState(
141 const base::Value& state) { 237 const base::Value& state) {
142 state_store_entries_.clear(); 238 state_store_entries_.clear();
143 239
144 const base::ListValue* entries = nullptr; 240 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). 304 // compare the DER (or its base64 encoding).
209 if (entry.spki_b64 == public_key_spki_der_b64) 305 if (entry.spki_b64 == public_key_spki_der_b64)
210 return &entry; 306 return &entry;
211 } 307 }
212 308
213 state_store_entries_.push_back(KeyEntry(public_key_spki_der_b64)); 309 state_store_entries_.push_back(KeyEntry(public_key_spki_der_b64));
214 return &state_store_entries_.back(); 310 return &state_store_entries_.back();
215 } 311 }
216 312
217 KeyPermissions::KeyPermissions(bool profile_is_managed, 313 KeyPermissions::KeyPermissions(bool profile_is_managed,
314 PrefService* profile_prefs,
315 policy::PolicyService* profile_policies,
218 extensions::StateStore* extensions_state_store) 316 extensions::StateStore* extensions_state_store)
219 : profile_is_managed_(profile_is_managed), 317 : profile_is_managed_(profile_is_managed),
318 profile_prefs_(profile_prefs),
319 profile_policies_(profile_policies),
220 extensions_state_store_(extensions_state_store), 320 extensions_state_store_(extensions_state_store),
221 weak_factory_(this) { 321 weak_factory_(this) {
322 DCHECK(profile_prefs_);
323 DCHECK(extensions_state_store_);
324 DCHECK(!profile_is_managed_ || profile_policies_);
222 } 325 }
223 326
224 KeyPermissions::~KeyPermissions() { 327 KeyPermissions::~KeyPermissions() {
225 } 328 }
226 329
227 void KeyPermissions::GetPermissionsForExtension( 330 void KeyPermissions::GetPermissionsForExtension(
228 const std::string& extension_id, 331 const std::string& extension_id,
229 const PermissionsCallback& callback) { 332 const PermissionsCallback& callback) {
230 extensions_state_store_->GetExtensionValue( 333 extensions_state_store_->GetExtensionValue(
231 extension_id, kStateStorePlatformKeys, 334 extension_id, kStateStorePlatformKeys,
232 base::Bind(&KeyPermissions::CreatePermissionObjectAndPassToCallback, 335 base::Bind(&KeyPermissions::CreatePermissionObjectAndPassToCallback,
233 weak_factory_.GetWeakPtr(), extension_id, callback)); 336 weak_factory_.GetWeakPtr(), extension_id, callback));
234 } 337 }
235 338
236 bool KeyPermissions::CanUserGrantPermissionFor( 339 bool KeyPermissions::CanUserGrantPermissionFor(
237 const std::string& public_key_spki_der) { 340 const std::string& public_key_spki_der) const {
238 // As keys cannot be tagged for non-corporate usage, the user can currently 341 // As keys cannot be tagged for non-corporate usage, the user can currently
239 // not grant any permissions if the profile is managed. 342 // not grant any permissions if the profile is managed.
240 return !profile_is_managed_; 343 if (profile_is_managed_)
344 return false;
345
346 std::string public_key_spki_der_b64;
347 base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64);
348
349 // If this profile is not managed but we find a corporate key, don't allow
350 // the user to grant permissions.
351 return !IsCorporateKey(public_key_spki_der_b64);
352 }
353
354 bool KeyPermissions::IsCorporateKey(
355 const std::string& public_key_spki_der_b64) const {
356 const base::DictionaryValue* prefs_entry =
357 GetPrefsEntry(public_key_spki_der_b64);
358 if (prefs_entry) {
359 std::string key_usage;
360 prefs_entry->GetStringWithoutPathExpansion(kPrefKeyUsage, &key_usage);
361 return key_usage == kPrefKeyUsageCorporate;
362 }
363 return false;
364 }
365
366 void KeyPermissions::RegisterProfilePrefs(
367 user_prefs::PrefRegistrySyncable* registry) {
368 // For the format of the dictionary see the documentation at kPrefKeyUsage.
369 registry->RegisterDictionaryPref(prefs::kPlatformKeys);
370 }
371
372 void KeyPermissions::CreatePermissionObjectAndPassToCallback(
373 const std::string& extension_id,
374 const PermissionsCallback& callback,
375 scoped_ptr<base::Value> value) {
376 callback.Run(make_scoped_ptr(new PermissionsForExtension(
377 extension_id, value.Pass(), profile_prefs_, profile_policies_, this)));
241 } 378 }
242 379
243 void KeyPermissions::SetPlatformKeysOfExtension(const std::string& extension_id, 380 void KeyPermissions::SetPlatformKeysOfExtension(const std::string& extension_id,
244 scoped_ptr<base::Value> value) { 381 scoped_ptr<base::Value> value) {
245 extensions_state_store_->SetExtensionValue( 382 extensions_state_store_->SetExtensionValue(
246 extension_id, kStateStorePlatformKeys, value.Pass()); 383 extension_id, kStateStorePlatformKeys, value.Pass());
247 } 384 }
248 385
249 void KeyPermissions::CreatePermissionObjectAndPassToCallback( 386 const base::DictionaryValue* KeyPermissions::GetPrefsEntry(
250 const std::string& extension_id, 387 const std::string& public_key_spki_der_b64) const {
251 const PermissionsCallback& callback, 388 const base::DictionaryValue* platform_keys =
252 scoped_ptr<base::Value> value) { 389 profile_prefs_->GetDictionary(prefs::kPlatformKeys);
253 callback.Run(make_scoped_ptr( 390
254 new PermissionsForExtension(extension_id, value.Pass(), this))); 391 const base::DictionaryValue* key_entry = nullptr;
392 platform_keys->GetDictionaryWithoutPathExpansion(public_key_spki_der_b64,
393 &key_entry);
394 return key_entry;
255 } 395 }
256 396
257 } // namespace chromeos 397 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698