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
27namespace content {
28
29using webcrypto::Status;
30
31namespace {
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.
76class CryptoThreadPool {
77 public:
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
92base::LazyInstance<CryptoThreadPool>::Leaky crypto_thread_pool =
93    LAZY_INSTANCE_INITIALIZER;
94
95bool 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
100void CompleteWithThreadPoolError(blink::WebCryptoResult* result) {
101  result->completeWithError(blink::WebCryptoErrorTypeOperation,
102                            "Failed posting to crypto worker pool");
103}
104
105void 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
112void 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
128void 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.
147scoped_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
170struct BaseState {
171  explicit BaseState(const blink::WebCryptoResult& result)
172      : origin_thread(GetCurrentBlinkThread()), result(result) {}
173
174  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.
186  ~BaseState() {}
187};
188
189struct EncryptState : public BaseState {
190  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
207typedef EncryptState DecryptState;
208typedef EncryptState DigestState;
209
210struct GenerateKeyState : public BaseState {
211  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
234struct ImportKeyState : public BaseState {
235  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
259struct ExportKeyState : public BaseState {
260  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
271typedef EncryptState SignState;
272
273struct VerifySignatureState : public BaseState {
274  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
296struct WrapKeyState : public BaseState {
297  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
316struct UnwrapKeyState : public BaseState {
317  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
354void DoEncryptReply(scoped_ptr<EncryptState> state) {
355  CompleteWithBufferOrError(state->status, state->buffer, &state->result);
356}
357
358void 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
370void DoDecryptReply(scoped_ptr<DecryptState> state) {
371  CompleteWithBufferOrError(state->status, state->buffer, &state->result);
372}
373
374void 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
386void DoDigestReply(scoped_ptr<DigestState> state) {
387  CompleteWithBufferOrError(state->status, state->buffer, &state->result);
388}
389
390void 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
400void 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
411void 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
450void DoImportKeyReply(scoped_ptr<ImportKeyState> state) {
451  CompleteWithKeyOrError(state->status, state->key, &state->result);
452}
453
454void 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
474void 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
489void 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
499void DoSignReply(scoped_ptr<SignState> state) {
500  CompleteWithBufferOrError(state->status, state->buffer, &state->result);
501}
502
503void 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
516void 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
524void 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
538void DoWrapKeyReply(scoped_ptr<WrapKeyState> state) {
539  CompleteWithBufferOrError(state->status, state->buffer, &state->result);
540}
541
542void 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
556void DoUnwrapKeyReply(scoped_ptr<UnwrapKeyState> state) {
557  CompleteWithKeyOrError(state->status, state->unwrapped_key, &state->result);
558}
559
560void 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
580WebCryptoImpl::WebCryptoImpl() {
581}
582
583WebCryptoImpl::~WebCryptoImpl() {
584}
585
586void 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
601void 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
616void 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
630void 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
644void 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
664void 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
674void 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
687void 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
702void 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
715void 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
740blink::WebCryptoDigestor* WebCryptoImpl::createDigestor(
741    blink::WebCryptoAlgorithmId algorithm_id) {
742  return webcrypto::CreateDigestor(algorithm_id).release();
743}
744
745bool 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
764bool 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