Popular sites on the NTP: check that experiment group StartsWith (rather than IS...
[chromium-blink-merge.git] / chrome / browser / chromeos / platform_keys / key_permissions.cc
blobe080a63b6a179657a5ff014808bec3e30b655eb0
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
3 // found in the LICENSE file.
5 #include "chrome/browser/chromeos/platform_keys/key_permissions.h"
7 #include "base/base64.h"
8 #include "base/bind.h"
9 #include "base/callback.h"
10 #include "base/logging.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/prefs/scoped_user_pref_update.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"
19 #include "extensions/browser/state_store.h"
20 #include "policy/policy_constants.h"
22 namespace chromeos {
24 namespace {
26 // The key at which platform key specific data is stored in each extension's
27 // state store.
29 // From older versions of ChromeOS, this key can hold a list of base64 and
30 // DER-encoded SPKIs. A key can be used for signing at most once if it is part
31 // of that list.
33 // The current format of data that is written to the PlatformKeys field is a
34 // list of serialized KeyEntry objects:
35 // { 'SPKI': string,
36 // 'signOnce': bool, // if not present, defaults to false
37 // 'signUnlimited': bool // if not present, defaults to false
38 // }
40 // Do not change this constant as clients will lose their existing state.
41 const char kStateStorePlatformKeys[] = "PlatformKeys";
42 const char kStateStoreSPKI[] = "SPKI";
43 const char kStateStoreSignOnce[] = "signOnce";
44 const char kStateStoreSignUnlimited[] = "signUnlimited";
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";
63 const char kPolicyAllowCorporateKeyUsage[] = "allowCorporateKeyUsage";
65 } // namespace
67 struct KeyPermissions::PermissionsForExtension::KeyEntry {
68 explicit KeyEntry(const std::string& public_key_spki_der_b64)
69 : spki_b64(public_key_spki_der_b64) {}
71 // The base64-encoded DER of a X.509 Subject Public Key Info.
72 std::string spki_b64;
74 // True if the key can be used once for singing.
75 // This permission is granted if an extension generated a key using the
76 // enterprise.platformKeys API, so that it can build a certification request.
77 // After the first signing operation this permission will be revoked.
78 bool sign_once = false;
80 // True if the key can be used for signing an unlimited number of times.
81 // This permission is granted by the user to allow the extension to use the
82 // key for signing through the enterprise.platformKeys or platformKeys API.
83 // This permission is granted until revoked by the user or the policy.
84 bool sign_unlimited = false;
87 KeyPermissions::PermissionsForExtension::PermissionsForExtension(
88 const std::string& extension_id,
89 scoped_ptr<base::Value> state_store_value,
90 PrefService* profile_prefs,
91 policy::PolicyService* profile_policies,
92 KeyPermissions* 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_);
99 DCHECK(key_permissions_);
100 if (state_store_value)
101 KeyEntriesFromState(*state_store_value);
104 KeyPermissions::PermissionsForExtension::~PermissionsForExtension() {
107 bool KeyPermissions::PermissionsForExtension::CanUseKeyForSigning(
108 const std::string& public_key_spki_der) {
109 std::string public_key_spki_der_b64;
110 base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64);
112 KeyEntry* matching_entry = GetStateStoreEntry(public_key_spki_der_b64);
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;
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();
129 // Only permissions for keys that are not designated for corporate usage are
130 // determined by user decisions.
131 return matching_entry->sign_unlimited;
134 void KeyPermissions::PermissionsForExtension::SetKeyUsedForSigning(
135 const std::string& public_key_spki_der) {
136 std::string public_key_spki_der_b64;
137 base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64);
139 KeyEntry* matching_entry = GetStateStoreEntry(public_key_spki_der_b64);
141 if (!matching_entry->sign_once) {
142 if (matching_entry->sign_unlimited)
143 VLOG(1) << "Key is already marked as not usable for signing, skipping.";
144 else
145 LOG(ERROR) << "Key was not allowed for signing.";
146 return;
149 matching_entry->sign_once = false;
150 WriteToStateStore();
153 void KeyPermissions::PermissionsForExtension::RegisterKeyForCorporateUsage(
154 const std::string& public_key_spki_der) {
155 std::string public_key_spki_der_b64;
156 base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64);
158 KeyEntry* matching_entry = GetStateStoreEntry(public_key_spki_der_b64);
160 if (matching_entry->sign_once) {
161 VLOG(1) << "Key is already allowed for signing, skipping.";
162 return;
165 matching_entry->sign_once = true;
166 WriteToStateStore();
168 DictionaryPrefUpdate update(profile_prefs_, prefs::kPlatformKeys);
170 scoped_ptr<base::DictionaryValue> new_pref_entry(new base::DictionaryValue);
171 new_pref_entry->SetStringWithoutPathExpansion(kPrefKeyUsage,
172 kPrefKeyUsageCorporate);
174 update->SetWithoutPathExpansion(public_key_spki_der_b64,
175 new_pref_entry.release());
178 void KeyPermissions::PermissionsForExtension::SetUserGrantedPermission(
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;
187 std::string public_key_spki_der_b64;
188 base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64);
189 KeyEntry* matching_entry = GetStateStoreEntry(public_key_spki_der_b64);
191 if (matching_entry->sign_unlimited) {
192 VLOG(1) << "Key is already allowed for signing, skipping.";
193 return;
196 matching_entry->sign_unlimited = true;
197 WriteToStateStore();
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;
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;
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;
222 bool allow_corporate_key_usage = false;
223 key_permissions_for_ext->GetBooleanWithoutPathExpansion(
224 kPolicyAllowCorporateKeyUsage, &allow_corporate_key_usage);
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;
231 void KeyPermissions::PermissionsForExtension::WriteToStateStore() {
232 key_permissions_->SetPlatformKeysOfExtension(extension_id_,
233 KeyEntriesToState());
236 void KeyPermissions::PermissionsForExtension::KeyEntriesFromState(
237 const base::Value& state) {
238 state_store_entries_.clear();
240 const base::ListValue* entries = nullptr;
241 if (!state.GetAsList(&entries)) {
242 LOG(ERROR) << "Found a state store of wrong type.";
243 return;
245 for (const base::Value* entry : *entries) {
246 if (!entry) {
247 LOG(ERROR) << "Found invalid NULL entry in PlatformKeys state store.";
248 continue;
251 std::string spki_b64;
252 const base::DictionaryValue* dict_entry = nullptr;
253 if (entry->GetAsString(&spki_b64)) {
254 // This handles the case that the store contained a plain list of base64
255 // and DER-encoded SPKIs from an older version of ChromeOS.
256 KeyEntry new_entry(spki_b64);
257 new_entry.sign_once = true;
258 state_store_entries_.push_back(new_entry);
259 } else if (entry->GetAsDictionary(&dict_entry)) {
260 dict_entry->GetStringWithoutPathExpansion(kStateStoreSPKI, &spki_b64);
261 KeyEntry new_entry(spki_b64);
262 dict_entry->GetBooleanWithoutPathExpansion(kStateStoreSignOnce,
263 &new_entry.sign_once);
264 dict_entry->GetBooleanWithoutPathExpansion(kStateStoreSignUnlimited,
265 &new_entry.sign_unlimited);
266 state_store_entries_.push_back(new_entry);
267 } else {
268 LOG(ERROR) << "Found invalid entry of type " << entry->GetType()
269 << " in PlatformKeys state store.";
270 continue;
275 scoped_ptr<base::Value>
276 KeyPermissions::PermissionsForExtension::KeyEntriesToState() {
277 scoped_ptr<base::ListValue> new_state(new base::ListValue);
278 for (const KeyEntry& entry : state_store_entries_) {
279 // Drop entries that the extension doesn't have any permissions for anymore.
280 if (!entry.sign_once && !entry.sign_unlimited)
281 continue;
283 scoped_ptr<base::DictionaryValue> new_entry(new base::DictionaryValue);
284 new_entry->SetStringWithoutPathExpansion(kStateStoreSPKI, entry.spki_b64);
285 // Omit writing default values, namely |false|.
286 if (entry.sign_once) {
287 new_entry->SetBooleanWithoutPathExpansion(kStateStoreSignOnce,
288 entry.sign_once);
290 if (entry.sign_unlimited) {
291 new_entry->SetBooleanWithoutPathExpansion(kStateStoreSignUnlimited,
292 entry.sign_unlimited);
294 new_state->Append(new_entry.release());
296 return new_state.Pass();
299 KeyPermissions::PermissionsForExtension::KeyEntry*
300 KeyPermissions::PermissionsForExtension::GetStateStoreEntry(
301 const std::string& public_key_spki_der_b64) {
302 for (KeyEntry& entry : state_store_entries_) {
303 // For every ASN.1 value there is exactly one DER encoding, so it is fine to
304 // compare the DER (or its base64 encoding).
305 if (entry.spki_b64 == public_key_spki_der_b64)
306 return &entry;
309 state_store_entries_.push_back(KeyEntry(public_key_spki_der_b64));
310 return &state_store_entries_.back();
313 KeyPermissions::KeyPermissions(bool profile_is_managed,
314 PrefService* profile_prefs,
315 policy::PolicyService* profile_policies,
316 extensions::StateStore* extensions_state_store)
317 : profile_is_managed_(profile_is_managed),
318 profile_prefs_(profile_prefs),
319 profile_policies_(profile_policies),
320 extensions_state_store_(extensions_state_store),
321 weak_factory_(this) {
322 DCHECK(profile_prefs_);
323 DCHECK(extensions_state_store_);
324 DCHECK(!profile_is_managed_ || profile_policies_);
327 KeyPermissions::~KeyPermissions() {
330 void KeyPermissions::GetPermissionsForExtension(
331 const std::string& extension_id,
332 const PermissionsCallback& callback) {
333 extensions_state_store_->GetExtensionValue(
334 extension_id, kStateStorePlatformKeys,
335 base::Bind(&KeyPermissions::CreatePermissionObjectAndPassToCallback,
336 weak_factory_.GetWeakPtr(), extension_id, callback));
339 bool KeyPermissions::CanUserGrantPermissionFor(
340 const std::string& public_key_spki_der) const {
341 // As keys cannot be tagged for non-corporate usage, the user can currently
342 // not grant any permissions if the profile is managed.
343 if (profile_is_managed_)
344 return false;
346 std::string public_key_spki_der_b64;
347 base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64);
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);
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;
363 return false;
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);
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)));
380 void KeyPermissions::SetPlatformKeysOfExtension(const std::string& extension_id,
381 scoped_ptr<base::Value> value) {
382 extensions_state_store_->SetExtensionValue(
383 extension_id, kStateStorePlatformKeys, value.Pass());
386 const base::DictionaryValue* KeyPermissions::GetPrefsEntry(
387 const std::string& public_key_spki_der_b64) const {
388 const base::DictionaryValue* platform_keys =
389 profile_prefs_->GetDictionary(prefs::kPlatformKeys);
391 const base::DictionaryValue* key_entry = nullptr;
392 platform_keys->GetDictionaryWithoutPathExpansion(public_key_spki_der_b64,
393 &key_entry);
394 return key_entry;
397 } // namespace chromeos