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

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: Minor cleanup. 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 State {
50 NOT_STARTED,
51 READ_PLATFORM_KEYS,
52 WRITE_UPDATE,
kaliamoorthi 2015/02/09 10:44:01 Not sure if you need so many states. There is just
pneubeck (no reviews) 2015/02/09 14:02:38 dropped the NOT_STARTED state (which was meant to
53 DONE,
54 };
55
56 PermissionUpdateTask(const bool new_permission_value,
57 const std::string& public_key_spki_der,
58 const std::string& extension_id,
59 base::Callback<void(Task*)> callback,
60 PlatformKeysService* service)
61 : new_permission_value_(new_permission_value),
62 public_key_spki_der_(public_key_spki_der),
63 extension_id_(extension_id),
64 callback_(callback),
65 service_(service),
66 weak_factory_(this) {}
67
68 ~PermissionUpdateTask() override {}
69
70 void Start() override {
71 CHECK(state_ == State::NOT_STARTED);
72 Step();
73 }
74 bool IsDone() override { return state_ == State::DONE; }
75 bool old_permission_value() { return old_permission_value_; }
76
77 private:
78 void Step() {
79 CHECK(state_ != State::DONE);
80 state_ = next_state_;
81 switch (state_) {
82 case State::NOT_STARTED:
83 NOTREACHED();
84 return;
85 case State::READ_PLATFORM_KEYS:
86 next_state_ = State::WRITE_UPDATE;
87 ReadPlatformKeys();
88 return;
89 case State::WRITE_UPDATE:
90 next_state_ = State::DONE;
91 WriteUpdate();
92 return;
93 case State::DONE:
94 if (!callback_.is_null()) {
95 // Make a local copy of the callback to run as it might be deleted
96 // during the Run().
97 base::ResetAndReturn(&callback_).Run(this);
98 // |this| might be invalid now.
99 }
100 return;
101 }
102 }
103
104 // Reads the PlatformKeys value from the extension's state store and calls
105 // back to GotPlatformKeys().
106 void ReadPlatformKeys() {
107 service_->GetPlatformKeysOfExtension(
108 extension_id_, base::Bind(&PermissionUpdateTask::GotPlatformKeys,
109 weak_factory_.GetWeakPtr()));
110 }
111
112 void GotPlatformKeys(scoped_ptr<base::ListValue> platform_keys) {
113 platform_keys_ = platform_keys.Pass();
114 Step();
115 }
116
117 // Returns whether the extension has permission to use the key for signing
118 // according to the PlatformKeys value read from the extensions state store.
119 // Invalidates the key if it was found to be valid.
120 void WriteUpdate() {
121 scoped_ptr<base::StringValue> key_value(
122 GetPublicKeyValue(public_key_spki_der_));
123
124 base::ListValue::const_iterator it = platform_keys_->Find(*key_value);
125 old_permission_value_ = it != platform_keys_->end();
126 if (old_permission_value_ == new_permission_value_)
127 return;
128
129 if (new_permission_value_)
130 platform_keys_->Append(key_value.release());
131 else
132 platform_keys_->Remove(*key_value, nullptr);
133
134 service_->SetPlatformKeysOfExtension(extension_id_, platform_keys_.Pass());
135 Step();
136 }
137
138 State state_ = State::NOT_STARTED;
139 State next_state_ = State::READ_PLATFORM_KEYS;
140 scoped_ptr<base::ListValue> platform_keys_;
141 bool old_permission_value_ = false;
142
143 const bool new_permission_value_;
144 const std::string public_key_spki_der_;
145 const std::string extension_id_;
146 base::Callback<void(Task*)> callback_;
147 PlatformKeysService* const service_;
148 base::WeakPtrFactory<PermissionUpdateTask> weak_factory_;
149
150 DISALLOW_COPY_AND_ASSIGN(PermissionUpdateTask);
151 };
152
153 class PlatformKeysService::SignTask : public Task {
154 public:
155 enum class State {
156 NOT_STARTED,
157 UPDATE_PERMISSION,
158 SIGN_OR_ABORT,
159 DONE,
160 };
161
162 // This Task will check the permissions of the extension with |extension_id|
163 // for the key identified by |public_key_spki_der|, then updates the
164 // permission to prevent any future signing operation of that extension using
165 // that same key. If the permission check was positive, it will actually sign
166 // |data| with the key and pass the signature to |callback|.
167 // If an error occurs, an error message is passed to |callback| instead.
168 SignTask(const std::string& token_id,
169 scoped_ptr<platform_keys::SignRSAParams> params,
170 const std::string& extension_id,
171 const SignCallback& callback,
172 PlatformKeysService* service)
173 : token_id_(token_id),
174 params_(params.Pass()),
175 extension_id_(extension_id),
176 callback_(callback),
177 service_(service),
178 weak_factory_(this) {}
179 ~SignTask() override {}
180
181 void Start() override {
182 CHECK(state_ == State::NOT_STARTED);
183 Step();
184 }
185 bool IsDone() override { return state_ == State::DONE; }
186
187 private:
188 void Step() {
189 CHECK(state_ != State::DONE);
190 state_ = next_state_;
191 switch (state_) {
192 case State::NOT_STARTED:
193 NOTREACHED();
194 return;
195 case State::UPDATE_PERMISSION:
196 next_state_ = State::SIGN_OR_ABORT;
197 UpdatePermission();
198 return;
199 case State::SIGN_OR_ABORT:
200 next_state_ = State::DONE;
201 if (!service_->permission_check_enabled_ ||
202 permission_update_->old_permission_value()) {
203 Sign();
204 } else {
205 callback_.Run(std::string() /* no signature */,
206 kErrorKeyNotAllowedForSigning);
207 Step();
208 }
209 return;
210 case State::DONE:
211 service_->TaskFinished(this);
212 // |this| might be invalid now.
213 return;
214 }
215 }
216
217 // Reads the current permission of the extension with |extension_id_| for key
218 // |params_->public_key| and updates the permission to disable further
219 // signing operations with that key.
220 void UpdatePermission() {
221 permission_update_.reset(new PermissionUpdateTask(
kaliamoorthi 2015/02/09 10:44:01 Combining SignTask with PermissionUpdateTask can r
pneubeck (no reviews) 2015/02/09 14:02:38 PermissionUpdate will also be used independent of
222 false /* new permission value */, params_->public_key(), extension_id_,
223 base::Bind(&SignTask::DidUpdatePermission, weak_factory_.GetWeakPtr()),
224 service_));
225 permission_update_->Start();
226 }
227
228 void DidUpdatePermission(Task* /* task */) { Step(); }
229
230 // Starts the actual signing operation and afterwards passes the signature (or
231 // error) to |callback_|.
232 void Sign() {
233 platform_keys::subtle::SignRSA(
234 token_id_, params_.Pass(),
235 base::Bind(&SignTask::DidSign, weak_factory_.GetWeakPtr()),
236 service_->browser_context_);
237 }
238
239 void DidSign(const std::string& signature, const std::string& error_message) {
240 callback_.Run(signature, error_message);
241 Step();
242 }
243
244 State state_ = State::NOT_STARTED;
245 State next_state_ = State::UPDATE_PERMISSION;
246 scoped_ptr<base::ListValue> platform_keys_;
247 scoped_ptr<PermissionUpdateTask> permission_update_;
248
249 const std::string token_id_;
250 scoped_ptr<platform_keys::SignRSAParams> params_;
251 const std::string extension_id_;
252 const SignCallback callback_;
253 PlatformKeysService* const service_;
254 base::WeakPtrFactory<SignTask> weak_factory_;
255
256 DISALLOW_COPY_AND_ASSIGN(SignTask);
257 };
258
60 PlatformKeysService::PlatformKeysService( 259 PlatformKeysService::PlatformKeysService(
61 content::BrowserContext* browser_context, 260 content::BrowserContext* browser_context,
62 extensions::StateStore* state_store) 261 extensions::StateStore* state_store)
63 : browser_context_(browser_context), 262 : browser_context_(browser_context),
64 state_store_(state_store), 263 state_store_(state_store),
65 weak_factory_(this) { 264 weak_factory_(this) {
66 DCHECK(state_store); 265 DCHECK(state_store);
67 } 266 }
68 267
69 PlatformKeysService::~PlatformKeysService() { 268 PlatformKeysService::~PlatformKeysService() {
70 } 269 }
71 270
72 void PlatformKeysService::DisablePermissionCheckForTesting() { 271 void PlatformKeysService::DisablePermissionCheckForTesting() {
73 permission_check_enabled_ = false; 272 permission_check_enabled_ = false;
74 } 273 }
75 274
76 void PlatformKeysService::GenerateRSAKey(const std::string& token_id, 275 void PlatformKeysService::GenerateRSAKey(const std::string& token_id,
77 unsigned int modulus_length, 276 unsigned int modulus_length,
78 const std::string& extension_id, 277 const std::string& extension_id,
79 const GenerateKeyCallback& callback) { 278 const GenerateKeyCallback& callback) {
80 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 279 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
81 280
82 platform_keys::subtle::GenerateRSAKey( 281 platform_keys::subtle::GenerateRSAKey(
83 token_id, 282 token_id, modulus_length,
84 modulus_length, 283 base::Bind(&PlatformKeysService::GeneratedKey, weak_factory_.GetWeakPtr(),
85 base::Bind(&PlatformKeysService::GenerateRSAKeyCallback, 284 extension_id, callback),
86 weak_factory_.GetWeakPtr(),
87 extension_id,
88 callback),
89 browser_context_); 285 browser_context_);
90 } 286 }
91 287
92 void PlatformKeysService::SignRSA( 288 void PlatformKeysService::SignRSA(
93 const std::string& token_id, 289 const std::string& token_id,
94 scoped_ptr<platform_keys::SignRSAParams> params, 290 scoped_ptr<platform_keys::SignRSAParams> params,
95 const std::string& extension_id, 291 const std::string& extension_id,
96 const SignCallback& callback) { 292 const SignCallback& callback) {
97 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 293 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
98 ReadValidityAndInvalidateKey( 294 StartOrQueueTask(make_scoped_ptr(
99 extension_id, params->public_key(), 295 new SignTask(token_id, params.Pass(), extension_id, callback, this)));
100 base::Bind(&CheckValidityAndSign, token_id, base::Passed(&params),
101 callback, browser_context_));
102 } 296 }
103 297
104 void PlatformKeysService::SelectClientCertificates( 298 void PlatformKeysService::SelectClientCertificates(
105 const platform_keys::ClientCertificateRequest& request, 299 const platform_keys::ClientCertificateRequest& request,
106 const std::string& extension_id, 300 const std::string& extension_id,
107 const SelectCertificatesCallback& callback) { 301 const SelectCertificatesCallback& callback) {
108 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 302 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
109 303
110 platform_keys::subtle::SelectClientCertificates( 304 platform_keys::subtle::SelectClientCertificates(
111 request, 305 request,
112 base::Bind(&PlatformKeysService::SelectClientCertificatesCallback, 306 base::Bind(&PlatformKeysService::SelectClientCertificatesCallback,
113 weak_factory_.GetWeakPtr(), extension_id, callback), 307 weak_factory_.GetWeakPtr(), extension_id, callback),
114 browser_context_); 308 browser_context_);
115 } 309 }
116 310
117 void PlatformKeysService::RegisterPublicKey( 311 void PlatformKeysService::StartOrQueueTask(scoped_ptr<Task> task) {
118 const std::string& extension_id, 312 tasks_.push(make_linked_ptr(task.release()));
119 const std::string& public_key_spki_der, 313 if (tasks_.size() == 1)
120 const base::Closure& callback) { 314 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 } 315 }
129 316
130 void PlatformKeysService::ReadValidityAndInvalidateKey( 317 void PlatformKeysService::TaskFinished(Task* task) {
131 const std::string& extension_id, 318 DCHECK(!tasks_.empty());
132 const std::string& public_key_spki_der, 319 DCHECK(task == tasks_.front().get());
133 const base::Callback<void(bool)>& callback) { 320 while (!tasks_.empty() && tasks_.front()->IsDone())
134 GetPlatformKeysOfExtension(extension_id, 321 tasks_.pop();
135 base::Bind(&PlatformKeysService::InvalidateKey, 322
136 weak_factory_.GetWeakPtr(), 323 if (!tasks_.empty())
137 extension_id, 324 tasks_.front()->Start();
138 public_key_spki_der,
139 callback));
140 } 325 }
141 326
142 void PlatformKeysService::GetPlatformKeysOfExtension( 327 void PlatformKeysService::GetPlatformKeysOfExtension(
143 const std::string& extension_id, 328 const std::string& extension_id,
144 const GetPlatformKeysCallback& callback) { 329 const GetPlatformKeysCallback& callback) {
145 state_store_->GetExtensionValue( 330 state_store_->GetExtensionValue(
146 extension_id, kStateStorePlatformKeys, 331 extension_id, kStateStorePlatformKeys,
147 base::Bind(&PlatformKeysService::GotPlatformKeysOfExtension, 332 base::Bind(&PlatformKeysService::GotPlatformKeysOfExtension,
148 weak_factory_.GetWeakPtr(), extension_id, callback)); 333 weak_factory_.GetWeakPtr(), extension_id, callback));
149 } 334 }
150 335
151 void PlatformKeysService::SetPlatformKeysOfExtension( 336 void PlatformKeysService::SetPlatformKeysOfExtension(
152 const std::string& extension_id, 337 const std::string& extension_id,
153 scoped_ptr<base::ListValue> platform_keys) { 338 scoped_ptr<base::ListValue> platform_keys) {
154 state_store_->SetExtensionValue(extension_id, kStateStorePlatformKeys, 339 state_store_->SetExtensionValue(extension_id, kStateStorePlatformKeys,
155 platform_keys.Pass()); 340 platform_keys.Pass());
156 } 341 }
157 342
158 void PlatformKeysService::GenerateRSAKeyCallback( 343 void PlatformKeysService::GeneratedKey(const std::string& extension_id,
159 const std::string& extension_id, 344 const GenerateKeyCallback& callback,
160 const GenerateKeyCallback& callback, 345 const std::string& public_key_spki_der,
161 const std::string& public_key_spki_der, 346 const std::string& error_message) {
162 const std::string& error_message) {
163 if (!error_message.empty()) { 347 if (!error_message.empty()) {
164 callback.Run(std::string() /* no public key */, error_message); 348 callback.Run(std::string() /* no public key */, error_message);
165 return; 349 return;
166 } 350 }
167 base::Closure wrapped_callback( 351
168 base::Bind(&RunGenerateKeyCallback, callback, public_key_spki_der)); 352 StartOrQueueTask(make_scoped_ptr(new PermissionUpdateTask(
169 RegisterPublicKey(extension_id, public_key_spki_der, wrapped_callback); 353 true /* new permission value */, public_key_spki_der, extension_id,
354 base::Bind(&PlatformKeysService::DidRegisterGeneratedKey,
355 base::Unretained(this), callback, public_key_spki_der),
356 this)));
357 }
358
359 void PlatformKeysService::DidRegisterGeneratedKey(
360 const GenerateKeyCallback& callback,
361 const std::string& public_key_spki_der,
362 Task* task) {
363 callback.Run(public_key_spki_der, std::string() /* no error */);
364 TaskFinished(task);
170 } 365 }
171 366
172 void PlatformKeysService::SelectClientCertificatesCallback( 367 void PlatformKeysService::SelectClientCertificatesCallback(
173 const std::string& extension_id, 368 const std::string& extension_id,
174 const SelectCertificatesCallback& callback, 369 const SelectCertificatesCallback& callback,
175 scoped_ptr<net::CertificateList> matches, 370 scoped_ptr<net::CertificateList> matches,
176 const std::string& error_message) { 371 const std::string& error_message) {
177 if (permission_check_enabled_) 372 if (permission_check_enabled_)
178 matches->clear(); 373 matches->clear();
179 374
180 // TODO(pneubeck): Remove all certs that the extension doesn't have access to. 375 // TODO(pneubeck): Remove all certs that the extension doesn't have access to.
181 callback.Run(matches.Pass(), error_message); 376 callback.Run(matches.Pass(), error_message);
182 } 377 }
183 378
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( 379 void PlatformKeysService::GotPlatformKeysOfExtension(
230 const std::string& extension_id, 380 const std::string& extension_id,
231 const GetPlatformKeysCallback& callback, 381 const GetPlatformKeysCallback& callback,
232 scoped_ptr<base::Value> value) { 382 scoped_ptr<base::Value> value) {
233 if (!value) 383 if (!value)
234 value.reset(new base::ListValue); 384 value.reset(new base::ListValue);
235 385
236 base::ListValue* keys = NULL; 386 base::ListValue* keys = NULL;
237 if (!value->GetAsList(&keys)) { 387 if (!value->GetAsList(&keys)) {
238 LOG(ERROR) << "Found a value of wrong type."; 388 LOG(ERROR) << "Found a value of wrong type.";
239 389
240 keys = new base::ListValue; 390 keys = new base::ListValue;
241 value.reset(keys); 391 value.reset(keys);
242 } 392 }
243 393
244 ignore_result(value.release()); 394 ignore_result(value.release());
245 callback.Run(make_scoped_ptr(keys)); 395 callback.Run(make_scoped_ptr(keys));
246 } 396 }
247 397
248 } // namespace chromeos 398 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698