| // Copyright 2014 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "components/webcrypto/webcrypto_impl.h" | 
 |  | 
 | #include <limits.h> | 
 | #include <stdint.h> | 
 |  | 
 | #include <memory> | 
 |  | 
 | #include "base/bind.h" | 
 | #include "base/lazy_instance.h" | 
 | #include "base/location.h" | 
 | #include "base/logging.h" | 
 | #include "base/macros.h" | 
 | #include "base/single_thread_task_runner.h" | 
 | #include "base/task_runner.h" | 
 | #include "base/threading/thread.h" | 
 | #include "base/threading/thread_task_runner_handle.h" | 
 | #include "base/trace_event/trace_event.h" | 
 | #include "components/webcrypto/algorithm_dispatch.h" | 
 | #include "components/webcrypto/crypto_data.h" | 
 | #include "components/webcrypto/generate_key_result.h" | 
 | #include "components/webcrypto/status.h" | 
 | #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h" | 
 | #include "third_party/WebKit/public/platform/WebString.h" | 
 |  | 
 | namespace webcrypto { | 
 |  | 
 | using webcrypto::Status; | 
 |  | 
 | namespace { | 
 |  | 
 | // --------------------- | 
 | // Threading | 
 | // --------------------- | 
 | // | 
 | // WebCrypto operations can be slow. For instance generating an RSA key can | 
 | // take seconds. | 
 | // | 
 | // The strategy used here is to run a worker pool for all WebCrypto operations | 
 | // (except structured cloning). This same pool is also used by requests started | 
 | // from Blink Web Workers. | 
 | // | 
 | // A few notes to keep in mind: | 
 | // | 
 | // * PostTaskAndReply() is not used because of how it handles failures -- it | 
 | //   leaks the callback when failing to post back to the origin thread. | 
 | // | 
 | //   This is a problem since WebCrypto may be called from WebWorker threads, | 
 | //   which may be aborted at any time. Leaking would be undesirable, and | 
 | //   reachable in practice. | 
 | // | 
 | // * blink::WebArrayBuffer is NOT threadsafe, and should therefore be allocated | 
 | //   only on the target Blink thread. | 
 | // | 
 | //   TODO(eroman): Is there any way around this? Copying the result between | 
 | //                 threads is silly. | 
 | // | 
 | // * WebCryptoAlgorithm and WebCryptoKey are threadsafe, by virtue of being | 
 | //   immutable. Internally asymmetric WebCryptoKeys wrap BoringSSL's EVP_PKEY. | 
 | //   These are safe to use for BoringSSL operations across threads, provided | 
 | //   the internals of the EVP_PKEY are not mutated (they never should be | 
 | //   following ImportKey()). | 
 | // | 
 | // * blink::WebCryptoResult is not threadsafe and should only be operated on | 
 | //   the target Blink thread. HOWEVER, it is safe to delete it from any thread. | 
 | //   This can happen if by the time the operation has completed in the crypto | 
 | //   worker pool, the Blink worker thread that initiated the request is gone. | 
 | //   Posting back to the origin thread will fail, and the WebCryptoResult will | 
 | //   be deleted while running in the crypto worker pool. | 
 | class CryptoThreadPool { | 
 |  public: | 
 |   CryptoThreadPool() : worker_thread_("WebCrypto") { | 
 |     base::Thread::Options options; | 
 |     options.joinable = false; | 
 |     worker_thread_.StartWithOptions(options); | 
 |   } | 
 |  | 
 |   static bool PostTask(const base::Location& from_here, | 
 |                        const base::Closure& task); | 
 |  | 
 |  private: | 
 |   // TODO(gab): the pool is currently using a single non-joinable thread to | 
 |   // mimic the old behavior of using a CONTINUE_ON_SHUTDOWN SequencedTaskRunner | 
 |   // on a single-threaded SequencedWorkerPool, but we'd like to consider using | 
 |   // the TaskScheduler here and allowing multiple threads (SEQUENCED or even | 
 |   // PARALLEL ExecutionMode: http://crbug.com/623700). | 
 |   base::Thread worker_thread_; | 
 |  | 
 |   DISALLOW_COPY_AND_ASSIGN(CryptoThreadPool); | 
 | }; | 
 |  | 
 | base::LazyInstance<CryptoThreadPool>::Leaky crypto_thread_pool = | 
 |     LAZY_INSTANCE_INITIALIZER; | 
 |  | 
 | bool CryptoThreadPool::PostTask(const base::Location& from_here, | 
 |                                 const base::Closure& task) { | 
 |   return crypto_thread_pool.Get().worker_thread_.task_runner()->PostTask( | 
 |       from_here, task); | 
 | } | 
 |  | 
 | void CompleteWithThreadPoolError(blink::WebCryptoResult* result) { | 
 |   result->CompleteWithError(blink::kWebCryptoErrorTypeOperation, | 
 |                             "Failed posting to crypto worker pool"); | 
 | } | 
 |  | 
 | void CompleteWithError(const Status& status, blink::WebCryptoResult* result) { | 
 |   DCHECK(status.IsError()); | 
 |  | 
 |   result->CompleteWithError(status.error_type(), | 
 |                             blink::WebString::FromUTF8(status.error_details())); | 
 | } | 
 |  | 
 | void CompleteWithBufferOrError(const Status& status, | 
 |                                const std::vector<uint8_t>& buffer, | 
 |                                blink::WebCryptoResult* result) { | 
 |   if (status.IsError()) { | 
 |     CompleteWithError(status, result); | 
 |   } else { | 
 |     if (buffer.size() > UINT_MAX) { | 
 |       // WebArrayBuffers have a smaller range than std::vector<>, so | 
 |       // theoretically this could overflow. | 
 |       CompleteWithError(Status::ErrorUnexpected(), result); | 
 |     } else { | 
 |       result->CompleteWithBuffer(buffer.data(), | 
 |                                  static_cast<unsigned int>(buffer.size())); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void CompleteWithKeyOrError(const Status& status, | 
 |                             const blink::WebCryptoKey& key, | 
 |                             blink::WebCryptoResult* result) { | 
 |   if (status.IsError()) { | 
 |     CompleteWithError(status, result); | 
 |   } else { | 
 |     result->CompleteWithKey(key); | 
 |   } | 
 | } | 
 |  | 
 | // Gets a task runner for the current thread. | 
 | scoped_refptr<base::TaskRunner> GetCurrentBlinkThread() { | 
 |   DCHECK(base::ThreadTaskRunnerHandle::IsSet()); | 
 |   return base::ThreadTaskRunnerHandle::Get(); | 
 | } | 
 |  | 
 | // -------------------------------------------------------------------- | 
 | // State | 
 | // -------------------------------------------------------------------- | 
 | // | 
 | // Explicit state classes are used rather than base::Bind(). This is done | 
 | // both for clarity, but also to avoid extraneous allocations for things | 
 | // like passing buffers and result objects between threads. | 
 | // | 
 | // BaseState is the base class common to all of the async operations, and | 
 | // keeps track of the thread to complete on, the error state, and the | 
 | // callback into Blink. | 
 | // | 
 | // Ownership of the State object is passed between the crypto thread and the | 
 | // Blink thread. Under normal completion it is destroyed on the Blink thread. | 
 | // However it may also be destroyed on the crypto thread if the Blink thread | 
 | // has vanished (which can happen for Blink web worker threads). | 
 |  | 
 | struct BaseState { | 
 |   explicit BaseState(const blink::WebCryptoResult& result) | 
 |       : origin_thread(GetCurrentBlinkThread()), result(result) {} | 
 |  | 
 |   bool cancelled() { return result.Cancelled(); } | 
 |  | 
 |   scoped_refptr<base::TaskRunner> origin_thread; | 
 |  | 
 |   webcrypto::Status status; | 
 |   blink::WebCryptoResult result; | 
 |  | 
 |  protected: | 
 |   // Since there is no virtual destructor, must not delete directly as a | 
 |   // BaseState. | 
 |   ~BaseState() {} | 
 | }; | 
 |  | 
 | struct EncryptState : public BaseState { | 
 |   EncryptState(const blink::WebCryptoAlgorithm& algorithm, | 
 |                const blink::WebCryptoKey& key, | 
 |                blink::WebVector<unsigned char> data, | 
 |                const blink::WebCryptoResult& result) | 
 |       : BaseState(result), | 
 |         algorithm(algorithm), | 
 |         key(key), | 
 |         data(std::move(data)) {} | 
 |  | 
 |   const blink::WebCryptoAlgorithm algorithm; | 
 |   const blink::WebCryptoKey key; | 
 |   const blink::WebVector<unsigned char> data; | 
 |  | 
 |   std::vector<uint8_t> buffer; | 
 | }; | 
 |  | 
 | typedef EncryptState DecryptState; | 
 | typedef EncryptState DigestState; | 
 |  | 
 | struct GenerateKeyState : public BaseState { | 
 |   GenerateKeyState(const blink::WebCryptoAlgorithm& algorithm, | 
 |                    bool extractable, | 
 |                    blink::WebCryptoKeyUsageMask usages, | 
 |                    const blink::WebCryptoResult& result) | 
 |       : BaseState(result), | 
 |         algorithm(algorithm), | 
 |         extractable(extractable), | 
 |         usages(usages) {} | 
 |  | 
 |   const blink::WebCryptoAlgorithm algorithm; | 
 |   const bool extractable; | 
 |   const blink::WebCryptoKeyUsageMask usages; | 
 |  | 
 |   webcrypto::GenerateKeyResult generate_key_result; | 
 | }; | 
 |  | 
 | struct ImportKeyState : public BaseState { | 
 |   ImportKeyState(blink::WebCryptoKeyFormat format, | 
 |                  blink::WebVector<unsigned char> key_data, | 
 |                  const blink::WebCryptoAlgorithm& algorithm, | 
 |                  bool extractable, | 
 |                  blink::WebCryptoKeyUsageMask usages, | 
 |                  const blink::WebCryptoResult& result) | 
 |       : BaseState(result), | 
 |         format(format), | 
 |         key_data(std::move(key_data)), | 
 |         algorithm(algorithm), | 
 |         extractable(extractable), | 
 |         usages(usages) {} | 
 |  | 
 |   const blink::WebCryptoKeyFormat format; | 
 |   const blink::WebVector<unsigned char> key_data; | 
 |   const blink::WebCryptoAlgorithm algorithm; | 
 |   const bool extractable; | 
 |   const blink::WebCryptoKeyUsageMask usages; | 
 |  | 
 |   blink::WebCryptoKey key; | 
 | }; | 
 |  | 
 | struct ExportKeyState : public BaseState { | 
 |   ExportKeyState(blink::WebCryptoKeyFormat format, | 
 |                  const blink::WebCryptoKey& key, | 
 |                  const blink::WebCryptoResult& result) | 
 |       : BaseState(result), format(format), key(key) {} | 
 |  | 
 |   const blink::WebCryptoKeyFormat format; | 
 |   const blink::WebCryptoKey key; | 
 |  | 
 |   std::vector<uint8_t> buffer; | 
 | }; | 
 |  | 
 | typedef EncryptState SignState; | 
 |  | 
 | struct VerifySignatureState : public BaseState { | 
 |   VerifySignatureState(const blink::WebCryptoAlgorithm& algorithm, | 
 |                        const blink::WebCryptoKey& key, | 
 |                        blink::WebVector<unsigned char> signature, | 
 |                        blink::WebVector<unsigned char> data, | 
 |                        const blink::WebCryptoResult& result) | 
 |       : BaseState(result), | 
 |         algorithm(algorithm), | 
 |         key(key), | 
 |         signature(std::move(signature)), | 
 |         data(std::move(data)), | 
 |         verify_result(false) {} | 
 |  | 
 |   const blink::WebCryptoAlgorithm algorithm; | 
 |   const blink::WebCryptoKey key; | 
 |   blink::WebVector<unsigned char> signature; | 
 |   blink::WebVector<unsigned char> data; | 
 |  | 
 |   bool verify_result; | 
 | }; | 
 |  | 
 | struct WrapKeyState : public BaseState { | 
 |   WrapKeyState(blink::WebCryptoKeyFormat format, | 
 |                const blink::WebCryptoKey& key, | 
 |                const blink::WebCryptoKey& wrapping_key, | 
 |                const blink::WebCryptoAlgorithm& wrap_algorithm, | 
 |                const blink::WebCryptoResult& result) | 
 |       : BaseState(result), | 
 |         format(format), | 
 |         key(key), | 
 |         wrapping_key(wrapping_key), | 
 |         wrap_algorithm(wrap_algorithm) {} | 
 |  | 
 |   const blink::WebCryptoKeyFormat format; | 
 |   const blink::WebCryptoKey key; | 
 |   const blink::WebCryptoKey wrapping_key; | 
 |   const blink::WebCryptoAlgorithm wrap_algorithm; | 
 |  | 
 |   std::vector<uint8_t> buffer; | 
 | }; | 
 |  | 
 | struct UnwrapKeyState : public BaseState { | 
 |   UnwrapKeyState(blink::WebCryptoKeyFormat format, | 
 |                  blink::WebVector<unsigned char> wrapped_key, | 
 |                  const blink::WebCryptoKey& wrapping_key, | 
 |                  const blink::WebCryptoAlgorithm& unwrap_algorithm, | 
 |                  const blink::WebCryptoAlgorithm& unwrapped_key_algorithm, | 
 |                  bool extractable, | 
 |                  blink::WebCryptoKeyUsageMask usages, | 
 |                  const blink::WebCryptoResult& result) | 
 |       : BaseState(result), | 
 |         format(format), | 
 |         wrapped_key(std::move(wrapped_key)), | 
 |         wrapping_key(wrapping_key), | 
 |         unwrap_algorithm(unwrap_algorithm), | 
 |         unwrapped_key_algorithm(unwrapped_key_algorithm), | 
 |         extractable(extractable), | 
 |         usages(usages) {} | 
 |  | 
 |   const blink::WebCryptoKeyFormat format; | 
 |   blink::WebVector<unsigned char> wrapped_key; | 
 |   const blink::WebCryptoKey wrapping_key; | 
 |   const blink::WebCryptoAlgorithm unwrap_algorithm; | 
 |   const blink::WebCryptoAlgorithm unwrapped_key_algorithm; | 
 |   const bool extractable; | 
 |   const blink::WebCryptoKeyUsageMask usages; | 
 |  | 
 |   blink::WebCryptoKey unwrapped_key; | 
 | }; | 
 |  | 
 | struct DeriveBitsState : public BaseState { | 
 |   DeriveBitsState(const blink::WebCryptoAlgorithm& algorithm, | 
 |                   const blink::WebCryptoKey& base_key, | 
 |                   unsigned int length_bits, | 
 |                   const blink::WebCryptoResult& result) | 
 |       : BaseState(result), | 
 |         algorithm(algorithm), | 
 |         base_key(base_key), | 
 |         length_bits(length_bits) {} | 
 |  | 
 |   const blink::WebCryptoAlgorithm algorithm; | 
 |   const blink::WebCryptoKey base_key; | 
 |   const unsigned int length_bits; | 
 |  | 
 |   std::vector<uint8_t> derived_bytes; | 
 | }; | 
 |  | 
 | struct DeriveKeyState : public BaseState { | 
 |   DeriveKeyState(const blink::WebCryptoAlgorithm& algorithm, | 
 |                  const blink::WebCryptoKey& base_key, | 
 |                  const blink::WebCryptoAlgorithm& import_algorithm, | 
 |                  const blink::WebCryptoAlgorithm& key_length_algorithm, | 
 |                  bool extractable, | 
 |                  blink::WebCryptoKeyUsageMask usages, | 
 |                  const blink::WebCryptoResult& result) | 
 |       : BaseState(result), | 
 |         algorithm(algorithm), | 
 |         base_key(base_key), | 
 |         import_algorithm(import_algorithm), | 
 |         key_length_algorithm(key_length_algorithm), | 
 |         extractable(extractable), | 
 |         usages(usages) {} | 
 |  | 
 |   const blink::WebCryptoAlgorithm algorithm; | 
 |   const blink::WebCryptoKey base_key; | 
 |   const blink::WebCryptoAlgorithm import_algorithm; | 
 |   const blink::WebCryptoAlgorithm key_length_algorithm; | 
 |   bool extractable; | 
 |   blink::WebCryptoKeyUsageMask usages; | 
 |  | 
 |   blink::WebCryptoKey derived_key; | 
 | }; | 
 |  | 
 | // -------------------------------------------------------------------- | 
 | // Wrapper functions | 
 | // -------------------------------------------------------------------- | 
 | // | 
 | // * The methods named Do*() run on the crypto thread. | 
 | // * The methods named Do*Reply() run on the target Blink thread | 
 |  | 
 | void DoEncryptReply(std::unique_ptr<EncryptState> state) { | 
 |   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), | 
 |                "DoEncryptReply"); | 
 |   CompleteWithBufferOrError(state->status, state->buffer, &state->result); | 
 | } | 
 |  | 
 | void DoEncrypt(std::unique_ptr<EncryptState> passed_state) { | 
 |   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "DoEncrypt"); | 
 |   EncryptState* state = passed_state.get(); | 
 |   if (state->cancelled()) | 
 |     return; | 
 |   state->status = | 
 |       webcrypto::Encrypt(state->algorithm, state->key, | 
 |                          webcrypto::CryptoData(state->data), &state->buffer); | 
 |   state->origin_thread->PostTask( | 
 |       FROM_HERE, base::Bind(DoEncryptReply, base::Passed(&passed_state))); | 
 | } | 
 |  | 
 | void DoDecryptReply(std::unique_ptr<DecryptState> state) { | 
 |   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), | 
 |                "DoDecryptReply"); | 
 |   CompleteWithBufferOrError(state->status, state->buffer, &state->result); | 
 | } | 
 |  | 
 | void DoDecrypt(std::unique_ptr<DecryptState> passed_state) { | 
 |   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "DoDecrypt"); | 
 |   DecryptState* state = passed_state.get(); | 
 |   if (state->cancelled()) | 
 |     return; | 
 |   state->status = | 
 |       webcrypto::Decrypt(state->algorithm, state->key, | 
 |                          webcrypto::CryptoData(state->data), &state->buffer); | 
 |   state->origin_thread->PostTask( | 
 |       FROM_HERE, base::Bind(DoDecryptReply, base::Passed(&passed_state))); | 
 | } | 
 |  | 
 | void DoDigestReply(std::unique_ptr<DigestState> state) { | 
 |   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "DoDigestReply"); | 
 |   CompleteWithBufferOrError(state->status, state->buffer, &state->result); | 
 | } | 
 |  | 
 | void DoDigest(std::unique_ptr<DigestState> passed_state) { | 
 |   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "DoDigest"); | 
 |   DigestState* state = passed_state.get(); | 
 |   if (state->cancelled()) | 
 |     return; | 
 |   state->status = webcrypto::Digest( | 
 |       state->algorithm, webcrypto::CryptoData(state->data), &state->buffer); | 
 |   state->origin_thread->PostTask( | 
 |       FROM_HERE, base::Bind(DoDigestReply, base::Passed(&passed_state))); | 
 | } | 
 |  | 
 | void DoGenerateKeyReply(std::unique_ptr<GenerateKeyState> state) { | 
 |   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), | 
 |                "DoGenerateKeyReply"); | 
 |   if (state->status.IsError()) { | 
 |     CompleteWithError(state->status, &state->result); | 
 |   } else { | 
 |     state->generate_key_result.Complete(&state->result); | 
 |   } | 
 | } | 
 |  | 
 | void DoGenerateKey(std::unique_ptr<GenerateKeyState> passed_state) { | 
 |   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "DoGenerateKey"); | 
 |   GenerateKeyState* state = passed_state.get(); | 
 |   if (state->cancelled()) | 
 |     return; | 
 |   state->status = | 
 |       webcrypto::GenerateKey(state->algorithm, state->extractable, | 
 |                              state->usages, &state->generate_key_result); | 
 |   state->origin_thread->PostTask( | 
 |       FROM_HERE, base::Bind(DoGenerateKeyReply, base::Passed(&passed_state))); | 
 | } | 
 |  | 
 | void DoImportKeyReply(std::unique_ptr<ImportKeyState> state) { | 
 |   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), | 
 |                "DoImportKeyReply"); | 
 |   CompleteWithKeyOrError(state->status, state->key, &state->result); | 
 | } | 
 |  | 
 | void DoImportKey(std::unique_ptr<ImportKeyState> passed_state) { | 
 |   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "DoImportKey"); | 
 |   ImportKeyState* state = passed_state.get(); | 
 |   if (state->cancelled()) | 
 |     return; | 
 |   state->status = webcrypto::ImportKey( | 
 |       state->format, webcrypto::CryptoData(state->key_data), state->algorithm, | 
 |       state->extractable, state->usages, &state->key); | 
 |   if (state->status.IsSuccess()) { | 
 |     DCHECK(state->key.Handle()); | 
 |     DCHECK(!state->key.Algorithm().IsNull()); | 
 |     DCHECK_EQ(state->extractable, state->key.Extractable()); | 
 |   } | 
 |  | 
 |   state->origin_thread->PostTask( | 
 |       FROM_HERE, base::Bind(DoImportKeyReply, base::Passed(&passed_state))); | 
 | } | 
 |  | 
 | void DoExportKeyReply(std::unique_ptr<ExportKeyState> state) { | 
 |   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), | 
 |                "DoExportKeyReply"); | 
 |   if (state->format != blink::kWebCryptoKeyFormatJwk) { | 
 |     CompleteWithBufferOrError(state->status, state->buffer, &state->result); | 
 |     return; | 
 |   } | 
 |  | 
 |   if (state->status.IsError()) { | 
 |     CompleteWithError(state->status, &state->result); | 
 |   } else { | 
 |     state->result.CompleteWithJson( | 
 |         reinterpret_cast<const char*>(state->buffer.data()), | 
 |         static_cast<unsigned int>(state->buffer.size())); | 
 |   } | 
 | } | 
 |  | 
 | void DoExportKey(std::unique_ptr<ExportKeyState> passed_state) { | 
 |   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "DoExportKey"); | 
 |   ExportKeyState* state = passed_state.get(); | 
 |   if (state->cancelled()) | 
 |     return; | 
 |   state->status = | 
 |       webcrypto::ExportKey(state->format, state->key, &state->buffer); | 
 |   state->origin_thread->PostTask( | 
 |       FROM_HERE, base::Bind(DoExportKeyReply, base::Passed(&passed_state))); | 
 | } | 
 |  | 
 | void DoSignReply(std::unique_ptr<SignState> state) { | 
 |   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "DoSignReply"); | 
 |   CompleteWithBufferOrError(state->status, state->buffer, &state->result); | 
 | } | 
 |  | 
 | void DoSign(std::unique_ptr<SignState> passed_state) { | 
 |   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "DoSign"); | 
 |   SignState* state = passed_state.get(); | 
 |   if (state->cancelled()) | 
 |     return; | 
 |   state->status = | 
 |       webcrypto::Sign(state->algorithm, state->key, | 
 |                       webcrypto::CryptoData(state->data), &state->buffer); | 
 |  | 
 |   state->origin_thread->PostTask( | 
 |       FROM_HERE, base::Bind(DoSignReply, base::Passed(&passed_state))); | 
 | } | 
 |  | 
 | void DoVerifyReply(std::unique_ptr<VerifySignatureState> state) { | 
 |   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "DoVerifyReply"); | 
 |   if (state->status.IsError()) { | 
 |     CompleteWithError(state->status, &state->result); | 
 |   } else { | 
 |     state->result.CompleteWithBoolean(state->verify_result); | 
 |   } | 
 | } | 
 |  | 
 | void DoVerify(std::unique_ptr<VerifySignatureState> passed_state) { | 
 |   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "DoVerify"); | 
 |   VerifySignatureState* state = passed_state.get(); | 
 |   if (state->cancelled()) | 
 |     return; | 
 |   state->status = webcrypto::Verify( | 
 |       state->algorithm, state->key, webcrypto::CryptoData(state->signature), | 
 |       webcrypto::CryptoData(state->data), &state->verify_result); | 
 |  | 
 |   state->origin_thread->PostTask( | 
 |       FROM_HERE, base::Bind(DoVerifyReply, base::Passed(&passed_state))); | 
 | } | 
 |  | 
 | void DoWrapKeyReply(std::unique_ptr<WrapKeyState> state) { | 
 |   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), | 
 |                "DoWrapKeyReply"); | 
 |   CompleteWithBufferOrError(state->status, state->buffer, &state->result); | 
 | } | 
 |  | 
 | void DoWrapKey(std::unique_ptr<WrapKeyState> passed_state) { | 
 |   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "DoWrapKey"); | 
 |   WrapKeyState* state = passed_state.get(); | 
 |   if (state->cancelled()) | 
 |     return; | 
 |   state->status = | 
 |       webcrypto::WrapKey(state->format, state->key, state->wrapping_key, | 
 |                          state->wrap_algorithm, &state->buffer); | 
 |  | 
 |   state->origin_thread->PostTask( | 
 |       FROM_HERE, base::Bind(DoWrapKeyReply, base::Passed(&passed_state))); | 
 | } | 
 |  | 
 | void DoUnwrapKeyReply(std::unique_ptr<UnwrapKeyState> state) { | 
 |   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), | 
 |                "DoUnwrapKeyReply"); | 
 |   CompleteWithKeyOrError(state->status, state->unwrapped_key, &state->result); | 
 | } | 
 |  | 
 | void DoUnwrapKey(std::unique_ptr<UnwrapKeyState> passed_state) { | 
 |   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "DoUnwrapKey"); | 
 |   UnwrapKeyState* state = passed_state.get(); | 
 |   if (state->cancelled()) | 
 |     return; | 
 |   state->status = webcrypto::UnwrapKey( | 
 |       state->format, webcrypto::CryptoData(state->wrapped_key), | 
 |       state->wrapping_key, state->unwrap_algorithm, | 
 |       state->unwrapped_key_algorithm, state->extractable, state->usages, | 
 |       &state->unwrapped_key); | 
 |  | 
 |   state->origin_thread->PostTask( | 
 |       FROM_HERE, base::Bind(DoUnwrapKeyReply, base::Passed(&passed_state))); | 
 | } | 
 |  | 
 | void DoDeriveBitsReply(std::unique_ptr<DeriveBitsState> state) { | 
 |   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), | 
 |                "DoDeriveBitsReply"); | 
 |   CompleteWithBufferOrError(state->status, state->derived_bytes, | 
 |                             &state->result); | 
 | } | 
 |  | 
 | void DoDeriveBits(std::unique_ptr<DeriveBitsState> passed_state) { | 
 |   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "DoDeriveBits"); | 
 |   DeriveBitsState* state = passed_state.get(); | 
 |   if (state->cancelled()) | 
 |     return; | 
 |   state->status = | 
 |       webcrypto::DeriveBits(state->algorithm, state->base_key, | 
 |                             state->length_bits, &state->derived_bytes); | 
 |   state->origin_thread->PostTask( | 
 |       FROM_HERE, base::Bind(DoDeriveBitsReply, base::Passed(&passed_state))); | 
 | } | 
 |  | 
 | void DoDeriveKeyReply(std::unique_ptr<DeriveKeyState> state) { | 
 |   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), | 
 |                "DoDeriveKeyReply"); | 
 |   CompleteWithKeyOrError(state->status, state->derived_key, &state->result); | 
 | } | 
 |  | 
 | void DoDeriveKey(std::unique_ptr<DeriveKeyState> passed_state) { | 
 |   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "DoDeriveKey"); | 
 |   DeriveKeyState* state = passed_state.get(); | 
 |   if (state->cancelled()) | 
 |     return; | 
 |   state->status = webcrypto::DeriveKey( | 
 |       state->algorithm, state->base_key, state->import_algorithm, | 
 |       state->key_length_algorithm, state->extractable, state->usages, | 
 |       &state->derived_key); | 
 |   state->origin_thread->PostTask( | 
 |       FROM_HERE, base::Bind(DoDeriveKeyReply, base::Passed(&passed_state))); | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | WebCryptoImpl::WebCryptoImpl() { | 
 | } | 
 |  | 
 | WebCryptoImpl::~WebCryptoImpl() { | 
 | } | 
 |  | 
 | void WebCryptoImpl::Encrypt(const blink::WebCryptoAlgorithm& algorithm, | 
 |                             const blink::WebCryptoKey& key, | 
 |                             blink::WebVector<unsigned char> data, | 
 |                             blink::WebCryptoResult result) { | 
 |   DCHECK(!algorithm.IsNull()); | 
 |  | 
 |   std::unique_ptr<EncryptState> state( | 
 |       new EncryptState(algorithm, key, std::move(data), result)); | 
 |   if (!CryptoThreadPool::PostTask( | 
 |           FROM_HERE, base::Bind(DoEncrypt, base::Passed(&state)))) { | 
 |     CompleteWithThreadPoolError(&result); | 
 |   } | 
 | } | 
 |  | 
 | void WebCryptoImpl::Decrypt(const blink::WebCryptoAlgorithm& algorithm, | 
 |                             const blink::WebCryptoKey& key, | 
 |                             blink::WebVector<unsigned char> data, | 
 |                             blink::WebCryptoResult result) { | 
 |   DCHECK(!algorithm.IsNull()); | 
 |  | 
 |   std::unique_ptr<DecryptState> state( | 
 |       new DecryptState(algorithm, key, std::move(data), result)); | 
 |   if (!CryptoThreadPool::PostTask( | 
 |           FROM_HERE, base::Bind(DoDecrypt, base::Passed(&state)))) { | 
 |     CompleteWithThreadPoolError(&result); | 
 |   } | 
 | } | 
 |  | 
 | void WebCryptoImpl::Digest(const blink::WebCryptoAlgorithm& algorithm, | 
 |                            blink::WebVector<unsigned char> data, | 
 |                            blink::WebCryptoResult result) { | 
 |   DCHECK(!algorithm.IsNull()); | 
 |  | 
 |   std::unique_ptr<DigestState> state(new DigestState( | 
 |       algorithm, blink::WebCryptoKey::CreateNull(), std::move(data), result)); | 
 |   if (!CryptoThreadPool::PostTask(FROM_HERE, | 
 |                                   base::Bind(DoDigest, base::Passed(&state)))) { | 
 |     CompleteWithThreadPoolError(&result); | 
 |   } | 
 | } | 
 |  | 
 | void WebCryptoImpl::GenerateKey(const blink::WebCryptoAlgorithm& algorithm, | 
 |                                 bool extractable, | 
 |                                 blink::WebCryptoKeyUsageMask usages, | 
 |                                 blink::WebCryptoResult result) { | 
 |   DCHECK(!algorithm.IsNull()); | 
 |  | 
 |   std::unique_ptr<GenerateKeyState> state( | 
 |       new GenerateKeyState(algorithm, extractable, usages, result)); | 
 |   if (!CryptoThreadPool::PostTask( | 
 |           FROM_HERE, base::Bind(DoGenerateKey, base::Passed(&state)))) { | 
 |     CompleteWithThreadPoolError(&result); | 
 |   } | 
 | } | 
 |  | 
 | void WebCryptoImpl::ImportKey(blink::WebCryptoKeyFormat format, | 
 |                               blink::WebVector<unsigned char> key_data, | 
 |                               const blink::WebCryptoAlgorithm& algorithm, | 
 |                               bool extractable, | 
 |                               blink::WebCryptoKeyUsageMask usages, | 
 |                               blink::WebCryptoResult result) { | 
 |   std::unique_ptr<ImportKeyState> state(new ImportKeyState( | 
 |       format, std::move(key_data), algorithm, extractable, usages, result)); | 
 |   if (!CryptoThreadPool::PostTask( | 
 |           FROM_HERE, base::Bind(DoImportKey, base::Passed(&state)))) { | 
 |     CompleteWithThreadPoolError(&result); | 
 |   } | 
 | } | 
 |  | 
 | void WebCryptoImpl::ExportKey(blink::WebCryptoKeyFormat format, | 
 |                               const blink::WebCryptoKey& key, | 
 |                               blink::WebCryptoResult result) { | 
 |   std::unique_ptr<ExportKeyState> state( | 
 |       new ExportKeyState(format, key, result)); | 
 |   if (!CryptoThreadPool::PostTask( | 
 |           FROM_HERE, base::Bind(DoExportKey, base::Passed(&state)))) { | 
 |     CompleteWithThreadPoolError(&result); | 
 |   } | 
 | } | 
 |  | 
 | void WebCryptoImpl::Sign(const blink::WebCryptoAlgorithm& algorithm, | 
 |                          const blink::WebCryptoKey& key, | 
 |                          blink::WebVector<unsigned char> data, | 
 |                          blink::WebCryptoResult result) { | 
 |   std::unique_ptr<SignState> state( | 
 |       new SignState(algorithm, key, std::move(data), result)); | 
 |   if (!CryptoThreadPool::PostTask(FROM_HERE, | 
 |                                   base::Bind(DoSign, base::Passed(&state)))) { | 
 |     CompleteWithThreadPoolError(&result); | 
 |   } | 
 | } | 
 |  | 
 | void WebCryptoImpl::VerifySignature(const blink::WebCryptoAlgorithm& algorithm, | 
 |                                     const blink::WebCryptoKey& key, | 
 |                                     blink::WebVector<unsigned char> signature, | 
 |                                     blink::WebVector<unsigned char> data, | 
 |                                     blink::WebCryptoResult result) { | 
 |   std::unique_ptr<VerifySignatureState> state(new VerifySignatureState( | 
 |       algorithm, key, std::move(signature), std::move(data), result)); | 
 |   if (!CryptoThreadPool::PostTask(FROM_HERE, | 
 |                                   base::Bind(DoVerify, base::Passed(&state)))) { | 
 |     CompleteWithThreadPoolError(&result); | 
 |   } | 
 | } | 
 |  | 
 | void WebCryptoImpl::WrapKey(blink::WebCryptoKeyFormat format, | 
 |                             const blink::WebCryptoKey& key, | 
 |                             const blink::WebCryptoKey& wrapping_key, | 
 |                             const blink::WebCryptoAlgorithm& wrap_algorithm, | 
 |                             blink::WebCryptoResult result) { | 
 |   std::unique_ptr<WrapKeyState> state( | 
 |       new WrapKeyState(format, key, wrapping_key, wrap_algorithm, result)); | 
 |   if (!CryptoThreadPool::PostTask( | 
 |           FROM_HERE, base::Bind(DoWrapKey, base::Passed(&state)))) { | 
 |     CompleteWithThreadPoolError(&result); | 
 |   } | 
 | } | 
 |  | 
 | void WebCryptoImpl::UnwrapKey( | 
 |     blink::WebCryptoKeyFormat format, | 
 |     blink::WebVector<unsigned char> wrapped_key, | 
 |     const blink::WebCryptoKey& wrapping_key, | 
 |     const blink::WebCryptoAlgorithm& unwrap_algorithm, | 
 |     const blink::WebCryptoAlgorithm& unwrapped_key_algorithm, | 
 |     bool extractable, | 
 |     blink::WebCryptoKeyUsageMask usages, | 
 |     blink::WebCryptoResult result) { | 
 |   std::unique_ptr<UnwrapKeyState> state(new UnwrapKeyState( | 
 |       format, std::move(wrapped_key), wrapping_key, unwrap_algorithm, | 
 |       unwrapped_key_algorithm, extractable, usages, result)); | 
 |   if (!CryptoThreadPool::PostTask( | 
 |           FROM_HERE, base::Bind(DoUnwrapKey, base::Passed(&state)))) { | 
 |     CompleteWithThreadPoolError(&result); | 
 |   } | 
 | } | 
 |  | 
 | void WebCryptoImpl::DeriveBits(const blink::WebCryptoAlgorithm& algorithm, | 
 |                                const blink::WebCryptoKey& base_key, | 
 |                                unsigned int length_bits, | 
 |                                blink::WebCryptoResult result) { | 
 |   std::unique_ptr<DeriveBitsState> state( | 
 |       new DeriveBitsState(algorithm, base_key, length_bits, result)); | 
 |   if (!CryptoThreadPool::PostTask( | 
 |           FROM_HERE, base::Bind(DoDeriveBits, base::Passed(&state)))) { | 
 |     CompleteWithThreadPoolError(&result); | 
 |   } | 
 | } | 
 |  | 
 | void WebCryptoImpl::DeriveKey( | 
 |     const blink::WebCryptoAlgorithm& algorithm, | 
 |     const blink::WebCryptoKey& base_key, | 
 |     const blink::WebCryptoAlgorithm& import_algorithm, | 
 |     const blink::WebCryptoAlgorithm& key_length_algorithm, | 
 |     bool extractable, | 
 |     blink::WebCryptoKeyUsageMask usages, | 
 |     blink::WebCryptoResult result) { | 
 |   std::unique_ptr<DeriveKeyState> state( | 
 |       new DeriveKeyState(algorithm, base_key, import_algorithm, | 
 |                          key_length_algorithm, extractable, usages, result)); | 
 |   if (!CryptoThreadPool::PostTask( | 
 |           FROM_HERE, base::Bind(DoDeriveKey, base::Passed(&state)))) { | 
 |     CompleteWithThreadPoolError(&result); | 
 |   } | 
 | } | 
 |  | 
 | std::unique_ptr<blink::WebCryptoDigestor> WebCryptoImpl::CreateDigestor( | 
 |     blink::WebCryptoAlgorithmId algorithm_id) { | 
 |   return webcrypto::CreateDigestor(algorithm_id); | 
 | } | 
 |  | 
 | bool WebCryptoImpl::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) { | 
 |   return webcrypto::DeserializeKeyForClone( | 
 |       algorithm, type, extractable, usages, | 
 |       webcrypto::CryptoData(key_data, key_data_size), &key); | 
 | } | 
 |  | 
 | bool WebCryptoImpl::SerializeKeyForClone( | 
 |     const blink::WebCryptoKey& key, | 
 |     blink::WebVector<unsigned char>& key_data) { | 
 |   return webcrypto::SerializeKeyForClone(key, &key_data); | 
 | } | 
 |  | 
 | }  // namespace webcrypto |