| Index: chrome/browser/chromeos/platform_keys/key_permissions.cc
|
| diff --git a/chrome/browser/chromeos/platform_keys/key_permissions.cc b/chrome/browser/chromeos/platform_keys/key_permissions.cc
|
| index 7f184a7c37f5ebf7ca71a4ebdc62f198f60f6eb9..e080a63b6a179657a5ff014808bec3e30b655eb0 100644
|
| --- a/chrome/browser/chromeos/platform_keys/key_permissions.cc
|
| +++ b/chrome/browser/chromeos/platform_keys/key_permissions.cc
|
| @@ -8,8 +8,16 @@
|
| #include "base/bind.h"
|
| #include "base/callback.h"
|
| #include "base/logging.h"
|
| +#include "base/prefs/pref_service.h"
|
| +#include "base/prefs/scoped_user_pref_update.h"
|
| #include "base/values.h"
|
| +#include "chrome/common/pref_names.h"
|
| +#include "components/policy/core/common/policy_map.h"
|
| +#include "components/policy/core/common/policy_namespace.h"
|
| +#include "components/policy/core/common/policy_service.h"
|
| +#include "components/pref_registry/pref_registry_syncable.h"
|
| #include "extensions/browser/state_store.h"
|
| +#include "policy/policy_constants.h"
|
|
|
| namespace chromeos {
|
|
|
| @@ -35,6 +43,25 @@ const char kStateStoreSPKI[] = "SPKI";
|
| const char kStateStoreSignOnce[] = "signOnce";
|
| const char kStateStoreSignUnlimited[] = "signUnlimited";
|
|
|
| +// The profile pref prefs::kPlatformKeys stores a dictionary mapping from
|
| +// public key (base64 encoding of an DER-encoded SPKI) to key properties. The
|
| +// currently only key property is the key usage, which can either be undefined
|
| +// or "corporate". If a key is not present in the pref, the default for the key
|
| +// usage is undefined, which in particular means "not for corporate usage".
|
| +// E.g. the entry in the profile pref might look like:
|
| +// "platform_keys" : {
|
| +// "ABCDEF123" : {
|
| +// "keyUsage" : "corporate"
|
| +// },
|
| +// "abcdef567" : {
|
| +// "keyUsage" : "corporate"
|
| +// }
|
| +// }
|
| +const char kPrefKeyUsage[] = "keyUsage";
|
| +const char kPrefKeyUsageCorporate[] = "corporate";
|
| +
|
| +const char kPolicyAllowCorporateKeyUsage[] = "allowCorporateKeyUsage";
|
| +
|
| } // namespace
|
|
|
| struct KeyPermissions::PermissionsForExtension::KeyEntry {
|
| @@ -51,9 +78,8 @@ struct KeyPermissions::PermissionsForExtension::KeyEntry {
|
| bool sign_once = false;
|
|
|
| // True if the key can be used for signing an unlimited number of times.
|
| - // This permission is granted by the user or by policy to allow the extension
|
| - // to use the key for signing through the enterprise.platformKeys or
|
| - // platformKeys API.
|
| + // This permission is granted by the user to allow the extension to use the
|
| + // key for signing through the enterprise.platformKeys or platformKeys API.
|
| // This permission is granted until revoked by the user or the policy.
|
| bool sign_unlimited = false;
|
| };
|
| @@ -61,8 +87,15 @@ struct KeyPermissions::PermissionsForExtension::KeyEntry {
|
| KeyPermissions::PermissionsForExtension::PermissionsForExtension(
|
| const std::string& extension_id,
|
| scoped_ptr<base::Value> state_store_value,
|
| + PrefService* profile_prefs,
|
| + policy::PolicyService* profile_policies,
|
| KeyPermissions* key_permissions)
|
| - : extension_id_(extension_id), key_permissions_(key_permissions) {
|
| + : extension_id_(extension_id),
|
| + profile_prefs_(profile_prefs),
|
| + profile_policies_(profile_policies),
|
| + key_permissions_(key_permissions) {
|
| + DCHECK(profile_prefs_);
|
| + DCHECK(profile_policies_);
|
| DCHECK(key_permissions_);
|
| if (state_store_value)
|
| KeyEntriesFromState(*state_store_value);
|
| @@ -78,7 +111,24 @@ bool KeyPermissions::PermissionsForExtension::CanUseKeyForSigning(
|
|
|
| KeyEntry* matching_entry = GetStateStoreEntry(public_key_spki_der_b64);
|
|
|
| - return matching_entry->sign_once || matching_entry->sign_unlimited;
|
| + // In any case, we allow the generating extension to use the generated key a
|
| + // single time for signing arbitrary data. The reason is, that the extension
|
| + // usually has to sign a certification request containing the public key in
|
| + // order to obtain a certificate for the key.
|
| + // That means, once a certificate authority generated a certificate for the
|
| + // key, the generating extension doesn't have access to the key anymore,
|
| + // except if explicitly permitted by the administrator.
|
| + if (matching_entry->sign_once)
|
| + return true;
|
| +
|
| + // Usage of corporate keys is solely determined by policy. The user must not
|
| + // circumvent this decision.
|
| + if (key_permissions_->IsCorporateKey(public_key_spki_der_b64))
|
| + return PolicyAllowsCorporateKeyUsage();
|
| +
|
| + // Only permissions for keys that are not designated for corporate usage are
|
| + // determined by user decisions.
|
| + return matching_entry->sign_unlimited;
|
| }
|
|
|
| void KeyPermissions::PermissionsForExtension::SetKeyUsedForSigning(
|
| @@ -114,13 +164,28 @@ void KeyPermissions::PermissionsForExtension::RegisterKeyForCorporateUsage(
|
|
|
| matching_entry->sign_once = true;
|
| WriteToStateStore();
|
| +
|
| + DictionaryPrefUpdate update(profile_prefs_, prefs::kPlatformKeys);
|
| +
|
| + scoped_ptr<base::DictionaryValue> new_pref_entry(new base::DictionaryValue);
|
| + new_pref_entry->SetStringWithoutPathExpansion(kPrefKeyUsage,
|
| + kPrefKeyUsageCorporate);
|
| +
|
| + update->SetWithoutPathExpansion(public_key_spki_der_b64,
|
| + new_pref_entry.release());
|
| }
|
|
|
| void KeyPermissions::PermissionsForExtension::SetUserGrantedPermission(
|
| const std::string& public_key_spki_der) {
|
| + if (!key_permissions_->CanUserGrantPermissionFor(public_key_spki_der)) {
|
| + LOG(WARNING) << "Tried to grant permission for a key although prohibited "
|
| + "(either key is a corporate key or this account is "
|
| + "managed).";
|
| + return;
|
| + }
|
| +
|
| std::string public_key_spki_der_b64;
|
| base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64);
|
| -
|
| KeyEntry* matching_entry = GetStateStoreEntry(public_key_spki_der_b64);
|
|
|
| if (matching_entry->sign_unlimited) {
|
| @@ -132,6 +197,37 @@ void KeyPermissions::PermissionsForExtension::SetUserGrantedPermission(
|
| WriteToStateStore();
|
| }
|
|
|
| +bool KeyPermissions::PermissionsForExtension::PolicyAllowsCorporateKeyUsage()
|
| + const {
|
| + const policy::PolicyMap& policies = profile_policies_->GetPolicies(
|
| + policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME, std::string()));
|
| + const base::Value* policy_value =
|
| + policies.GetValue(policy::key::kKeyPermissions);
|
| + if (!policy_value)
|
| + return false;
|
| +
|
| + const base::DictionaryValue* key_permissions_map = nullptr;
|
| + policy_value->GetAsDictionary(&key_permissions_map);
|
| + if (!key_permissions_map) {
|
| + LOG(ERROR) << "Expected policy to be a dictionary.";
|
| + return false;
|
| + }
|
| +
|
| + const base::DictionaryValue* key_permissions_for_ext = nullptr;
|
| + key_permissions_map->GetDictionaryWithoutPathExpansion(
|
| + extension_id_, &key_permissions_for_ext);
|
| + if (!key_permissions_for_ext)
|
| + return false;
|
| +
|
| + bool allow_corporate_key_usage = false;
|
| + key_permissions_for_ext->GetBooleanWithoutPathExpansion(
|
| + kPolicyAllowCorporateKeyUsage, &allow_corporate_key_usage);
|
| +
|
| + VLOG_IF(allow_corporate_key_usage, 2)
|
| + << "Policy allows usage of corporate keys by extension " << extension_id_;
|
| + return allow_corporate_key_usage;
|
| +}
|
| +
|
| void KeyPermissions::PermissionsForExtension::WriteToStateStore() {
|
| key_permissions_->SetPlatformKeysOfExtension(extension_id_,
|
| KeyEntriesToState());
|
| @@ -215,10 +311,17 @@ KeyPermissions::PermissionsForExtension::GetStateStoreEntry(
|
| }
|
|
|
| KeyPermissions::KeyPermissions(bool profile_is_managed,
|
| + PrefService* profile_prefs,
|
| + policy::PolicyService* profile_policies,
|
| extensions::StateStore* extensions_state_store)
|
| : profile_is_managed_(profile_is_managed),
|
| + profile_prefs_(profile_prefs),
|
| + profile_policies_(profile_policies),
|
| extensions_state_store_(extensions_state_store),
|
| weak_factory_(this) {
|
| + DCHECK(profile_prefs_);
|
| + DCHECK(extensions_state_store_);
|
| + DCHECK(!profile_is_managed_ || profile_policies_);
|
| }
|
|
|
| KeyPermissions::~KeyPermissions() {
|
| @@ -234,24 +337,61 @@ void KeyPermissions::GetPermissionsForExtension(
|
| }
|
|
|
| bool KeyPermissions::CanUserGrantPermissionFor(
|
| - const std::string& public_key_spki_der) {
|
| + const std::string& public_key_spki_der) const {
|
| // As keys cannot be tagged for non-corporate usage, the user can currently
|
| // not grant any permissions if the profile is managed.
|
| - return !profile_is_managed_;
|
| + if (profile_is_managed_)
|
| + return false;
|
| +
|
| + std::string public_key_spki_der_b64;
|
| + base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64);
|
| +
|
| + // If this profile is not managed but we find a corporate key, don't allow
|
| + // the user to grant permissions.
|
| + return !IsCorporateKey(public_key_spki_der_b64);
|
| }
|
|
|
| -void KeyPermissions::SetPlatformKeysOfExtension(const std::string& extension_id,
|
| - scoped_ptr<base::Value> value) {
|
| - extensions_state_store_->SetExtensionValue(
|
| - extension_id, kStateStorePlatformKeys, value.Pass());
|
| +bool KeyPermissions::IsCorporateKey(
|
| + const std::string& public_key_spki_der_b64) const {
|
| + const base::DictionaryValue* prefs_entry =
|
| + GetPrefsEntry(public_key_spki_der_b64);
|
| + if (prefs_entry) {
|
| + std::string key_usage;
|
| + prefs_entry->GetStringWithoutPathExpansion(kPrefKeyUsage, &key_usage);
|
| + return key_usage == kPrefKeyUsageCorporate;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +void KeyPermissions::RegisterProfilePrefs(
|
| + user_prefs::PrefRegistrySyncable* registry) {
|
| + // For the format of the dictionary see the documentation at kPrefKeyUsage.
|
| + registry->RegisterDictionaryPref(prefs::kPlatformKeys);
|
| }
|
|
|
| void KeyPermissions::CreatePermissionObjectAndPassToCallback(
|
| const std::string& extension_id,
|
| const PermissionsCallback& callback,
|
| scoped_ptr<base::Value> value) {
|
| - callback.Run(make_scoped_ptr(
|
| - new PermissionsForExtension(extension_id, value.Pass(), this)));
|
| + callback.Run(make_scoped_ptr(new PermissionsForExtension(
|
| + extension_id, value.Pass(), profile_prefs_, profile_policies_, this)));
|
| +}
|
| +
|
| +void KeyPermissions::SetPlatformKeysOfExtension(const std::string& extension_id,
|
| + scoped_ptr<base::Value> value) {
|
| + extensions_state_store_->SetExtensionValue(
|
| + extension_id, kStateStorePlatformKeys, value.Pass());
|
| +}
|
| +
|
| +const base::DictionaryValue* KeyPermissions::GetPrefsEntry(
|
| + const std::string& public_key_spki_der_b64) const {
|
| + const base::DictionaryValue* platform_keys =
|
| + profile_prefs_->GetDictionary(prefs::kPlatformKeys);
|
| +
|
| + const base::DictionaryValue* key_entry = nullptr;
|
| + platform_keys->GetDictionaryWithoutPathExpansion(public_key_spki_der_b64,
|
| + &key_entry);
|
| + return key_entry;
|
| }
|
|
|
| } // namespace chromeos
|
|
|