| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 // From older versions of ChromeOS, this key can hold a list of base64 and | 28 // From older versions of ChromeOS, this key can hold a list of base64 and |
| 21 // DER-encoded SPKIs. A key can be used for signing at most once if it is part | 29 // DER-encoded SPKIs. A key can be used for signing at most once if it is part |
| 22 // of that list | 30 // of that list |
| 23 // and removed from that list afterwards. | 31 // and removed from that list afterwards. |
| 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 kPrefIsCorporateKey[] = "is_platform_key"; |
| 47 const char kPolicyAllowCorporateKeyUsage[] = "allowCorporateKeyUsage"; |
| 48 |
| 38 } // namespace | 49 } // namespace |
| 39 | 50 |
| 40 struct KeyPermissions::PermissionsForExtension::KeyEntry { | 51 struct KeyPermissions::PermissionsForExtension::KeyEntry { |
| 41 explicit KeyEntry(const std::string& public_key_spki_der_b64) | 52 explicit KeyEntry(const std::string& public_key_spki_der_b64) |
| 42 : spki_b64(public_key_spki_der_b64) {} | 53 : spki_b64(public_key_spki_der_b64) {} |
| 43 | 54 |
| 44 // The base64-encoded DER of a X.509 Subject Public Key Info. | 55 // The base64-encoded DER of a X.509 Subject Public Key Info. |
| 45 const std::string spki_b64; | 56 const std::string spki_b64; |
| 46 | 57 |
| 47 // True if the key can be used once for singing. | 58 // True if the key can be used once for singing. |
| 48 // This permission is granted if an extension generated a key using the | 59 // This permission is granted if an extension generated a key using the |
| 49 // enterprise.platformKeys API, so that it can build a certification request.. | 60 // enterprise.platformKeys API, so that it can build a certification request.. |
| 50 // After the first signing operation this permission will be revoked. | 61 // After the first signing operation this permission will be revoked. |
| 51 bool sign_once = false; | 62 bool sign_once = false; |
| 52 | 63 |
| 53 // True if the key can be used for signing an unlimited number of times. | 64 // 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 | 65 // 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 | 66 // 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. | 67 // This permission is granted until revoked by the user or the policy. |
| 58 bool sign_unlimited = false; | 68 bool sign_unlimited = false; |
| 59 }; | 69 }; |
| 60 | 70 |
| 61 KeyPermissions::PermissionsForExtension::PermissionsForExtension( | 71 KeyPermissions::PermissionsForExtension::PermissionsForExtension( |
| 62 const std::string& extension_id, | 72 const std::string& extension_id, |
| 63 scoped_ptr<base::Value> state_store_value, | 73 scoped_ptr<base::Value> state_store_value, |
| 74 PrefService* profile_prefs, |
| 75 policy::PolicyService* profile_policies, |
| 64 KeyPermissions* key_permissions) | 76 KeyPermissions* key_permissions) |
| 65 : extension_id_(extension_id), key_permissions_(key_permissions) { | 77 : extension_id_(extension_id), |
| 78 profile_prefs_(profile_prefs), |
| 79 profile_policies_(profile_policies), |
| 80 key_permissions_(key_permissions) { |
| 81 DCHECK(profile_prefs_); |
| 82 DCHECK(profile_policies_); |
| 66 DCHECK(key_permissions_); | 83 DCHECK(key_permissions_); |
| 67 if (state_store_value) | 84 if (state_store_value) |
| 68 KeyEntriesFromState(*state_store_value); | 85 KeyEntriesFromState(*state_store_value); |
| 69 } | 86 } |
| 70 | 87 |
| 71 KeyPermissions::PermissionsForExtension::~PermissionsForExtension() { | 88 KeyPermissions::PermissionsForExtension::~PermissionsForExtension() { |
| 72 } | 89 } |
| 73 | 90 |
| 74 bool KeyPermissions::PermissionsForExtension::CanUseKeyForSigning( | 91 bool KeyPermissions::PermissionsForExtension::CanUseKeyForSigning( |
| 75 const std::string& public_key_spki_der) { | 92 const std::string& public_key_spki_der) { |
| 76 KeyEntry* matching_entry = GetKeyEntry(public_key_spki_der); | 93 KeyEntry* matching_entry = GetStateStoreEntry(public_key_spki_der); |
| 94 if (matching_entry->sign_once) |
| 95 return true; |
| 77 | 96 |
| 78 return matching_entry->sign_once || matching_entry->sign_unlimited; | 97 if (key_permissions_->IsCorporateKey(public_key_spki_der)) { |
| 98 LOG(ERROR) << "is corporate key"; |
| 99 return PolicyAllowsCorporateKeyUsage(); |
| 100 } |
| 101 |
| 102 return matching_entry->sign_unlimited; |
| 79 } | 103 } |
| 80 | 104 |
| 81 void KeyPermissions::PermissionsForExtension::SetKeyUsedForSigning( | 105 void KeyPermissions::PermissionsForExtension::SetKeyUsedForSigning( |
| 82 const std::string& public_key_spki_der) { | 106 const std::string& public_key_spki_der) { |
| 83 KeyEntry* matching_entry = GetKeyEntry(public_key_spki_der); | 107 KeyEntry* matching_entry = GetStateStoreEntry(public_key_spki_der); |
| 84 | 108 |
| 85 if (!matching_entry->sign_once) { | 109 if (!matching_entry->sign_once) { |
| 86 if (matching_entry->sign_unlimited) | 110 if (matching_entry->sign_unlimited) |
| 87 VLOG(1) << "Key is already marked as not usable for signing, skipping."; | 111 VLOG(1) << "Key is already marked as not usable for signing, skipping."; |
| 88 else | 112 else |
| 89 LOG(ERROR) << "Key was not allowed for signing."; | 113 LOG(ERROR) << "Key was not allowed for signing."; |
| 90 return; | 114 return; |
| 91 } | 115 } |
| 92 | 116 |
| 93 matching_entry->sign_once = false; | 117 matching_entry->sign_once = false; |
| 94 WriteToStateStore(); | 118 WriteToStateStore(); |
| 95 } | 119 } |
| 96 | 120 |
| 97 void KeyPermissions::PermissionsForExtension::RegisterKeyForCorporateUsage( | 121 void KeyPermissions::PermissionsForExtension::RegisterKeyForCorporateUsage( |
| 98 const std::string& public_key_spki_der) { | 122 const std::string& public_key_spki_der) { |
| 99 KeyEntry* matching_entry = GetKeyEntry(public_key_spki_der); | 123 KeyEntry* matching_entry = GetStateStoreEntry(public_key_spki_der); |
| 100 | 124 |
| 101 if (matching_entry->sign_once) { | 125 if (matching_entry->sign_once) { |
| 102 VLOG(1) << "Key is already allowed for signing, skipping."; | 126 VLOG(1) << "Key is already allowed for signing, skipping."; |
| 103 return; | 127 return; |
| 104 } | 128 } |
| 105 | 129 |
| 106 matching_entry->sign_once = true; | 130 matching_entry->sign_once = true; |
| 107 WriteToStateStore(); | 131 WriteToStateStore(); |
| 132 |
| 133 DictionaryPrefUpdate update(profile_prefs_, prefs::kPlatformKeys); |
| 134 |
| 135 scoped_ptr<base::DictionaryValue> new_pref_entry(new base::DictionaryValue); |
| 136 new_pref_entry->SetBooleanWithoutPathExpansion(kPrefIsCorporateKey, true); |
| 137 |
| 138 std::string public_key_spki_der_b64; |
| 139 base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64); |
| 140 |
| 141 update->SetWithoutPathExpansion(public_key_spki_der_b64, |
| 142 new_pref_entry.release()); |
| 108 } | 143 } |
| 109 | 144 |
| 110 void KeyPermissions::PermissionsForExtension::SetUserGrantedPermission( | 145 void KeyPermissions::PermissionsForExtension::SetUserGrantedPermission( |
| 111 const std::string& public_key_spki_der) { | 146 const std::string& public_key_spki_der) { |
| 112 KeyEntry* matching_entry = GetKeyEntry(public_key_spki_der); | 147 if (key_permissions_->IsCorporateKey(public_key_spki_der)) { |
| 148 LOG(WARNING) << "Tried to grant permission for corporate key."; |
| 149 return; |
| 150 } |
| 151 |
| 152 KeyEntry* matching_entry = GetStateStoreEntry(public_key_spki_der); |
| 113 | 153 |
| 114 if (matching_entry->sign_unlimited) { | 154 if (matching_entry->sign_unlimited) { |
| 115 VLOG(1) << "Key is already allowed for signing, skipping."; | 155 VLOG(1) << "Key is already allowed for signing, skipping."; |
| 116 return; | 156 return; |
| 117 } | 157 } |
| 118 | 158 |
| 119 matching_entry->sign_unlimited = true; | 159 matching_entry->sign_unlimited = true; |
| 120 WriteToStateStore(); | 160 WriteToStateStore(); |
| 121 } | 161 } |
| 122 | 162 |
| 163 bool KeyPermissions::PermissionsForExtension::PolicyAllowsCorporateKeyUsage() { |
| 164 const policy::PolicyMap& policies = profile_policies_->GetPolicies( |
| 165 policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME, std::string())); |
| 166 const base::Value* policy_value = |
| 167 policies.GetValue(policy::key::kKeyPermissions); |
| 168 LOG(ERROR) << "policy value " << policy_value; |
| 169 if (!policy_value) |
| 170 return false; |
| 171 LOG(ERROR) << *policy_value; |
| 172 |
| 173 const base::DictionaryValue* key_permissions_map = nullptr; |
| 174 policy_value->GetAsDictionary(&key_permissions_map); |
| 175 if (!key_permissions_map) { |
| 176 LOG(ERROR) << "Expected policy to be a dictionary."; |
| 177 return false; |
| 178 } |
| 179 |
| 180 const base::DictionaryValue* key_permissions_for_ext = nullptr; |
| 181 key_permissions_map->GetDictionaryWithoutPathExpansion( |
| 182 extension_id_, &key_permissions_for_ext); |
| 183 if (!key_permissions_for_ext) { |
| 184 LOG(ERROR) << "no entry for " << extension_id_; |
| 185 return false; |
| 186 } |
| 187 |
| 188 bool allow_corporate_key_usage = false; |
| 189 key_permissions_for_ext->GetBooleanWithoutPathExpansion( |
| 190 kPolicyAllowCorporateKeyUsage, &allow_corporate_key_usage); |
| 191 |
| 192 LOG(ERROR) << "policy allows corp usage " << allow_corporate_key_usage; |
| 193 return allow_corporate_key_usage; |
| 194 } |
| 195 |
| 123 void KeyPermissions::PermissionsForExtension::WriteToStateStore() { | 196 void KeyPermissions::PermissionsForExtension::WriteToStateStore() { |
| 124 key_permissions_->SetPlatformKeysOfExtension(extension_id_, | 197 key_permissions_->SetPlatformKeysOfExtension(extension_id_, |
| 125 KeyEntriesToState()); | 198 KeyEntriesToState()); |
| 126 } | 199 } |
| 127 | 200 |
| 128 void KeyPermissions::PermissionsForExtension::KeyEntriesFromState( | 201 void KeyPermissions::PermissionsForExtension::KeyEntriesFromState( |
| 129 const base::Value& state) { | 202 const base::Value& state) { |
| 130 state_store_entries_.clear(); | 203 state_store_entries_.clear(); |
| 131 | 204 |
| 132 const base::ListValue* entries = nullptr; | 205 const base::ListValue* entries = nullptr; |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 184 entry.sign_unlimited); | 257 entry.sign_unlimited); |
| 185 } | 258 } |
| 186 new_state->Append(new_entry.release()); | 259 new_state->Append(new_entry.release()); |
| 187 } | 260 } |
| 188 return new_state.Pass(); | 261 return new_state.Pass(); |
| 189 } | 262 } |
| 190 | 263 |
| 191 // Searches |platform_keys| for an entry for |public_key_spki_der_b64|. If found | 264 // Searches |platform_keys| for an entry for |public_key_spki_der_b64|. If found |
| 192 // returns a pointer to it, otherwise returns null. | 265 // returns a pointer to it, otherwise returns null. |
| 193 KeyPermissions::PermissionsForExtension::KeyEntry* | 266 KeyPermissions::PermissionsForExtension::KeyEntry* |
| 194 KeyPermissions::PermissionsForExtension::GetKeyEntry( | 267 KeyPermissions::PermissionsForExtension::GetStateStoreEntry( |
| 195 const std::string& public_key_spki_der) { | 268 const std::string& public_key_spki_der) { |
| 196 std::string public_key_spki_der_b64; | 269 std::string public_key_spki_der_b64; |
| 197 base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64); | 270 base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64); |
| 198 | 271 |
| 199 for (KeyEntry& entry : state_store_entries_) { | 272 for (KeyEntry& entry : state_store_entries_) { |
| 200 // For every ASN.1 value there is exactly one DER encoding, so it is fine to | 273 // For every ASN.1 value there is exactly one DER encoding, so it is fine to |
| 201 // compare the DER (or its base64 encoding). | 274 // compare the DER (or its base64 encoding). |
| 202 if (entry.spki_b64 == public_key_spki_der_b64) | 275 if (entry.spki_b64 == public_key_spki_der_b64) |
| 203 return &entry; | 276 return &entry; |
| 204 } | 277 } |
| 205 | 278 |
| 206 state_store_entries_.push_back(KeyEntry(public_key_spki_der_b64)); | 279 state_store_entries_.push_back(KeyEntry(public_key_spki_der_b64)); |
| 207 return &state_store_entries_.back(); | 280 return &state_store_entries_.back(); |
| 208 } | 281 } |
| 209 | 282 |
| 210 KeyPermissions::KeyPermissions(extensions::StateStore* extensions_state_store) | 283 KeyPermissions::KeyPermissions(PrefService* profile_prefs, |
| 211 : extensions_state_store_(extensions_state_store), weak_factory_(this) { | 284 bool profile_is_managed, |
| 285 policy::PolicyService* profile_policies, |
| 286 extensions::StateStore* extensions_state_store) |
| 287 : profile_prefs_(profile_prefs), |
| 288 profile_is_managed_(profile_is_managed), |
| 289 profile_policies_(profile_policies), |
| 290 extensions_state_store_(extensions_state_store), |
| 291 weak_factory_(this) { |
| 292 DCHECK(profile_prefs_); |
| 293 DCHECK(extensions_state_store_); |
| 294 DCHECK(!profile_is_managed_ || profile_policies_); |
| 212 } | 295 } |
| 213 | 296 |
| 214 KeyPermissions::~KeyPermissions() { | 297 KeyPermissions::~KeyPermissions() { |
| 215 } | 298 } |
| 216 | 299 |
| 217 void KeyPermissions::GetPermissionsForExtension( | 300 void KeyPermissions::GetPermissionsForExtension( |
| 218 const std::string& extension_id, | 301 const std::string& extension_id, |
| 219 const PermissionsCallback& callback) { | 302 const PermissionsCallback& callback) { |
| 220 extensions_state_store_->GetExtensionValue( | 303 extensions_state_store_->GetExtensionValue( |
| 221 extension_id, kStateStorePlatformKeys, | 304 extension_id, kStateStorePlatformKeys, |
| 222 base::Bind(&KeyPermissions::CreatePermissionObjectAndPassToCallback, | 305 base::Bind(&KeyPermissions::CreatePermissionObjectAndPassToCallback, |
| 223 weak_factory_.GetWeakPtr(), extension_id, callback)); | 306 weak_factory_.GetWeakPtr(), extension_id, callback)); |
| 224 } | 307 } |
| 225 | 308 |
| 309 bool KeyPermissions::CanUserGrantPermissionFor( |
| 310 const std::string& public_key_spki_der) { |
| 311 LOG(ERROR) << "profile is managed " << profile_is_managed_; |
| 312 // As keys cannot be tagged for non-corporate usage, the user can currently |
| 313 // not grant any permissions if the profile is managed. |
| 314 if (profile_is_managed_) |
| 315 return false; |
| 316 |
| 317 // If this profile is not managed but we find a corporate key, don't allow |
| 318 // the user to grant permissions. |
| 319 return !IsCorporateKey(public_key_spki_der); |
| 320 } |
| 321 |
| 322 bool KeyPermissions::IsCorporateKey(const std::string& public_key_spki_der) { |
| 323 const base::DictionaryValue* prefs_entry = GetPrefsEntry(public_key_spki_der); |
| 324 if (prefs_entry) { |
| 325 bool is_corporate_key = false; |
| 326 prefs_entry->GetBooleanWithoutPathExpansion(kPrefIsCorporateKey, |
| 327 &is_corporate_key); |
| 328 return is_corporate_key; |
| 329 } |
| 330 return false; |
| 331 } |
| 332 |
| 333 void KeyPermissions::RegisterProfilePrefs( |
| 334 user_prefs::PrefRegistrySyncable* registry) { |
| 335 registry->RegisterDictionaryPref(prefs::kPlatformKeys); |
| 336 } |
| 337 |
| 338 void KeyPermissions::CreatePermissionObjectAndPassToCallback( |
| 339 const std::string& extension_id, |
| 340 const PermissionsCallback& callback, |
| 341 scoped_ptr<base::Value> value) { |
| 342 callback.Run(make_scoped_ptr(new PermissionsForExtension( |
| 343 extension_id, value.Pass(), profile_prefs_, profile_policies_, this))); |
| 344 } |
| 345 |
| 226 void KeyPermissions::SetPlatformKeysOfExtension(const std::string& extension_id, | 346 void KeyPermissions::SetPlatformKeysOfExtension(const std::string& extension_id, |
| 227 scoped_ptr<base::Value> value) { | 347 scoped_ptr<base::Value> value) { |
| 228 extensions_state_store_->SetExtensionValue( | 348 extensions_state_store_->SetExtensionValue( |
| 229 extension_id, kStateStorePlatformKeys, value.Pass()); | 349 extension_id, kStateStorePlatformKeys, value.Pass()); |
| 230 } | 350 } |
| 231 | 351 |
| 232 void KeyPermissions::CreatePermissionObjectAndPassToCallback( | 352 const base::DictionaryValue* KeyPermissions::GetPrefsEntry( |
| 233 const std::string& extension_id, | 353 const std::string& public_key_spki_der) { |
| 234 const PermissionsCallback& callback, | 354 std::string public_key_spki_der_b64; |
| 235 scoped_ptr<base::Value> value) { | 355 base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64); |
| 236 callback.Run(make_scoped_ptr( | 356 |
| 237 new PermissionsForExtension(extension_id, value.Pass(), this))); | 357 const base::DictionaryValue* platform_keys = |
| 358 profile_prefs_->GetDictionary(prefs::kPlatformKeys); |
| 359 |
| 360 const base::DictionaryValue* key_entry = nullptr; |
| 361 platform_keys->GetDictionaryWithoutPathExpansion(public_key_spki_der_b64, |
| 362 &key_entry); |
| 363 return key_entry; |
| 238 } | 364 } |
| 239 | 365 |
| 240 } // namespace chromeos | 366 } // namespace chromeos |
| OLD | NEW |