Index: chrome/browser/chromeos/platform_keys/platform_keys_service.cc |
diff --git a/chrome/browser/chromeos/platform_keys/platform_keys_service.cc b/chrome/browser/chromeos/platform_keys/platform_keys_service.cc |
index 4f9eb1761d888a5fcf95cfc08cecab7a476c01ba..01abc1ae0661865d7d969651ad9cd91812623cc2 100644 |
--- a/chrome/browser/chromeos/platform_keys/platform_keys_service.cc |
+++ b/chrome/browser/chromeos/platform_keys/platform_keys_service.cc |
@@ -17,18 +17,125 @@ using content::BrowserThread; |
namespace chromeos { |
+struct PlatformKeysService::KeyEntry { |
+ // The base64-encoded DER of a X.509 Subject Public Key Info. |
+ std::string spki_b64; |
+ |
+ // True if the key can be used once for singing. |
+ // This permission is granted if an extension generated a key using the |
+ // enterprise.platformKeys API, so that it can build a certification request.. |
+ // After the first signing operation this permission will be revoked. |
+ 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 until revoked by the user or the policy. |
+ bool sign_unlimited = false; |
+}; |
+ |
namespace { |
const char kErrorKeyNotAllowedForSigning[] = |
"This key is not allowed for signing. Either it was used for signing " |
"before or it was not correctly generated."; |
+ |
+// The key at which platform key specific data is stored in each extension's |
+// state store. |
+// From older versions of ChromeOS, this key can hold a list of base64 and |
+// DER-encoded SPKIs. A key can be used for signing at most once if it is part |
+// of that list |
+// and removed from that list afterwards. |
+// |
+// The current format of data that is written to the PlatformKeys field is a |
+// list of serialized KeyEntry objects: |
+// { 'SPKI': string, |
+// 'signOnce': bool, // if not present, defaults to false |
+// 'signUnlimited': bool // if not present, defaults to false |
+// } |
+// |
+// Do not change this constant as clients will lose their existing state. |
const char kStateStorePlatformKeys[] = "PlatformKeys"; |
+const char kStateStoreSPKI[] = "SPKI"; |
+const char kStateStoreSignOnce[] = "signOnce"; |
+const char kStateStoreSignUnlimited[] = "signUnlimited"; |
+ |
+scoped_ptr<PlatformKeysService::KeyEntries> KeyEntriesFromState( |
+ const base::Value& state) { |
+ scoped_ptr<PlatformKeysService::KeyEntries> new_entries( |
+ new PlatformKeysService::KeyEntries); |
+ |
+ const base::ListValue* entries = nullptr; |
+ if (!state.GetAsList(&entries)) { |
+ LOG(ERROR) << "Found a state store of wrong type."; |
+ return new_entries.Pass(); |
+ } |
+ for (const base::Value* entry : *entries) { |
+ if (!entry) { |
+ LOG(ERROR) << "Found invalid NULL entry in PlatformKeys state store."; |
+ continue; |
+ } |
+ |
+ PlatformKeysService::KeyEntry new_entry; |
+ const base::DictionaryValue* dict_entry = nullptr; |
+ if (entry->GetAsString(&new_entry.spki_b64)) { |
+ // This handles the case that the store contained a plain list of base64 |
+ // and DER-encoded SPKIs from an older version of ChromeOS. |
+ new_entry.sign_once = true; |
+ } else if (entry->GetAsDictionary(&dict_entry)) { |
+ dict_entry->GetStringWithoutPathExpansion(kStateStoreSPKI, |
+ &new_entry.spki_b64); |
+ dict_entry->GetBooleanWithoutPathExpansion(kStateStoreSignOnce, |
+ &new_entry.sign_once); |
+ dict_entry->GetBooleanWithoutPathExpansion(kStateStoreSignUnlimited, |
+ &new_entry.sign_unlimited); |
+ } else { |
+ LOG(ERROR) << "Found invalid entry of type " << entry->GetType() |
+ << " in PlatformKeys state store."; |
+ continue; |
+ } |
+ new_entries->push_back(new_entry); |
+ } |
+ return new_entries.Pass(); |
+} |
+ |
+scoped_ptr<base::ListValue> KeyEntriesToState( |
+ const PlatformKeysService::KeyEntries& entries) { |
+ scoped_ptr<base::ListValue> new_state(new base::ListValue); |
+ for (const PlatformKeysService::KeyEntry& entry : entries) { |
+ // Drop entries that the extension doesn't have any permissions for anymore. |
+ if (!entry.sign_once && !entry.sign_unlimited) |
+ continue; |
+ |
+ scoped_ptr<base::DictionaryValue> new_entry(new base::DictionaryValue); |
+ new_entry->SetStringWithoutPathExpansion(kStateStoreSPKI, entry.spki_b64); |
+ // Omit writing default values, namely |false|. |
+ if (entry.sign_once) { |
+ new_entry->SetBooleanWithoutPathExpansion(kStateStoreSignOnce, |
+ entry.sign_once); |
+ } |
+ if (entry.sign_unlimited) { |
+ new_entry->SetBooleanWithoutPathExpansion(kStateStoreSignUnlimited, |
+ entry.sign_unlimited); |
+ } |
+ new_state->Append(new_entry.release()); |
+ } |
+ return new_state.Pass(); |
+} |
-scoped_ptr<base::StringValue> GetPublicKeyValue( |
- const std::string& public_key_spki_der) { |
- std::string public_key_spki_der_b64; |
- base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64); |
- return make_scoped_ptr(new base::StringValue(public_key_spki_der_b64)); |
+// Searches |platform_keys| for an entry for |public_key_spki_der_b64|. If found |
+// returns a pointer to it, otherwise returns null. |
+PlatformKeysService::KeyEntry* GetMatchingEntry( |
+ const std::string& public_key_spki_der_b64, |
+ PlatformKeysService::KeyEntries* platform_keys) { |
+ for (PlatformKeysService::KeyEntry& entry : *platform_keys) { |
+ // For every ASN.1 value there is exactly one DER encoding, so it is fine to |
+ // compare the DER (or its base64 encoding). |
+ if (entry.spki_b64 == public_key_spki_der_b64) |
+ return &entry; |
+ } |
+ return nullptr; |
} |
} // namespace |
@@ -55,14 +162,16 @@ class PlatformKeysService::PermissionUpdateTask : public Task { |
// Creates a task that reads the current permission for an extension to access |
// a certain key. Afterwards it updates and persists the permission to the new |
// value |new_permission_value|. |callback| will be run after the permission |
- // was persisted. The old permission value is then accessible through |
- // old_permission_value(). |
- PermissionUpdateTask(const bool new_permission_value, |
+ // was persisted. The old permission values are then available through |
+ // old_key_entry(). |
+ PermissionUpdateTask(const SignPermission permission, |
+ const bool new_permission_value, |
const std::string& public_key_spki_der, |
const std::string& extension_id, |
base::Callback<void(Task*)> callback, |
PlatformKeysService* service) |
- : new_permission_value_(new_permission_value), |
+ : permission_(permission), |
+ new_permission_value_(new_permission_value), |
public_key_spki_der_(public_key_spki_der), |
extension_id_(extension_id), |
callback_(callback), |
@@ -78,9 +187,9 @@ class PlatformKeysService::PermissionUpdateTask : public Task { |
bool IsDone() override { return next_step_ == Step::DONE; } |
- // The original permission value before setting the new value |
- // |new_permission_value|. |
- bool old_permission_value() { return old_permission_value_; } |
+ // The old key entry with the old permissions before setting |permission| to |
+ // the new value |new_permission_value|. |
+ const KeyEntry& old_key_entry() { return old_key_entry_; } |
private: |
void DoStep() { |
@@ -113,38 +222,59 @@ class PlatformKeysService::PermissionUpdateTask : public Task { |
weak_factory_.GetWeakPtr())); |
} |
- void GotPlatformKeys(scoped_ptr<base::ListValue> platform_keys) { |
+ void GotPlatformKeys(scoped_ptr<KeyEntries> platform_keys) { |
platform_keys_ = platform_keys.Pass(); |
DoStep(); |
} |
- // Returns whether the extension has permission to use the key for signing |
- // according to the PlatformKeys value read from the extensions state store. |
- // Invalidates the key if it was found to be valid. |
+ // Persists the existing KeyEntry in |old_key_entry_|, updates the entry with |
+ // the new permission and persists it to the extension's state store if it was |
+ // changed. |
void WriteUpdate() { |
- scoped_ptr<base::StringValue> key_value( |
- GetPublicKeyValue(public_key_spki_der_)); |
- |
- base::ListValue::const_iterator it = platform_keys_->Find(*key_value); |
- old_permission_value_ = it != platform_keys_->end(); |
- if (old_permission_value_ == new_permission_value_) |
- return; |
- |
- if (new_permission_value_) |
- platform_keys_->Append(key_value.release()); |
- else |
- platform_keys_->Remove(*key_value, nullptr); |
+ DCHECK(platform_keys_); |
+ |
+ std::string public_key_spki_der_b64; |
+ base::Base64Encode(public_key_spki_der_, &public_key_spki_der_b64); |
+ |
+ KeyEntry* matching_entry = |
+ GetMatchingEntry(public_key_spki_der_b64, platform_keys_.get()); |
+ |
+ if (!matching_entry) { |
+ platform_keys_->push_back(KeyEntry()); |
+ matching_entry = &platform_keys_->back(); |
+ matching_entry->spki_b64 = public_key_spki_der_b64; |
+ } else if (permission_ == SignPermission::ONCE && new_permission_value_) { |
+ // The one-time sign permission is supposed to be granted once per key |
+ // during generation. Generated keys should be unique and thus this case |
+ // should never occur. |
+ NOTREACHED() << "Requested one-time sign permission on existing key."; |
+ } |
+ old_key_entry_ = *matching_entry; |
+ |
+ bool* permission_value = nullptr; |
+ switch (permission_) { |
+ case SignPermission::ONCE: |
+ permission_value = &matching_entry->sign_once; |
+ break; |
+ case SignPermission::UNLIMITED: |
+ permission_value = &matching_entry->sign_unlimited; |
+ break; |
+ } |
- service_->SetPlatformKeysOfExtension(extension_id_, platform_keys_.Pass()); |
+ if (*permission_value != new_permission_value_) { |
+ *permission_value = new_permission_value_; |
+ service_->SetPlatformKeysOfExtension(extension_id_, *platform_keys_); |
+ } |
} |
Step next_step_ = Step::READ_PLATFORM_KEYS; |
- scoped_ptr<base::ListValue> platform_keys_; |
- bool old_permission_value_ = false; |
+ KeyEntry old_key_entry_; |
+ const SignPermission permission_; |
const bool new_permission_value_; |
const std::string public_key_spki_der_; |
const std::string extension_id_; |
+ scoped_ptr<KeyEntries> platform_keys_; |
base::Callback<void(Task*)> callback_; |
PlatformKeysService* const service_; |
base::WeakPtrFactory<PermissionUpdateTask> weak_factory_; |
@@ -198,17 +328,21 @@ class PlatformKeysService::SignTask : public Task { |
next_step_ = Step::SIGN_OR_ABORT; |
UpdatePermission(); |
return; |
- case Step::SIGN_OR_ABORT: |
+ case Step::SIGN_OR_ABORT: { |
next_step_ = Step::DONE; |
- if (!service_->permission_check_enabled_ || |
- permission_update_->old_permission_value()) { |
+ bool sign_granted = permission_update_->old_key_entry().sign_once || |
+ permission_update_->old_key_entry().sign_unlimited; |
+ if (sign_granted) { |
Sign(); |
} else { |
- callback_.Run(std::string() /* no signature */, |
- kErrorKeyNotAllowedForSigning); |
+ if (!callback_.is_null()) { |
+ callback_.Run(std::string() /* no signature */, |
+ kErrorKeyNotAllowedForSigning); |
+ } |
DoStep(); |
} |
return; |
+ } |
case Step::DONE: |
service_->TaskFinished(this); |
// |this| might be invalid now. |
@@ -221,7 +355,8 @@ class PlatformKeysService::SignTask : public Task { |
// signing operations with that key. |
void UpdatePermission() { |
permission_update_.reset(new PermissionUpdateTask( |
- false /* new permission value */, public_key_, extension_id_, |
+ SignPermission::ONCE, false /* new permission value */, public_key_, |
+ extension_id_, |
base::Bind(&SignTask::DidUpdatePermission, weak_factory_.GetWeakPtr()), |
service_)); |
permission_update_->Start(); |
@@ -251,7 +386,7 @@ class PlatformKeysService::SignTask : public Task { |
} |
Step next_step_ = Step::UPDATE_PERMISSION; |
- scoped_ptr<base::ListValue> platform_keys_; |
+ scoped_ptr<KeyEntries> platform_keys_; |
scoped_ptr<PermissionUpdateTask> permission_update_; |
const std::string token_id_; |
@@ -271,6 +406,213 @@ class PlatformKeysService::SignTask : public Task { |
DISALLOW_COPY_AND_ASSIGN(SignTask); |
}; |
+class PlatformKeysService::SelectTask : public Task { |
+ public: |
+ enum class Step { |
+ GET_MATCHING_CERTS, |
+ SELECT_CERTS, |
+ READ_PLATFORM_KEYS, |
+ UPDATE_PERMISSION, |
+ FILTER_BY_PERMISSIONS, |
+ DONE, |
+ }; |
+ |
+ // This task determines all known client certs matching |request|. If |
+ // |interactive| is true, calls |service->select_delegate_->Select()| to |
+ // select a cert from all matches. The extension with |extension_id| will be |
+ // granted unlimited sign permission for the selected cert. |
+ // Finally, either the selection or, if |interactive| is false, matching certs |
+ // that the extension has permission for are passed to |callback|. |
+ SelectTask(const platform_keys::ClientCertificateRequest& request, |
+ bool interactive, |
+ const std::string& extension_id, |
+ const SelectCertificatesCallback& callback, |
+ PlatformKeysService* service) |
+ : request_(request), |
+ interactive_(interactive), |
+ extension_id_(extension_id), |
+ callback_(callback), |
+ service_(service), |
+ weak_factory_(this) {} |
+ ~SelectTask() override {} |
+ |
+ void Start() override { |
+ CHECK(next_step_ == Step::GET_MATCHING_CERTS); |
+ DoStep(); |
+ } |
+ bool IsDone() override { return next_step_ == Step::DONE; } |
+ |
+ private: |
+ void DoStep() { |
+ switch (next_step_) { |
+ case Step::GET_MATCHING_CERTS: |
+ if (interactive_) |
+ next_step_ = Step::SELECT_CERTS; |
+ else // Skip SelectCerts and UpdatePermission if not interactive. |
+ next_step_ = Step::READ_PLATFORM_KEYS; |
+ GetMatchingCerts(); |
+ return; |
+ case Step::SELECT_CERTS: |
+ next_step_ = Step::UPDATE_PERMISSION; |
+ SelectCerts(); |
+ return; |
+ case Step::UPDATE_PERMISSION: |
+ next_step_ = Step::READ_PLATFORM_KEYS; |
+ UpdatePermission(); |
+ return; |
+ case Step::READ_PLATFORM_KEYS: |
+ next_step_ = Step::FILTER_BY_PERMISSIONS; |
+ ReadPlatformKeys(); |
+ return; |
+ case Step::FILTER_BY_PERMISSIONS: |
+ next_step_ = Step::DONE; |
+ FilterSelectionByPermission(); |
+ return; |
+ case Step::DONE: |
+ service_->TaskFinished(this); |
+ // |this| might be invalid now. |
+ return; |
+ } |
+ } |
+ |
+ // Retrieves all certificates matching |request_|. Will call back to |
+ // |GotMatchingCerts()|. |
+ void GetMatchingCerts() { |
+ platform_keys::subtle::SelectClientCertificates( |
+ request_, |
+ base::Bind(&SelectTask::GotMatchingCerts, weak_factory_.GetWeakPtr()), |
+ service_->browser_context_); |
+ } |
+ |
+ // If the certificate request could be processed successfully, |matches| will |
+ // contain the list of matching certificates (maybe empty) and |error_message| |
+ // will be empty. If an error occurred, |matches| will be null and |
+ // |error_message| contain an error message. |
+ void GotMatchingCerts(scoped_ptr<net::CertificateList> matches, |
+ const std::string& error_message) { |
+ if (!error_message.empty()) { |
+ next_step_ = Step::DONE; |
+ callback_.Run(nullptr /* no certificates */, error_message); |
+ DoStep(); |
+ return; |
+ } |
+ matches_.swap(*matches); |
+ DoStep(); |
+ } |
+ |
+ // Calls |service_->select_delegate_->Select()| to select a cert from |
+ // |matches_|, which will be stored in |selected_cert_|. |
+ // Will call back to |GotSelection()|. |
+ void SelectCerts() { |
+ CHECK(interactive_); |
+ if (matches_.empty()) { |
+ // Don't show a select dialog if no certificate is matching. |
+ DoStep(); |
+ return; |
+ } |
+ service_->select_delegate_->Select( |
+ extension_id_, matches_, |
+ base::Bind(&SelectTask::GotSelection, base::Unretained(this))); |
+ } |
+ |
+ // Will be called by |SelectCerts()| with the selected cert or null if no cert |
+ // was selected. |
+ void GotSelection(scoped_refptr<net::X509Certificate> selected_cert) { |
+ selected_cert_ = selected_cert; |
+ DoStep(); |
+ } |
+ |
+ // Updates the extension's state store about unlimited sign permission for the |
+ // selected cert. Does nothing if no cert was selected. |
+ // Will call back to |DidUpdatePermission()|. |
+ void UpdatePermission() { |
+ CHECK(interactive_); |
+ if (!selected_cert_) { |
+ DoStep(); |
+ return; |
+ } |
+ const std::string public_key_spki_der( |
+ platform_keys::GetSubjectPublicKeyInfo(selected_cert_)); |
+ permission_update_.reset(new PermissionUpdateTask( |
+ SignPermission::UNLIMITED, true /* new permission value */, |
+ public_key_spki_der, extension_id_, |
+ base::Bind(&SelectTask::DidUpdatePermission, base::Unretained(this)), |
+ service_)); |
+ permission_update_->Start(); |
+ } |
+ |
+ void DidUpdatePermission(Task* /* task */) { DoStep(); } |
+ |
+ // Reads the PlatformKeys value from the extension's state store and calls |
+ // back to GotPlatformKeys(). |
+ void ReadPlatformKeys() { |
+ service_->GetPlatformKeysOfExtension( |
+ extension_id_, |
+ base::Bind(&SelectTask::GotPlatformKeys, weak_factory_.GetWeakPtr())); |
+ } |
+ |
+ void GotPlatformKeys(scoped_ptr<KeyEntries> platform_keys) { |
+ platform_keys_ = platform_keys.Pass(); |
+ DoStep(); |
+ } |
+ |
+ // Filters from all matches (if not interactive) or from the selection (if |
+ // interactive), the certificates that the extension has unlimited sign |
+ // permission for. Passes the filtered certs to |callback_|. |
+ void FilterSelectionByPermission() { |
+ scoped_ptr<net::CertificateList> selection(new net::CertificateList); |
+ if (interactive_) { |
+ if (selected_cert_) |
+ selection->push_back(selected_cert_); |
+ } else { |
+ selection->assign(matches_.begin(), matches_.end()); |
+ } |
+ |
+ scoped_ptr<net::CertificateList> filtered_certs(new net::CertificateList); |
+ for (scoped_refptr<net::X509Certificate> selected_cert : *selection) { |
+ const std::string public_key_spki_der( |
+ platform_keys::GetSubjectPublicKeyInfo(selected_cert)); |
+ std::string public_key_spki_der_b64; |
+ base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64); |
+ |
+ KeyEntry* matching_entry = |
+ GetMatchingEntry(public_key_spki_der_b64, platform_keys_.get()); |
+ if (!matching_entry || !matching_entry->sign_unlimited) |
+ continue; |
+ |
+ filtered_certs->push_back(selected_cert); |
+ } |
+ // Note: In the interactive case this should have filtered exactly the |
+ // one selected cert. Checking the permissions again is not striclty |
+ // necessary but this ensures that the permissions were updated correctly. |
+ CHECK(!selected_cert_ || (filtered_certs->size() == 1 && |
+ filtered_certs->front() == selected_cert_)); |
+ callback_.Run(filtered_certs.Pass(), std::string() /* no error */); |
+ DoStep(); |
+ } |
+ |
+ Step next_step_ = Step::GET_MATCHING_CERTS; |
+ scoped_ptr<KeyEntries> platform_keys_; |
+ scoped_ptr<PermissionUpdateTask> permission_update_; |
+ |
+ net::CertificateList matches_; |
+ scoped_refptr<net::X509Certificate> selected_cert_; |
+ platform_keys::ClientCertificateRequest request_; |
+ const bool interactive_; |
+ const std::string extension_id_; |
+ const SelectCertificatesCallback callback_; |
+ PlatformKeysService* const service_; |
+ base::WeakPtrFactory<SelectTask> weak_factory_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(SelectTask); |
+}; |
+ |
+PlatformKeysService::SelectDelegate::SelectDelegate() { |
+} |
+ |
+PlatformKeysService::SelectDelegate::~SelectDelegate() { |
+} |
+ |
PlatformKeysService::PlatformKeysService( |
content::BrowserContext* browser_context, |
extensions::StateStore* state_store) |
@@ -283,8 +625,22 @@ PlatformKeysService::PlatformKeysService( |
PlatformKeysService::~PlatformKeysService() { |
} |
-void PlatformKeysService::DisablePermissionCheckForTesting() { |
- permission_check_enabled_ = false; |
+void PlatformKeysService::SetSelectDelegate( |
+ scoped_ptr<SelectDelegate> delegate) { |
+ select_delegate_ = delegate.Pass(); |
+} |
+ |
+void PlatformKeysService::GrantUnlimitedSignPermission( |
+ const std::string& extension_id, |
+ scoped_refptr<net::X509Certificate> cert) { |
+ const std::string public_key_spki_der( |
+ platform_keys::GetSubjectPublicKeyInfo(cert)); |
+ |
+ StartOrQueueTask(make_scoped_ptr(new PermissionUpdateTask( |
+ SignPermission::UNLIMITED, true /* new permission value */, |
+ public_key_spki_der, extension_id, |
+ base::Bind(&PlatformKeysService::TaskFinished, base::Unretained(this)), |
+ this))); |
} |
void PlatformKeysService::GenerateRSAKey(const std::string& token_id, |
@@ -326,15 +682,12 @@ void PlatformKeysService::SignRSAPKCS1Raw(const std::string& token_id, |
void PlatformKeysService::SelectClientCertificates( |
const platform_keys::ClientCertificateRequest& request, |
+ bool interactive, |
const std::string& extension_id, |
const SelectCertificatesCallback& callback) { |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- |
- platform_keys::subtle::SelectClientCertificates( |
- request, |
- base::Bind(&PlatformKeysService::SelectClientCertificatesCallback, |
- weak_factory_.GetWeakPtr(), extension_id, callback), |
- browser_context_); |
+ StartOrQueueTask(make_scoped_ptr( |
+ new SelectTask(request, interactive, extension_id, callback, this))); |
} |
void PlatformKeysService::StartOrQueueTask(scoped_ptr<Task> task) { |
@@ -367,9 +720,9 @@ void PlatformKeysService::GetPlatformKeysOfExtension( |
void PlatformKeysService::SetPlatformKeysOfExtension( |
const std::string& extension_id, |
- scoped_ptr<base::ListValue> platform_keys) { |
+ const KeyEntries& platform_keys) { |
state_store_->SetExtensionValue(extension_id, kStateStorePlatformKeys, |
- platform_keys.Pass()); |
+ KeyEntriesToState(platform_keys)); |
} |
void PlatformKeysService::GeneratedKey(const std::string& extension_id, |
@@ -382,7 +735,8 @@ void PlatformKeysService::GeneratedKey(const std::string& extension_id, |
} |
StartOrQueueTask(make_scoped_ptr(new PermissionUpdateTask( |
- true /* new permission value */, public_key_spki_der, extension_id, |
+ SignPermission::ONCE, true /* new permission value */, |
+ public_key_spki_der, extension_id, |
base::Bind(&PlatformKeysService::RegisteredGeneratedKey, |
base::Unretained(this), callback, public_key_spki_der), |
this))); |
@@ -396,35 +750,16 @@ void PlatformKeysService::RegisteredGeneratedKey( |
TaskFinished(task); |
} |
-void PlatformKeysService::SelectClientCertificatesCallback( |
- const std::string& extension_id, |
- const SelectCertificatesCallback& callback, |
- scoped_ptr<net::CertificateList> matches, |
- const std::string& error_message) { |
- if (permission_check_enabled_) |
- matches->clear(); |
- |
- // TODO(pneubeck): Remove all certs that the extension doesn't have access to. |
- callback.Run(matches.Pass(), error_message); |
-} |
void PlatformKeysService::GotPlatformKeysOfExtension( |
const std::string& extension_id, |
const GetPlatformKeysCallback& callback, |
scoped_ptr<base::Value> value) { |
- if (!value) |
- value.reset(new base::ListValue); |
- |
- base::ListValue* keys = NULL; |
- if (!value->GetAsList(&keys)) { |
- LOG(ERROR) << "Found a value of wrong type."; |
- |
- keys = new base::ListValue; |
- value.reset(keys); |
- } |
+ scoped_ptr<KeyEntries> key_entries(new KeyEntries); |
+ if (value) |
+ key_entries = KeyEntriesFromState(*value); |
- ignore_result(value.release()); |
- callback.Run(make_scoped_ptr(keys)); |
+ callback.Run(key_entries.Pass()); |
} |
} // namespace chromeos |