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

Side by Side Diff: content/child/webcrypto/webcrypto_impl.cc

Issue 233733004: [webcrypto] Make operations run on worker threads. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix a crash (RSA-OAEP keys not supported) Created 6 years, 8 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 | Annotate | Revision Log
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 "content/child/webcrypto/webcrypto_impl.h" 5 #include "content/child/webcrypto/webcrypto_impl.h"
6 6
7 #include "base/bind.h"
8 #include "base/lazy_instance.h"
9 #include "base/location.h"
7 #include "base/logging.h" 10 #include "base/logging.h"
8 #include "base/memory/scoped_ptr.h" 11 #include "base/memory/scoped_ptr.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/task_runner.h"
14 #include "base/thread_task_runner_handle.h"
15 #include "base/threading/sequenced_worker_pool.h"
16 #include "base/threading/worker_pool.h"
9 #include "content/child/webcrypto/crypto_data.h" 17 #include "content/child/webcrypto/crypto_data.h"
10 #include "content/child/webcrypto/shared_crypto.h" 18 #include "content/child/webcrypto/shared_crypto.h"
11 #include "content/child/webcrypto/status.h" 19 #include "content/child/webcrypto/status.h"
12 #include "content/child/webcrypto/webcrypto_util.h" 20 #include "content/child/webcrypto/webcrypto_util.h"
21 #include "content/child/worker_thread_task_runner.h"
13 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h" 22 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
14 #include "third_party/WebKit/public/platform/WebString.h" 23 #include "third_party/WebKit/public/platform/WebString.h"
15 24
16 namespace content { 25 namespace content {
17 26
18 using webcrypto::Status; 27 using webcrypto::Status;
19 28
20 namespace { 29 namespace {
21 30
31 // ---------------------
32 // Threading
33 // ---------------------
34 //
35 // WebCrypto operations can be slow. For instance generating an RSA key can
36 // takes hundreds of milliseconds.
Ryan Sleevi 2014/04/18 00:51:26 "hundreds of milliseconds to several seconds" (eg:
eroman 2014/04/18 18:45:56 Done.
37 //
38 // Moreover the underlying crypto libraries are not threadsafe when operating
39 // on the same key.
40 //
41 // The strategy used here is to run a sequenced worker pool for all WebCrypto
42 // operations. This pool (of 1 threads) is also used by requests started from
43 // blink Web Workers.
Ryan Sleevi 2014/04/18 00:51:26 s/blink/Blink/
44 //
45 // A few notes to keep in mind:
46 //
47 // * PostTaskAndReply() cannot be used for two reasons:
48 //
49 // (1) Blink Web Worker threads do not have an associated message loop so
50 // construction of the reply callback will crash.
51 //
52 // (2) PostTaskAndReply() handles failure posting the reply by leaking the
53 // callback, rather than destroying it. In the case of Web Workers this
54 // condition is reachable via normal execution, since Web Workers can
55 // be stopped before the WebCrypto operation has finished. A policy of
56 // leaking would therefore be problematic.
57 //
58 // * blink::WebArrayBuffer is NOT threadsafe, and should therefore be allocated
59 // on the target blink thread.
60 //
61 // TODO(eroman): Is there any way around this? Copying the result between
62 // threads is silly.
63 //
64 // * WebCryptoAlgorithm and WebCryptoKey are threadsafe (however the key's
65 // handle() which wraps an NSS/OpenSSL type may not be, and should only be
Ryan Sleevi 2014/04/18 00:51:26 s/handle() /handle(), / s/type may/type, may/
eroman 2014/04/18 18:45:56 Done.
66 // used from the webcrypto thread).
67 //
68 // * blink::WebCryptoResult is NOT threadsafe and should only be operated on
69 // the target blink thread.
Ryan Sleevi 2014/04/18 00:51:26 s/blink/Blink/
70 //
71 // TODO(eroman): In the current design the WebCryptoResult object may be
72 // destroyed from the webcrypto worker pool if the blink worker
Ryan Sleevi 2014/04/18 00:51:26 s/blink/Blink/
73 // thread has vanished by the time the operation completes. This
74 // requires further investigation since WebCryptoResult itself is
75 // not thread safe... However if the worker thread has been
76 // stopped then the potential for races seems limited.
77 class CryptoThreadPool {
78 public:
79 CryptoThreadPool()
80 : worker_pool_(new base::SequencedWorkerPool(1, "WebCrypto")),
81 task_runner_(worker_pool_->GetSequencedTaskRunnerWithShutdownBehavior(
82 worker_pool_->GetSequenceToken(),
83 base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN)) {}
84
85 static bool PostTask(const tracked_objects::Location& from_here,
86 const base::Closure& task);
87
88 private:
89 scoped_refptr<base::SequencedWorkerPool> worker_pool_;
90 scoped_refptr<base::SequencedTaskRunner> task_runner_;
91 };
92
93 base::LazyInstance<CryptoThreadPool> crypto_thread_pool =
Ryan Sleevi 2014/04/18 00:51:26 LeakyLazyInstance
eroman 2014/04/18 18:45:56 Done.
94 LAZY_INSTANCE_INITIALIZER;
95
96 bool CryptoThreadPool::PostTask(const tracked_objects::Location& from_here,
97 const base::Closure& task) {
98 return crypto_thread_pool.Get().task_runner_->PostTask(from_here, task);
99 }
100
101 const char kFailedPostingToThreadPool[] =
102 "Failed posting to crypto worker pool";
103
22 void CompleteWithError(const Status& status, blink::WebCryptoResult* result) { 104 void CompleteWithError(const Status& status, blink::WebCryptoResult* result) {
23 DCHECK(status.IsError()); 105 DCHECK(status.IsError());
24 if (status.HasErrorDetails()) 106 if (status.HasErrorDetails())
25 result->completeWithError(blink::WebString::fromUTF8(status.ToString())); 107 result->completeWithError(blink::WebString::fromUTF8(status.ToString()));
26 else 108 else
27 result->completeWithError(); 109 result->completeWithError();
28 } 110 }
29 111
112 void CompleteWithBuffer(const Status& status,
113 const std::vector<uint8>& buffer,
114 blink::WebCryptoResult* result) {
115 if (status.IsError())
116 CompleteWithError(status, result);
117 else {
Ryan Sleevi 2014/04/18 00:51:26 use braces on 115 and 117 to match 117
eroman 2014/04/18 18:45:56 Done.
118 if (buffer.size() > UINT_MAX) {
119 // WebArrayBuffers have a smaller range than std::vector<>, so
120 // theoretically this could overflow.
121 CompleteWithError(Status::ErrorUnexpected(), result);
122 } else {
123 result->completeWithBuffer(webcrypto::Uint8VectorStart(buffer),
124 buffer.size());
125 }
126 }
127 }
128
129 void CompleteWithKey(const Status& status,
130 const blink::WebCryptoKey& key,
131 blink::WebCryptoResult* result) {
132 if (status.IsError())
133 CompleteWithError(status, result);
134 else {
135 result->completeWithKey(key);
136 }
Ryan Sleevi 2014/04/18 00:51:26 inconsistent braces. Brace ALL the things or brace
eroman 2014/04/18 18:45:56 Done. I agree. Not sure how this happened, proba
137 }
138
30 bool IsAlgorithmAsymmetric(const blink::WebCryptoAlgorithm& algorithm) { 139 bool IsAlgorithmAsymmetric(const blink::WebCryptoAlgorithm& algorithm) {
31 // TODO(padolph): include all other asymmetric algorithms once they are 140 // TODO(padolph): include all other asymmetric algorithms once they are
32 // defined, e.g. EC and DH. 141 // defined, e.g. EC and DH.
33 return (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 || 142 return (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 ||
34 algorithm.id() == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 || 143 algorithm.id() == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 ||
35 algorithm.id() == blink::WebCryptoAlgorithmIdRsaOaep); 144 algorithm.id() == blink::WebCryptoAlgorithmIdRsaOaep);
36 } 145 }
37 146
147 // Blink WebWorker threads do not have an associated task runner.
148 scoped_refptr<base::TaskRunner> GetCurrentBlinkThread() {
149 if (base::ThreadTaskRunnerHandle::IsSet())
150 return base::ThreadTaskRunnerHandle::Get();
151 return WorkerThreadTaskRunner::current();
152 }
Ryan Sleevi 2014/04/18 00:51:26 This comment and this function do not make sense i
eroman 2014/04/18 18:45:56 Changed the comment to hopefully clarify things:
153
154 // --------------------------------------------------------------------
155 // State
156 // --------------------------------------------------------------------
157 //
158 // Explicit state classes are used rather than base::Bind(). This is done
159 // both for clarity, but also to avoid extraneous allocations for things
160 // like passing buffers and result objects between threads.
161 //
162 // BaseState is the base class common to all of the async operations, and
163 // keeps track of the thread to complete on, the error state, and the
164 // callback into blink.
165 //
166 // Ownership of the State object is passed between the crypto thread and the
167 // Blink thread. Under normal completion it is destroyed on the Blink thread.
168 // However it may also be destroyed on the crypto thread if the Blink thread
169 // has vanished (which can happen for blink web worker threads).
170
171 struct BaseState {
172 explicit BaseState(const blink::WebCryptoResult& result)
173 : origin_thread(GetCurrentBlinkThread()), result(result) {}
174
175 scoped_refptr<base::TaskRunner> origin_thread;
176
177 webcrypto::Status status;
178 blink::WebCryptoResult result;
179
180 protected:
181 // Since there is no virtual destructor, must not delete directly as a
182 // BaseState.
183 ~BaseState() {}
184 };
185
186 struct EncryptState : public BaseState {
187 EncryptState(const blink::WebCryptoAlgorithm& algorithm,
188 const blink::WebCryptoKey& key,
189 const unsigned char* data,
190 unsigned int data_size,
191 const blink::WebCryptoResult& result)
192 : BaseState(result),
193 algorithm(algorithm),
194 key(key),
195 data(data, data + data_size) {}
196
197 const blink::WebCryptoAlgorithm algorithm;
198 const blink::WebCryptoKey key;
199 const std::vector<uint8> data;
200
201 std::vector<uint8> buffer;
202 };
203
204 typedef EncryptState DecryptState;
205 typedef EncryptState DigestState;
206
207 struct GenerateKeyState : public BaseState {
208 GenerateKeyState(const blink::WebCryptoAlgorithm& algorithm,
209 bool extractable,
210 blink::WebCryptoKeyUsageMask usage_mask,
211 const blink::WebCryptoResult& result)
212 : BaseState(result),
213 algorithm(algorithm),
214 extractable(extractable),
215 usage_mask(usage_mask),
216 public_key(blink::WebCryptoKey::createNull()),
217 private_key(blink::WebCryptoKey::createNull()),
218 is_asymetric(false) {}
219
220 const blink::WebCryptoAlgorithm algorithm;
221 const bool extractable;
222 const blink::WebCryptoKeyUsageMask usage_mask;
223
224 // If |is_asymetric| is false, then |public_key| is understood to mean the
Ryan Sleevi 2014/04/18 00:51:26 asymmetric
eroman 2014/04/18 18:45:56 Done throughout.
225 // symmetric key, and |private_key| is unused.
226 blink::WebCryptoKey public_key;
227 blink::WebCryptoKey private_key;
228 bool is_asymetric;
Ryan Sleevi 2014/04/18 00:51:26 asymmetric
229 };
230
231 struct ImportKeyState : public BaseState {
232 ImportKeyState(blink::WebCryptoKeyFormat format,
233 const unsigned char* key_data,
234 unsigned int key_data_size,
235 const blink::WebCryptoAlgorithm& algorithm,
236 bool extractable,
237 blink::WebCryptoKeyUsageMask usage_mask,
238 const blink::WebCryptoResult& result)
239 : BaseState(result),
240 format(format),
241 key_data(key_data, key_data + key_data_size),
242 algorithm(algorithm),
243 extractable(extractable),
244 usage_mask(usage_mask),
245 key(blink::WebCryptoKey::createNull()) {}
246
247 const blink::WebCryptoKeyFormat format;
248 const std::vector<uint8> key_data;
249 const blink::WebCryptoAlgorithm algorithm;
250 const bool extractable;
251 const blink::WebCryptoKeyUsageMask usage_mask;
252
253 blink::WebCryptoKey key;
254 };
255
256 struct ExportKeyState : public BaseState {
257 ExportKeyState(blink::WebCryptoKeyFormat format,
258 const blink::WebCryptoKey& key,
259 const blink::WebCryptoResult& result)
260 : BaseState(result), format(format), key(key) {}
261
262 const blink::WebCryptoKeyFormat format;
263 const blink::WebCryptoKey key;
264
265 std::vector<uint8> buffer;
266 };
267
268 typedef EncryptState SignState;
269
270 struct VerifySignatureState : public BaseState {
271 VerifySignatureState(const blink::WebCryptoAlgorithm& algorithm,
272 const blink::WebCryptoKey& key,
273 const unsigned char* signature,
274 unsigned int signature_size,
275 const unsigned char* data,
276 unsigned int data_size,
277 const blink::WebCryptoResult& result)
278 : BaseState(result),
279 algorithm(algorithm),
280 key(key),
281 signature(signature, signature + signature_size),
282 data(data, data + data_size),
283 verify_result(false) {}
284
285 const blink::WebCryptoAlgorithm algorithm;
286 const blink::WebCryptoKey key;
287 const std::vector<uint8> signature;
288 const std::vector<uint8> data;
289
290 bool verify_result;
291 };
292
293 struct WrapKeyState : public BaseState {
294 WrapKeyState(blink::WebCryptoKeyFormat format,
295 const blink::WebCryptoKey& key,
296 const blink::WebCryptoKey& wrapping_key,
297 const blink::WebCryptoAlgorithm& wrap_algorithm,
298 const blink::WebCryptoResult& result)
299 : BaseState(result),
300 format(format),
301 key(key),
302 wrapping_key(wrapping_key),
303 wrap_algorithm(wrap_algorithm) {}
304
305 const blink::WebCryptoKeyFormat format;
306 const blink::WebCryptoKey key;
307 const blink::WebCryptoKey wrapping_key;
308 const blink::WebCryptoAlgorithm wrap_algorithm;
309
310 std::vector<uint8> buffer;
311 };
312
313 struct UnwrapKeyState : public BaseState {
314 UnwrapKeyState(blink::WebCryptoKeyFormat format,
315 const unsigned char* wrapped_key,
316 unsigned wrapped_key_size,
317 const blink::WebCryptoKey& wrapping_key,
318 const blink::WebCryptoAlgorithm& unwrap_algorithm,
319 const blink::WebCryptoAlgorithm& unwrapped_key_algorithm,
320 bool extractable,
321 blink::WebCryptoKeyUsageMask usages,
322 const blink::WebCryptoResult& result)
323 : BaseState(result),
324 format(format),
325 wrapped_key(wrapped_key, wrapped_key + wrapped_key_size),
326 wrapping_key(wrapping_key),
327 unwrap_algorithm(unwrap_algorithm),
328 unwrapped_key_algorithm(unwrapped_key_algorithm),
329 extractable(extractable),
330 usages(usages),
331 unwrapped_key(blink::WebCryptoKey::createNull()) {}
332
333 const blink::WebCryptoKeyFormat format;
334 const std::vector<uint8> wrapped_key;
335 const blink::WebCryptoKey wrapping_key;
336 const blink::WebCryptoAlgorithm unwrap_algorithm;
337 const blink::WebCryptoAlgorithm unwrapped_key_algorithm;
338 const bool extractable;
339 const blink::WebCryptoKeyUsageMask usages;
340
341 blink::WebCryptoKey unwrapped_key;
342 };
343
344 // --------------------------------------------------------------------
345 // Wrapper functions
346 // --------------------------------------------------------------------
347 //
348 // * The methods named Do*() run on the crypto thread.
349 // * The methods named Do*Reply() run on the target Blink thread
350
351 void DoEncryptReply(scoped_ptr<EncryptState> state) {
352 CompleteWithBuffer(state->status, state->buffer, &state->result);
353 }
354
355 void DoEncrypt(scoped_ptr<EncryptState> state) {
356 state->status = webcrypto::Encrypt(state->algorithm,
357 state->key,
358 webcrypto::CryptoData(state->data),
359 &state->buffer);
360 state->origin_thread->PostTask(FROM_HERE,
361 base::Bind(DoEncryptReply, Passed(&state)));
362 }
363
364 void DoDecryptReply(scoped_ptr<DecryptState> state) {
365 CompleteWithBuffer(state->status, state->buffer, &state->result);
366 }
367
368 void DoDecrypt(scoped_ptr<DecryptState> state) {
369 state->status = webcrypto::Decrypt(state->algorithm,
370 state->key,
371 webcrypto::CryptoData(state->data),
372 &state->buffer);
373 state->origin_thread->PostTask(FROM_HERE,
374 base::Bind(DoDecryptReply, Passed(&state)));
375 }
376
377 void DoDigestReply(scoped_ptr<DigestState> state) {
378 CompleteWithBuffer(state->status, state->buffer, &state->result);
379 }
380
381 void DoDigest(scoped_ptr<DigestState> state) {
382 state->status = webcrypto::Digest(
383 state->algorithm, webcrypto::CryptoData(state->data), &state->buffer);
384 state->origin_thread->PostTask(FROM_HERE,
385 base::Bind(DoDigestReply, Passed(&state)));
386 }
387
388 void DoGenerateKeyReply(scoped_ptr<GenerateKeyState> state) {
389 if (state->status.IsError()) {
390 CompleteWithError(state->status, &state->result);
Ryan Sleevi 2014/04/18 00:51:26 Why do you allow CompleteWithError() here and in D
eroman 2014/04/18 18:45:56 Agreed. Done
391 } else {
392 if (state->is_asymetric)
393 state->result.completeWithKeyPair(state->public_key, state->private_key);
394 else
395 state->result.completeWithKey(state->public_key);
396 }
397 }
398
399 void DoGenerateKey(scoped_ptr<GenerateKeyState> state) {
400 state->is_asymetric = IsAlgorithmAsymmetric(state->algorithm);
401 if (state->is_asymetric) {
402 state->status = webcrypto::GenerateKeyPair(state->algorithm,
403 state->extractable,
404 state->usage_mask,
405 &state->public_key,
406 &state->private_key);
407
408 DCHECK(state->public_key.handle());
409 DCHECK(state->private_key.handle());
410 DCHECK_EQ(state->algorithm.id(), state->public_key.algorithm().id());
411 DCHECK_EQ(state->algorithm.id(), state->private_key.algorithm().id());
412 DCHECK_EQ(true, state->public_key.extractable());
413 DCHECK_EQ(state->extractable, state->private_key.extractable());
414 DCHECK_EQ(state->usage_mask, state->public_key.usages());
415 DCHECK_EQ(state->usage_mask, state->private_key.usages());
416 } else {
417 blink::WebCryptoKey* key = &state->public_key;
418
419 state->status = webcrypto::GenerateSecretKey(
420 state->algorithm, state->extractable, state->usage_mask, key);
421
422 DCHECK(key->handle());
423 DCHECK_EQ(state->algorithm.id(), key->algorithm().id());
424 DCHECK_EQ(state->extractable, key->extractable());
425 DCHECK_EQ(state->usage_mask, key->usages());
426 }
427
428 state->origin_thread->PostTask(
429 FROM_HERE, base::Bind(DoGenerateKeyReply, Passed(&state)));
430 }
431
432 void DoImportKeyReply(scoped_ptr<ImportKeyState> state) {
433 CompleteWithKey(state->status, state->key, &state->result);
434 }
435
436 void DoImportKey(scoped_ptr<ImportKeyState> state) {
437 state->status = webcrypto::ImportKey(state->format,
438 webcrypto::CryptoData(state->key_data),
439 state->algorithm,
440 state->extractable,
441 state->usage_mask,
442 &state->key);
443 DCHECK(state->key.handle());
444 DCHECK(!state->key.algorithm().isNull());
445 DCHECK_EQ(state->extractable, state->key.extractable());
446
447 state->origin_thread->PostTask(FROM_HERE,
448 base::Bind(DoImportKeyReply, Passed(&state)));
449 }
450
451 void DoExportKeyReply(scoped_ptr<ExportKeyState> state) {
452 CompleteWithBuffer(state->status, state->buffer, &state->result);
453 }
454
455 void DoExportKey(scoped_ptr<ExportKeyState> state) {
456 state->status =
457 webcrypto::ExportKey(state->format, state->key, &state->buffer);
458 state->origin_thread->PostTask(FROM_HERE,
459 base::Bind(DoExportKeyReply, Passed(&state)));
460 }
461
462 void DoSignReply(scoped_ptr<SignState> state) {
463 CompleteWithBuffer(state->status, state->buffer, &state->result);
464 }
465
466 void DoSign(scoped_ptr<SignState> state) {
467 state->status = webcrypto::Sign(state->algorithm,
468 state->key,
469 webcrypto::CryptoData(state->data),
470 &state->buffer);
471
472 state->origin_thread->PostTask(FROM_HERE,
473 base::Bind(DoSignReply, Passed(&state)));
474 }
475
476 void DoVerifyReply(scoped_ptr<VerifySignatureState> state) {
477 if (state->status.IsError()) {
478 CompleteWithError(state->status, &state->result);
479 } else {
480 state->result.completeWithBoolean(state->verify_result);
481 }
482 }
483
484 void DoVerify(scoped_ptr<VerifySignatureState> state) {
485 state->status =
486 webcrypto::VerifySignature(state->algorithm,
487 state->key,
488 webcrypto::CryptoData(state->signature),
489 webcrypto::CryptoData(state->data),
490 &state->verify_result);
491
492 state->origin_thread->PostTask(FROM_HERE,
493 base::Bind(DoVerifyReply, Passed(&state)));
494 }
495
496 void DoWrapKeyReply(scoped_ptr<WrapKeyState> state) {
497 CompleteWithBuffer(state->status, state->buffer, &state->result);
498 }
499
500 void DoWrapKey(scoped_ptr<WrapKeyState> state) {
501 // TODO(eroman): The parameter ordering of webcrypto::WrapKey() is
502 // inconsistent with that of blink::WebCrypto::wrapKey().
503 state->status = webcrypto::WrapKey(state->format,
504 state->wrapping_key,
505 state->key,
506 state->wrap_algorithm,
507 &state->buffer);
508
509 state->origin_thread->PostTask(FROM_HERE,
510 base::Bind(DoWrapKeyReply, Passed(&state)));
511 }
512
513 void DoUnwrapKeyReply(scoped_ptr<UnwrapKeyState> state) {
514 CompleteWithKey(state->status, state->unwrapped_key, &state->result);
515 }
516
517 void DoUnwrapKey(scoped_ptr<UnwrapKeyState> state) {
518 state->status =
519 webcrypto::UnwrapKey(state->format,
520 webcrypto::CryptoData(state->wrapped_key),
521 state->wrapping_key,
522 state->unwrap_algorithm,
523 state->unwrapped_key_algorithm,
524 state->extractable,
525 state->usages,
526 &state->unwrapped_key);
527
528 state->origin_thread->PostTask(FROM_HERE,
529 base::Bind(DoUnwrapKeyReply, Passed(&state)));
530 }
531
38 } // namespace 532 } // namespace
39 533
40 WebCryptoImpl::WebCryptoImpl() { webcrypto::Init(); } 534 WebCryptoImpl::WebCryptoImpl() {
41 535 webcrypto::Init();
42 WebCryptoImpl::~WebCryptoImpl() {} 536 }
537
538 WebCryptoImpl::~WebCryptoImpl() {
539 }
43 540
44 void WebCryptoImpl::encrypt(const blink::WebCryptoAlgorithm& algorithm, 541 void WebCryptoImpl::encrypt(const blink::WebCryptoAlgorithm& algorithm,
45 const blink::WebCryptoKey& key, 542 const blink::WebCryptoKey& key,
46 const unsigned char* data, 543 const unsigned char* data,
47 unsigned int data_size, 544 unsigned int data_size,
48 blink::WebCryptoResult result) { 545 blink::WebCryptoResult result) {
49 DCHECK(!algorithm.isNull()); 546 DCHECK(!algorithm.isNull());
50 blink::WebArrayBuffer buffer; 547
51 Status status = webcrypto::Encrypt( 548 scoped_ptr<EncryptState> state(
52 algorithm, key, webcrypto::CryptoData(data, data_size), &buffer); 549 new EncryptState(algorithm, key, data, data_size, result));
53 if (status.IsError()) 550 if (!CryptoThreadPool::PostTask(FROM_HERE,
54 CompleteWithError(status, &result); 551 base::Bind(DoEncrypt, Passed(&state)))) {
55 else 552 result.completeWithError(kFailedPostingToThreadPool);
56 result.completeWithBuffer(buffer); 553 }
57 } 554 }
58 555
59 void WebCryptoImpl::decrypt(const blink::WebCryptoAlgorithm& algorithm, 556 void WebCryptoImpl::decrypt(const blink::WebCryptoAlgorithm& algorithm,
60 const blink::WebCryptoKey& key, 557 const blink::WebCryptoKey& key,
61 const unsigned char* data, 558 const unsigned char* data,
62 unsigned int data_size, 559 unsigned int data_size,
63 blink::WebCryptoResult result) { 560 blink::WebCryptoResult result) {
64 DCHECK(!algorithm.isNull()); 561 DCHECK(!algorithm.isNull());
65 blink::WebArrayBuffer buffer; 562
66 Status status = webcrypto::Decrypt( 563 scoped_ptr<DecryptState> state(
67 algorithm, key, webcrypto::CryptoData(data, data_size), &buffer); 564 new DecryptState(algorithm, key, data, data_size, result));
68 if (status.IsError()) 565 if (!CryptoThreadPool::PostTask(FROM_HERE,
69 CompleteWithError(status, &result); 566 base::Bind(DoDecrypt, Passed(&state)))) {
70 else 567 result.completeWithError(kFailedPostingToThreadPool);
71 result.completeWithBuffer(buffer); 568 }
72 } 569 }
73 570
74 void WebCryptoImpl::digest(const blink::WebCryptoAlgorithm& algorithm, 571 void WebCryptoImpl::digest(const blink::WebCryptoAlgorithm& algorithm,
75 const unsigned char* data, 572 const unsigned char* data,
76 unsigned int data_size, 573 unsigned int data_size,
77 blink::WebCryptoResult result) { 574 blink::WebCryptoResult result) {
78 DCHECK(!algorithm.isNull()); 575 DCHECK(!algorithm.isNull());
79 blink::WebArrayBuffer buffer; 576
80 Status status = webcrypto::Digest( 577 scoped_ptr<DigestState> state(new DigestState(
81 algorithm, webcrypto::CryptoData(data, data_size), &buffer); 578 algorithm, blink::WebCryptoKey::createNull(), data, data_size, result));
82 if (status.IsError()) 579 if (!CryptoThreadPool::PostTask(FROM_HERE,
83 CompleteWithError(status, &result); 580 base::Bind(DoDigest, Passed(&state)))) {
84 else 581 result.completeWithError(kFailedPostingToThreadPool);
85 result.completeWithBuffer(buffer); 582 }
86 } 583 }
87 584
88 void WebCryptoImpl::generateKey(const blink::WebCryptoAlgorithm& algorithm, 585 void WebCryptoImpl::generateKey(const blink::WebCryptoAlgorithm& algorithm,
89 bool extractable, 586 bool extractable,
90 blink::WebCryptoKeyUsageMask usage_mask, 587 blink::WebCryptoKeyUsageMask usage_mask,
91 blink::WebCryptoResult result) { 588 blink::WebCryptoResult result) {
92 DCHECK(!algorithm.isNull()); 589 DCHECK(!algorithm.isNull());
93 if (IsAlgorithmAsymmetric(algorithm)) { 590
94 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull(); 591 scoped_ptr<GenerateKeyState> state(
95 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull(); 592 new GenerateKeyState(algorithm, extractable, usage_mask, result));
96 Status status = webcrypto::GenerateKeyPair( 593 if (!CryptoThreadPool::PostTask(FROM_HERE,
97 algorithm, extractable, usage_mask, &public_key, &private_key); 594 base::Bind(DoGenerateKey, Passed(&state)))) {
98 if (status.IsError()) { 595 result.completeWithError(kFailedPostingToThreadPool);
99 CompleteWithError(status, &result);
100 } else {
101 DCHECK(public_key.handle());
102 DCHECK(private_key.handle());
103 DCHECK_EQ(algorithm.id(), public_key.algorithm().id());
104 DCHECK_EQ(algorithm.id(), private_key.algorithm().id());
105 DCHECK_EQ(true, public_key.extractable());
106 DCHECK_EQ(extractable, private_key.extractable());
107 DCHECK_EQ(usage_mask, public_key.usages());
108 DCHECK_EQ(usage_mask, private_key.usages());
109 result.completeWithKeyPair(public_key, private_key);
110 }
111 } else {
112 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
113 Status status =
114 webcrypto::GenerateSecretKey(algorithm, extractable, usage_mask, &key);
115 if (status.IsError()) {
116 CompleteWithError(status, &result);
117 } else {
118 DCHECK(key.handle());
119 DCHECK_EQ(algorithm.id(), key.algorithm().id());
120 DCHECK_EQ(extractable, key.extractable());
121 DCHECK_EQ(usage_mask, key.usages());
122 result.completeWithKey(key);
123 }
124 } 596 }
125 } 597 }
126 598
127 void WebCryptoImpl::importKey(blink::WebCryptoKeyFormat format, 599 void WebCryptoImpl::importKey(blink::WebCryptoKeyFormat format,
128 const unsigned char* key_data, 600 const unsigned char* key_data,
129 unsigned int key_data_size, 601 unsigned int key_data_size,
130 const blink::WebCryptoAlgorithm& algorithm, 602 const blink::WebCryptoAlgorithm& algorithm,
131 bool extractable, 603 bool extractable,
132 blink::WebCryptoKeyUsageMask usage_mask, 604 blink::WebCryptoKeyUsageMask usage_mask,
133 blink::WebCryptoResult result) { 605 blink::WebCryptoResult result) {
134 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); 606 scoped_ptr<ImportKeyState> state(new ImportKeyState(format,
135 Status status = 607 key_data,
136 webcrypto::ImportKey(format, 608 key_data_size,
137 webcrypto::CryptoData(key_data, key_data_size), 609 algorithm,
138 algorithm, 610 extractable,
139 extractable, 611 usage_mask,
140 usage_mask, 612 result));
141 &key); 613 if (!CryptoThreadPool::PostTask(FROM_HERE,
142 if (status.IsError()) { 614 base::Bind(DoImportKey, Passed(&state)))) {
143 CompleteWithError(status, &result); 615 result.completeWithError(kFailedPostingToThreadPool);
144 } else {
145 DCHECK(key.handle());
146 DCHECK(!key.algorithm().isNull());
147 DCHECK_EQ(extractable, key.extractable());
148 result.completeWithKey(key);
149 } 616 }
150 } 617 }
151 618
152 void WebCryptoImpl::exportKey(blink::WebCryptoKeyFormat format, 619 void WebCryptoImpl::exportKey(blink::WebCryptoKeyFormat format,
153 const blink::WebCryptoKey& key, 620 const blink::WebCryptoKey& key,
154 blink::WebCryptoResult result) { 621 blink::WebCryptoResult result) {
155 blink::WebArrayBuffer buffer; 622 scoped_ptr<ExportKeyState> state(new ExportKeyState(format, key, result));
156 Status status = webcrypto::ExportKey(format, key, &buffer); 623 if (!CryptoThreadPool::PostTask(FROM_HERE,
157 if (status.IsError()) 624 base::Bind(DoExportKey, Passed(&state)))) {
158 CompleteWithError(status, &result); 625 result.completeWithError(kFailedPostingToThreadPool);
159 else 626 }
160 result.completeWithBuffer(buffer);
161 } 627 }
162 628
163 void WebCryptoImpl::sign(const blink::WebCryptoAlgorithm& algorithm, 629 void WebCryptoImpl::sign(const blink::WebCryptoAlgorithm& algorithm,
164 const blink::WebCryptoKey& key, 630 const blink::WebCryptoKey& key,
165 const unsigned char* data, 631 const unsigned char* data,
166 unsigned int data_size, 632 unsigned int data_size,
167 blink::WebCryptoResult result) { 633 blink::WebCryptoResult result) {
168 DCHECK(!algorithm.isNull()); 634 scoped_ptr<SignState> state(
169 blink::WebArrayBuffer buffer; 635 new SignState(algorithm, key, data, data_size, result));
170 Status status = webcrypto::Sign( 636 if (!CryptoThreadPool::PostTask(FROM_HERE,
171 algorithm, key, webcrypto::CryptoData(data, data_size), &buffer); 637 base::Bind(DoSign, Passed(&state)))) {
172 if (status.IsError()) 638 result.completeWithError(kFailedPostingToThreadPool);
173 CompleteWithError(status, &result); 639 }
174 else
175 result.completeWithBuffer(buffer);
176 } 640 }
177 641
178 void WebCryptoImpl::verifySignature(const blink::WebCryptoAlgorithm& algorithm, 642 void WebCryptoImpl::verifySignature(const blink::WebCryptoAlgorithm& algorithm,
179 const blink::WebCryptoKey& key, 643 const blink::WebCryptoKey& key,
180 const unsigned char* signature, 644 const unsigned char* signature,
181 unsigned int signature_size, 645 unsigned int signature_size,
182 const unsigned char* data, 646 const unsigned char* data,
183 unsigned int data_size, 647 unsigned int data_size,
184 blink::WebCryptoResult result) { 648 blink::WebCryptoResult result) {
185 DCHECK(!algorithm.isNull()); 649 scoped_ptr<VerifySignatureState> state(new VerifySignatureState(
186 bool signature_match = false; 650 algorithm, key, signature, signature_size, data, data_size, result));
187 Status status = webcrypto::VerifySignature( 651 if (!CryptoThreadPool::PostTask(FROM_HERE,
188 algorithm, 652 base::Bind(DoVerify, Passed(&state)))) {
189 key, 653 result.completeWithError(kFailedPostingToThreadPool);
190 webcrypto::CryptoData(signature, signature_size), 654 }
191 webcrypto::CryptoData(data, data_size),
192 &signature_match);
193 if (status.IsError())
194 CompleteWithError(status, &result);
195 else
196 result.completeWithBoolean(signature_match);
197 } 655 }
198 656
199 void WebCryptoImpl::wrapKey(blink::WebCryptoKeyFormat format, 657 void WebCryptoImpl::wrapKey(blink::WebCryptoKeyFormat format,
200 const blink::WebCryptoKey& key, 658 const blink::WebCryptoKey& key,
201 const blink::WebCryptoKey& wrapping_key, 659 const blink::WebCryptoKey& wrapping_key,
202 const blink::WebCryptoAlgorithm& wrap_algorithm, 660 const blink::WebCryptoAlgorithm& wrap_algorithm,
203 blink::WebCryptoResult result) { 661 blink::WebCryptoResult result) {
204 blink::WebArrayBuffer buffer; 662 scoped_ptr<WrapKeyState> state(
205 // TODO(eroman): Use the same parameter ordering. 663 new WrapKeyState(format, key, wrapping_key, wrap_algorithm, result));
206 Status status = webcrypto::WrapKey( 664 if (!CryptoThreadPool::PostTask(FROM_HERE,
207 format, wrapping_key, key, wrap_algorithm, &buffer); 665 base::Bind(DoWrapKey, Passed(&state)))) {
208 if (status.IsError()) 666 result.completeWithError(kFailedPostingToThreadPool);
209 CompleteWithError(status, &result); 667 }
210 else
211 result.completeWithBuffer(buffer);
212 } 668 }
213 669
214 void WebCryptoImpl::unwrapKey( 670 void WebCryptoImpl::unwrapKey(
215 blink::WebCryptoKeyFormat format, 671 blink::WebCryptoKeyFormat format,
216 const unsigned char* wrapped_key, 672 const unsigned char* wrapped_key,
217 unsigned wrapped_key_size, 673 unsigned wrapped_key_size,
218 const blink::WebCryptoKey& wrapping_key, 674 const blink::WebCryptoKey& wrapping_key,
219 const blink::WebCryptoAlgorithm& unwrap_algorithm, 675 const blink::WebCryptoAlgorithm& unwrap_algorithm,
220 const blink::WebCryptoAlgorithm& unwrapped_key_algorithm, 676 const blink::WebCryptoAlgorithm& unwrapped_key_algorithm,
221 bool extractable, 677 bool extractable,
222 blink::WebCryptoKeyUsageMask usages, 678 blink::WebCryptoKeyUsageMask usages,
223 blink::WebCryptoResult result) { 679 blink::WebCryptoResult result) {
224 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); 680 scoped_ptr<UnwrapKeyState> state(new UnwrapKeyState(format,
225 Status status = 681 wrapped_key,
226 webcrypto::UnwrapKey(format, 682 wrapped_key_size,
227 webcrypto::CryptoData(wrapped_key, wrapped_key_size), 683 wrapping_key,
228 wrapping_key, 684 unwrap_algorithm,
229 unwrap_algorithm, 685 unwrapped_key_algorithm,
230 unwrapped_key_algorithm, 686 extractable,
231 extractable, 687 usages,
232 usages, 688 result));
233 &key); 689 if (!CryptoThreadPool::PostTask(FROM_HERE,
234 if (status.IsError()) 690 base::Bind(DoUnwrapKey, Passed(&state)))) {
235 CompleteWithError(status, &result); 691 result.completeWithError(kFailedPostingToThreadPool);
236 else 692 }
237 result.completeWithKey(key);
238 }
239
240 bool WebCryptoImpl::digestSynchronous(
241 const blink::WebCryptoAlgorithmId algorithm_id,
242 const unsigned char* data,
243 unsigned int data_size,
244 blink::WebArrayBuffer& result) {
245 blink::WebCryptoAlgorithm algorithm =
246 blink::WebCryptoAlgorithm::adoptParamsAndCreate(algorithm_id, NULL);
247 return (webcrypto::Digest(
248 algorithm, webcrypto::CryptoData(data, data_size), &result))
249 .IsSuccess();
250 } 693 }
251 694
252 blink::WebCryptoDigestor* WebCryptoImpl::createDigestor( 695 blink::WebCryptoDigestor* WebCryptoImpl::createDigestor(
253 blink::WebCryptoAlgorithmId algorithm_id) { 696 blink::WebCryptoAlgorithmId algorithm_id) {
254 return webcrypto::CreateDigestor(algorithm_id).release(); 697 return webcrypto::CreateDigestor(algorithm_id).release();
255 } 698 }
256 699
257 bool WebCryptoImpl::deserializeKeyForClone( 700 bool WebCryptoImpl::deserializeKeyForClone(
258 const blink::WebCryptoKeyAlgorithm& algorithm, 701 const blink::WebCryptoKeyAlgorithm& algorithm,
259 blink::WebCryptoKeyType type, 702 blink::WebCryptoKeyType type,
260 bool extractable, 703 bool extractable,
261 blink::WebCryptoKeyUsageMask usages, 704 blink::WebCryptoKeyUsageMask usages,
262 const unsigned char* key_data, 705 const unsigned char* key_data,
263 unsigned key_data_size, 706 unsigned key_data_size,
264 blink::WebCryptoKey& key) { 707 blink::WebCryptoKey& key) {
265 Status status = webcrypto::DeserializeKeyForClone( 708 // TODO(eroman): Rather than do the import immediately on the current thread,
709 // it could defer to the crypto thread.
710 return webcrypto::DeserializeKeyForClone(
266 algorithm, 711 algorithm,
267 type, 712 type,
268 extractable, 713 extractable,
269 usages, 714 usages,
270 webcrypto::CryptoData(key_data, key_data_size), 715 webcrypto::CryptoData(key_data, key_data_size),
271 &key); 716 &key);
272 return status.IsSuccess();
273 } 717 }
274 718
275 bool WebCryptoImpl::serializeKeyForClone( 719 bool WebCryptoImpl::serializeKeyForClone(
276 const blink::WebCryptoKey& key, 720 const blink::WebCryptoKey& key,
277 blink::WebVector<unsigned char>& key_data) { 721 blink::WebVector<unsigned char>& key_data) {
278 Status status = webcrypto::SerializeKeyForClone(key, &key_data); 722 return webcrypto::SerializeKeyForClone(key, &key_data);
279 return status.IsSuccess();
280 } 723 }
281 724
282 } // namespace content 725 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698