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