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

Side by Side Diff: chrome/browser/chromeos/platform_keys/platform_keys_service.cc

Issue 892103003: PlatformKeysService: Process state accessing operations sequentially. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@cert_impl_sign
Patch Set: Addressed comments. Created 5 years, 10 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 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/platform_keys_service.h" 5 #include "chrome/browser/chromeos/platform_keys/platform_keys_service.h"
6 6
7 #include "base/base64.h" 7 #include "base/base64.h"
8 #include "base/callback.h" 8 #include "base/callback.h"
9 #include "base/callback_helpers.h"
9 #include "base/values.h" 10 #include "base/values.h"
10 #include "chrome/browser/chromeos/platform_keys/platform_keys.h" 11 #include "chrome/browser/chromeos/platform_keys/platform_keys.h"
11 #include "content/public/browser/browser_thread.h" 12 #include "content/public/browser/browser_thread.h"
12 #include "extensions/browser/state_store.h" 13 #include "extensions/browser/state_store.h"
13 #include "net/cert/x509_certificate.h" 14 #include "net/cert/x509_certificate.h"
14 15
15 using content::BrowserThread; 16 using content::BrowserThread;
16 17
17 namespace chromeos { 18 namespace chromeos {
18 19
19 namespace { 20 namespace {
20 21
21 const char kErrorKeyNotAllowedForSigning[] = 22 const char kErrorKeyNotAllowedForSigning[] =
22 "This key is not allowed for signing. Either it was used for signing " 23 "This key is not allowed for signing. Either it was used for signing "
23 "before or it was not correctly generated."; 24 "before or it was not correctly generated.";
24 const char kStateStorePlatformKeys[] = "PlatformKeys"; 25 const char kStateStorePlatformKeys[] = "PlatformKeys";
25 26
26 scoped_ptr<base::StringValue> GetPublicKeyValue( 27 scoped_ptr<base::StringValue> GetPublicKeyValue(
27 const std::string& public_key_spki_der) { 28 const std::string& public_key_spki_der) {
28 std::string public_key_spki_der_b64; 29 std::string public_key_spki_der_b64;
29 base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64); 30 base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64);
30 return make_scoped_ptr(new base::StringValue(public_key_spki_der_b64)); 31 return make_scoped_ptr(new base::StringValue(public_key_spki_der_b64));
31 } 32 }
32 33
33 void RunGenerateKeyCallback(
34 const PlatformKeysService::GenerateKeyCallback& callback,
35 const std::string& public_key_spki_der) {
36 callback.Run(public_key_spki_der, std::string() /* no error */);
37 }
38
39 // Callback used by |PlatformKeysService::Sign|.
40 // Is called with the old validity of |public_key_spki_der| (or false if an
41 // error occurred during reading the StateStore). If allowed, starts the actual
42 // signing operation which will call back |callback|. If not allowed, calls
43 // |callback| with an error.
44 void CheckValidityAndSign(const std::string& token_id,
45 scoped_ptr<platform_keys::SignRSAParams> params,
46 const PlatformKeysService::SignCallback& callback,
47 content::BrowserContext* browser_context,
48 bool key_is_valid) {
49 if (!key_is_valid) {
50 callback.Run(std::string() /* no signature */,
51 kErrorKeyNotAllowedForSigning);
52 return;
53 }
54 platform_keys::subtle::SignRSA(token_id, params.Pass(), callback,
55 browser_context);
56 }
57
58 } // namespace 34 } // namespace
59 35
36 class PlatformKeysService::Task {
37 public:
38 Task() {}
39 virtual ~Task() {}
40 virtual void Start() = 0;
41 virtual bool IsDone() = 0;
42
43 private:
44 DISALLOW_ASSIGN(Task);
45 };
46
47 class PlatformKeysService::PermissionUpdateTask : public Task {
48 public:
49 enum class Step {
50 READ_PLATFORM_KEYS,
51 WRITE_UPDATE_AND_CALLBACK,
52 DONE,
53 };
54
55 // Creates a task that reads the current permission for an extension to access
56 // a certain key. Afterwards it updates and persists the permission to the new
57 // value |new_permission_value|. |callback| will be run after the permission
58 // was persisted. The old permission value is then accessible through
59 // old_permission_value().
60 PermissionUpdateTask(const bool new_permission_value,
61 const std::string& public_key_spki_der,
62 const std::string& extension_id,
63 base::Callback<void(Task*)> callback,
64 PlatformKeysService* service)
65 : new_permission_value_(new_permission_value),
66 public_key_spki_der_(public_key_spki_der),
67 extension_id_(extension_id),
68 callback_(callback),
69 service_(service),
70 weak_factory_(this) {}
71
72 ~PermissionUpdateTask() override {}
73
74 void Start() override {
75 CHECK(next_step_ == Step::READ_PLATFORM_KEYS);
76 DoStep();
77 }
78
79 bool IsDone() override { return next_step_ == Step::DONE; }
80
81 // The original permission value before setting the new value
82 // |new_permission_value|.
83 bool old_permission_value() { return old_permission_value_; }
84
85 private:
86 void DoStep() {
87 switch (next_step_) {
88 case Step::READ_PLATFORM_KEYS:
89 next_step_ = Step::WRITE_UPDATE_AND_CALLBACK;
90 ReadPlatformKeys();
91 return;
92 case Step::WRITE_UPDATE_AND_CALLBACK:
93 next_step_ = Step::DONE;
94 WriteUpdate();
95 if (!callback_.is_null()) {
96 // Make a local copy of the callback to run as it might be deleted
97 // during the Run().
98 base::ResetAndReturn(&callback_).Run(this);
99 // |this| might be invalid now.
100 }
101 return;
102 case Step::DONE:
103 NOTREACHED();
104 return;
105 }
106 }
107
108 // Reads the PlatformKeys value from the extension's state store and calls
109 // back to GotPlatformKeys().
110 void ReadPlatformKeys() {
111 service_->GetPlatformKeysOfExtension(
112 extension_id_, base::Bind(&PermissionUpdateTask::GotPlatformKeys,
113 weak_factory_.GetWeakPtr()));
114 }
115
116 void GotPlatformKeys(scoped_ptr<base::ListValue> platform_keys) {
117 platform_keys_ = platform_keys.Pass();
118 DoStep();
119 }
120
121 // Returns whether the extension has permission to use the key for signing
122 // according to the PlatformKeys value read from the extensions state store.
123 // Invalidates the key if it was found to be valid.
124 void WriteUpdate() {
125 scoped_ptr<base::StringValue> key_value(
126 GetPublicKeyValue(public_key_spki_der_));
127
128 base::ListValue::const_iterator it = platform_keys_->Find(*key_value);
129 old_permission_value_ = it != platform_keys_->end();
130 if (old_permission_value_ == new_permission_value_)
131 return;
132
133 if (new_permission_value_)
134 platform_keys_->Append(key_value.release());
135 else
136 platform_keys_->Remove(*key_value, nullptr);
137
138 service_->SetPlatformKeysOfExtension(extension_id_, platform_keys_.Pass());
139 }
140
141 Step next_step_ = Step::READ_PLATFORM_KEYS;
142 scoped_ptr<base::ListValue> platform_keys_;
143 bool old_permission_value_ = false;
144
145 const bool new_permission_value_;
146 const std::string public_key_spki_der_;
147 const std::string extension_id_;
148 base::Callback<void(Task*)> callback_;
149 PlatformKeysService* const service_;
150 base::WeakPtrFactory<PermissionUpdateTask> weak_factory_;
151
152 DISALLOW_COPY_AND_ASSIGN(PermissionUpdateTask);
153 };
154
155 class PlatformKeysService::SignTask : public Task {
156 public:
157 enum class Step {
158 UPDATE_PERMISSION,
159 SIGN_OR_ABORT,
160 DONE,
161 };
162
163 // This Task will check the permissions of the extension with |extension_id|
164 // for the key identified by |public_key_spki_der|, then updates the
165 // permission to prevent any future signing operation of that extension using
166 // that same key. If the permission check was positive, it will actually sign
167 // |data| with the key and pass the signature to |callback|.
168 // If an error occurs, an error message is passed to |callback| instead.
169 SignTask(const std::string& token_id,
170 scoped_ptr<platform_keys::SignRSAParams> params,
171 const std::string& extension_id,
172 const SignCallback& callback,
173 PlatformKeysService* service)
174 : token_id_(token_id),
175 params_(params.Pass()),
176 extension_id_(extension_id),
177 callback_(callback),
178 service_(service),
179 weak_factory_(this) {}
180 ~SignTask() override {}
181
182 void Start() override {
183 CHECK(next_step_ == Step::UPDATE_PERMISSION);
184 DoStep();
185 }
186 bool IsDone() override { return next_step_ == Step::DONE; }
187
188 private:
189 void DoStep() {
190 switch (next_step_) {
191 case Step::UPDATE_PERMISSION:
192 next_step_ = Step::SIGN_OR_ABORT;
193 UpdatePermission();
194 return;
195 case Step::SIGN_OR_ABORT:
196 next_step_ = Step::DONE;
197 if (!service_->permission_check_enabled_ ||
198 permission_update_->old_permission_value()) {
199 Sign();
200 } else {
201 callback_.Run(std::string() /* no signature */,
202 kErrorKeyNotAllowedForSigning);
203 DoStep();
204 }
205 return;
206 case Step::DONE:
207 service_->TaskFinished(this);
208 // |this| might be invalid now.
209 return;
210 }
211 }
212
213 // Reads the current permission of the extension with |extension_id_| for key
214 // |params_->public_key| and updates the permission to disable further
215 // signing operations with that key.
216 void UpdatePermission() {
217 permission_update_.reset(new PermissionUpdateTask(
218 false /* new permission value */, params_->public_key(), extension_id_,
219 base::Bind(&SignTask::DidUpdatePermission, weak_factory_.GetWeakPtr()),
220 service_));
221 permission_update_->Start();
222 }
223
224 void DidUpdatePermission(Task* /* task */) { DoStep(); }
225
226 // Starts the actual signing operation and afterwards passes the signature (or
227 // error) to |callback_|.
228 void Sign() {
229 platform_keys::subtle::SignRSA(
230 token_id_, params_.Pass(),
231 base::Bind(&SignTask::DidSign, weak_factory_.GetWeakPtr()),
232 service_->browser_context_);
233 }
234
235 void DidSign(const std::string& signature, const std::string& error_message) {
236 callback_.Run(signature, error_message);
237 DoStep();
238 }
239
240 Step next_step_ = Step::UPDATE_PERMISSION;
241 scoped_ptr<base::ListValue> platform_keys_;
242 scoped_ptr<PermissionUpdateTask> permission_update_;
243
244 const std::string token_id_;
245 scoped_ptr<platform_keys::SignRSAParams> params_;
246 const std::string extension_id_;
247 const SignCallback callback_;
248 PlatformKeysService* const service_;
249 base::WeakPtrFactory<SignTask> weak_factory_;
250
251 DISALLOW_COPY_AND_ASSIGN(SignTask);
252 };
253
60 PlatformKeysService::PlatformKeysService( 254 PlatformKeysService::PlatformKeysService(
61 content::BrowserContext* browser_context, 255 content::BrowserContext* browser_context,
62 extensions::StateStore* state_store) 256 extensions::StateStore* state_store)
63 : browser_context_(browser_context), 257 : browser_context_(browser_context),
64 state_store_(state_store), 258 state_store_(state_store),
65 weak_factory_(this) { 259 weak_factory_(this) {
66 DCHECK(state_store); 260 DCHECK(state_store);
67 } 261 }
68 262
69 PlatformKeysService::~PlatformKeysService() { 263 PlatformKeysService::~PlatformKeysService() {
70 } 264 }
71 265
72 void PlatformKeysService::DisablePermissionCheckForTesting() { 266 void PlatformKeysService::DisablePermissionCheckForTesting() {
73 permission_check_enabled_ = false; 267 permission_check_enabled_ = false;
74 } 268 }
75 269
76 void PlatformKeysService::GenerateRSAKey(const std::string& token_id, 270 void PlatformKeysService::GenerateRSAKey(const std::string& token_id,
77 unsigned int modulus_length, 271 unsigned int modulus_length,
78 const std::string& extension_id, 272 const std::string& extension_id,
79 const GenerateKeyCallback& callback) { 273 const GenerateKeyCallback& callback) {
80 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 274 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
81 275
82 platform_keys::subtle::GenerateRSAKey( 276 platform_keys::subtle::GenerateRSAKey(
83 token_id, 277 token_id, modulus_length,
84 modulus_length, 278 base::Bind(&PlatformKeysService::GeneratedKey, weak_factory_.GetWeakPtr(),
85 base::Bind(&PlatformKeysService::GenerateRSAKeyCallback, 279 extension_id, callback),
86 weak_factory_.GetWeakPtr(),
87 extension_id,
88 callback),
89 browser_context_); 280 browser_context_);
90 } 281 }
91 282
92 void PlatformKeysService::SignRSA( 283 void PlatformKeysService::SignRSA(
93 const std::string& token_id, 284 const std::string& token_id,
94 scoped_ptr<platform_keys::SignRSAParams> params, 285 scoped_ptr<platform_keys::SignRSAParams> params,
95 const std::string& extension_id, 286 const std::string& extension_id,
96 const SignCallback& callback) { 287 const SignCallback& callback) {
97 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 288 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
98 ReadValidityAndInvalidateKey( 289 StartOrQueueTask(make_scoped_ptr(
99 extension_id, params->public_key(), 290 new SignTask(token_id, params.Pass(), extension_id, callback, this)));
100 base::Bind(&CheckValidityAndSign, token_id, base::Passed(&params),
101 callback, browser_context_));
102 } 291 }
103 292
104 void PlatformKeysService::SelectClientCertificates( 293 void PlatformKeysService::SelectClientCertificates(
105 const platform_keys::ClientCertificateRequest& request, 294 const platform_keys::ClientCertificateRequest& request,
106 const std::string& extension_id, 295 const std::string& extension_id,
107 const SelectCertificatesCallback& callback) { 296 const SelectCertificatesCallback& callback) {
108 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 297 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
109 298
110 platform_keys::subtle::SelectClientCertificates( 299 platform_keys::subtle::SelectClientCertificates(
111 request, 300 request,
112 base::Bind(&PlatformKeysService::SelectClientCertificatesCallback, 301 base::Bind(&PlatformKeysService::SelectClientCertificatesCallback,
113 weak_factory_.GetWeakPtr(), extension_id, callback), 302 weak_factory_.GetWeakPtr(), extension_id, callback),
114 browser_context_); 303 browser_context_);
115 } 304 }
116 305
117 void PlatformKeysService::RegisterPublicKey( 306 void PlatformKeysService::StartOrQueueTask(scoped_ptr<Task> task) {
118 const std::string& extension_id, 307 tasks_.push(make_linked_ptr(task.release()));
119 const std::string& public_key_spki_der, 308 if (tasks_.size() == 1)
120 const base::Closure& callback) { 309 tasks_.front()->Start();
121 GetPlatformKeysOfExtension(
122 extension_id,
123 base::Bind(&PlatformKeysService::RegisterPublicKeyGotPlatformKeys,
124 weak_factory_.GetWeakPtr(),
125 extension_id,
126 public_key_spki_der,
127 callback));
128 } 310 }
129 311
130 void PlatformKeysService::ReadValidityAndInvalidateKey( 312 void PlatformKeysService::TaskFinished(Task* task) {
131 const std::string& extension_id, 313 DCHECK(!tasks_.empty());
132 const std::string& public_key_spki_der, 314 DCHECK(task == tasks_.front().get());
133 const base::Callback<void(bool)>& callback) { 315 // Remove all finished tasks from the queue (should be at most one).
134 GetPlatformKeysOfExtension(extension_id, 316 while (!tasks_.empty() && tasks_.front()->IsDone())
135 base::Bind(&PlatformKeysService::InvalidateKey, 317 tasks_.pop();
136 weak_factory_.GetWeakPtr(), 318
137 extension_id, 319 // Now either the queue is empty or the next task is not finished yet and it
138 public_key_spki_der, 320 // can be started.
139 callback)); 321 if (!tasks_.empty())
322 tasks_.front()->Start();
140 } 323 }
141 324
142 void PlatformKeysService::GetPlatformKeysOfExtension( 325 void PlatformKeysService::GetPlatformKeysOfExtension(
143 const std::string& extension_id, 326 const std::string& extension_id,
144 const GetPlatformKeysCallback& callback) { 327 const GetPlatformKeysCallback& callback) {
145 state_store_->GetExtensionValue( 328 state_store_->GetExtensionValue(
146 extension_id, kStateStorePlatformKeys, 329 extension_id, kStateStorePlatformKeys,
147 base::Bind(&PlatformKeysService::GotPlatformKeysOfExtension, 330 base::Bind(&PlatformKeysService::GotPlatformKeysOfExtension,
148 weak_factory_.GetWeakPtr(), extension_id, callback)); 331 weak_factory_.GetWeakPtr(), extension_id, callback));
149 } 332 }
150 333
151 void PlatformKeysService::SetPlatformKeysOfExtension( 334 void PlatformKeysService::SetPlatformKeysOfExtension(
152 const std::string& extension_id, 335 const std::string& extension_id,
153 scoped_ptr<base::ListValue> platform_keys) { 336 scoped_ptr<base::ListValue> platform_keys) {
154 state_store_->SetExtensionValue(extension_id, kStateStorePlatformKeys, 337 state_store_->SetExtensionValue(extension_id, kStateStorePlatformKeys,
155 platform_keys.Pass()); 338 platform_keys.Pass());
156 } 339 }
157 340
158 void PlatformKeysService::GenerateRSAKeyCallback( 341 void PlatformKeysService::GeneratedKey(const std::string& extension_id,
159 const std::string& extension_id, 342 const GenerateKeyCallback& callback,
160 const GenerateKeyCallback& callback, 343 const std::string& public_key_spki_der,
161 const std::string& public_key_spki_der, 344 const std::string& error_message) {
162 const std::string& error_message) {
163 if (!error_message.empty()) { 345 if (!error_message.empty()) {
164 callback.Run(std::string() /* no public key */, error_message); 346 callback.Run(std::string() /* no public key */, error_message);
165 return; 347 return;
166 } 348 }
167 base::Closure wrapped_callback( 349
168 base::Bind(&RunGenerateKeyCallback, callback, public_key_spki_der)); 350 StartOrQueueTask(make_scoped_ptr(new PermissionUpdateTask(
169 RegisterPublicKey(extension_id, public_key_spki_der, wrapped_callback); 351 true /* new permission value */, public_key_spki_der, extension_id,
352 base::Bind(&PlatformKeysService::DidRegisterGeneratedKey,
353 base::Unretained(this), callback, public_key_spki_der),
354 this)));
355 }
356
357 void PlatformKeysService::DidRegisterGeneratedKey(
kaliamoorthi 2015/02/09 16:02:10 nit: How about RegisteredGeneratedKey? I see other
pneubeck (no reviews) 2015/02/15 09:25:57 Done.
358 const GenerateKeyCallback& callback,
359 const std::string& public_key_spki_der,
360 Task* task) {
361 callback.Run(public_key_spki_der, std::string() /* no error */);
362 TaskFinished(task);
170 } 363 }
171 364
172 void PlatformKeysService::SelectClientCertificatesCallback( 365 void PlatformKeysService::SelectClientCertificatesCallback(
173 const std::string& extension_id, 366 const std::string& extension_id,
174 const SelectCertificatesCallback& callback, 367 const SelectCertificatesCallback& callback,
175 scoped_ptr<net::CertificateList> matches, 368 scoped_ptr<net::CertificateList> matches,
176 const std::string& error_message) { 369 const std::string& error_message) {
177 if (permission_check_enabled_) 370 if (permission_check_enabled_)
178 matches->clear(); 371 matches->clear();
179 372
180 // TODO(pneubeck): Remove all certs that the extension doesn't have access to. 373 // TODO(pneubeck): Remove all certs that the extension doesn't have access to.
181 callback.Run(matches.Pass(), error_message); 374 callback.Run(matches.Pass(), error_message);
182 } 375 }
183 376
184 void PlatformKeysService::RegisterPublicKeyGotPlatformKeys(
185 const std::string& extension_id,
186 const std::string& public_key_spki_der,
187 const base::Closure& callback,
188 scoped_ptr<base::ListValue> platform_keys) {
189 scoped_ptr<base::StringValue> key_value(
190 GetPublicKeyValue(public_key_spki_der));
191
192 DCHECK(platform_keys->end() == platform_keys->Find(*key_value))
193 << "Keys are assumed to be generated and not to be registered multiple "
194 "times.";
195 platform_keys->Append(key_value.release());
196 SetPlatformKeysOfExtension(extension_id, platform_keys.Pass());
197 callback.Run();
198 }
199
200 void PlatformKeysService::InvalidateKey(
201 const std::string& extension_id,
202 const std::string& public_key_spki_der,
203 const base::Callback<void(bool)>& callback,
204 scoped_ptr<base::ListValue> platform_keys) {
205 scoped_ptr<base::StringValue> key_value(
206 GetPublicKeyValue(public_key_spki_der));
207
208 size_t index = 0;
209 // If the key is found in |platform_keys|, it's valid for the extension to use
210 // it for signing.
211 bool key_was_valid = platform_keys->Remove(*key_value, &index);
212
213 if (key_was_valid) {
214 // Persist that the key is now invalid.
215 SetPlatformKeysOfExtension(extension_id, platform_keys.Pass());
216 }
217
218 if (permission_check_enabled_) {
219 // If permission checks are enabled, pass back the key permission (before
220 // it was removed above).
221 callback.Run(key_was_valid);
222 } else {
223 // Otherwise just allow signing with the key (which is enabled for testing
224 // only).
225 callback.Run(true);
226 }
227 }
228
229 void PlatformKeysService::GotPlatformKeysOfExtension( 377 void PlatformKeysService::GotPlatformKeysOfExtension(
230 const std::string& extension_id, 378 const std::string& extension_id,
231 const GetPlatformKeysCallback& callback, 379 const GetPlatformKeysCallback& callback,
232 scoped_ptr<base::Value> value) { 380 scoped_ptr<base::Value> value) {
233 if (!value) 381 if (!value)
234 value.reset(new base::ListValue); 382 value.reset(new base::ListValue);
235 383
236 base::ListValue* keys = NULL; 384 base::ListValue* keys = NULL;
237 if (!value->GetAsList(&keys)) { 385 if (!value->GetAsList(&keys)) {
238 LOG(ERROR) << "Found a value of wrong type."; 386 LOG(ERROR) << "Found a value of wrong type.";
239 387
240 keys = new base::ListValue; 388 keys = new base::ListValue;
241 value.reset(keys); 389 value.reset(keys);
242 } 390 }
243 391
244 ignore_result(value.release()); 392 ignore_result(value.release());
245 callback.Run(make_scoped_ptr(keys)); 393 callback.Run(make_scoped_ptr(keys));
246 } 394 }
247 395
248 } // namespace chromeos 396 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698