| // 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 "content/child/webcrypto/webcrypto_impl.h" |
| |
| #include "base/bind.h" |
| #include "base/lazy_instance.h" |
| #include "base/location.h" |
| #include "base/logging.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/single_thread_task_runner.h" |
| #include "base/stl_util.h" |
| #include "base/task_runner.h" |
| #include "base/thread_task_runner_handle.h" |
| #include "base/threading/sequenced_worker_pool.h" |
| #include "base/threading/worker_pool.h" |
| #include "content/child/webcrypto/algorithm_dispatch.h" |
| #include "content/child/webcrypto/crypto_data.h" |
| #include "content/child/webcrypto/generate_key_result.h" |
| #include "content/child/webcrypto/status.h" |
| #include "content/child/webcrypto/structured_clone.h" |
| #include "content/child/webcrypto/webcrypto_util.h" |
| #include "content/child/worker_thread_task_runner.h" |
| #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h" |
| #include "third_party/WebKit/public/platform/WebString.h" |
| |
| namespace content { |
| |
| using webcrypto::Status; |
| |
| namespace { |
| |
| // --------------------- |
| // Threading |
| // --------------------- |
| // |
| // WebCrypto operations can be slow. For instance generating an RSA key can |
| // take hundreds of milliseconds to several seconds. |
| // |
| // Moreover the underlying crypto libraries are not threadsafe when operating |
| // on the same key. |
| // |
| // The strategy used here is to run a sequenced worker pool for all WebCrypto |
| // operations. This pool (of 1 threads) is also used by requests started from |
| // Blink Web Workers. |
| // |
| // A few notes to keep in mind: |
| // |
| // * PostTaskAndReply() cannot be used for two reasons: |
| // |
| // (1) Blink web worker threads do not have an associated message loop so |
| // construction of the reply callback will crash. |
| // |
| // (2) PostTaskAndReply() handles failure posting the reply by leaking the |
| // callback, rather than destroying it. In the case of Web Workers this |
| // condition is reachable via normal execution, since Web Workers can |
| // be stopped before the WebCrypto operation has finished. A policy of |
| // leaking would therefore be problematic. |
| // |
| // * blink::WebArrayBuffer is NOT threadsafe, and should therefore be allocated |
| // 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 (however the key's |
| // handle(), which wraps an NSS/OpenSSL type, may not be and should only be |
| // used from the webcrypto thread). |
| // |
| // * 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_pool_(new base::SequencedWorkerPool(1, "WebCrypto")), |
| task_runner_(worker_pool_->GetSequencedTaskRunnerWithShutdownBehavior( |
| worker_pool_->GetSequenceToken(), |
| base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN)) {} |
| |
| static bool PostTask(const tracked_objects::Location& from_here, |
| const base::Closure& task); |
| |
| private: |
| scoped_refptr<base::SequencedWorkerPool> worker_pool_; |
| scoped_refptr<base::SequencedTaskRunner> task_runner_; |
| }; |
| |
| base::LazyInstance<CryptoThreadPool>::Leaky crypto_thread_pool = |
| LAZY_INSTANCE_INITIALIZER; |
| |
| bool CryptoThreadPool::PostTask(const tracked_objects::Location& from_here, |
| const base::Closure& task) { |
| return crypto_thread_pool.Get().task_runner_->PostTask(from_here, task); |
| } |
| |
| void CompleteWithThreadPoolError(blink::WebCryptoResult* result) { |
| result->completeWithError(blink::WebCryptoErrorTypeOperation, |
| "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(vector_as_array(&buffer), 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. The current thread is either: |
| // |
| // * The main Blink thread |
| // * A Blink web worker thread |
| // |
| // A different mechanism is needed for posting to these threads. The main |
| // thread has an associated message loop and can simply use |
| // base::ThreadTaskRunnerHandle. Whereas the web worker threads are managed by |
| // Blink and need to be indirected through WorkerThreadTaskRunner. |
| scoped_refptr<base::TaskRunner> GetCurrentBlinkThread() { |
| if (base::ThreadTaskRunnerHandle::IsSet()) |
| return base::ThreadTaskRunnerHandle::Get(); |
| return WorkerThreadTaskRunner::current(); |
| } |
| |
| // -------------------------------------------------------------------- |
| // 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, |
| const unsigned char* data, |
| unsigned int data_size, |
| const blink::WebCryptoResult& result) |
| : BaseState(result), |
| algorithm(algorithm), |
| key(key), |
| data(data, data + data_size) {} |
| |
| const blink::WebCryptoAlgorithm algorithm; |
| const blink::WebCryptoKey key; |
| const std::vector<uint8_t> 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, |
| const unsigned char* key_data, |
| unsigned int key_data_size, |
| const blink::WebCryptoAlgorithm& algorithm, |
| bool extractable, |
| blink::WebCryptoKeyUsageMask usages, |
| const blink::WebCryptoResult& result) |
| : BaseState(result), |
| format(format), |
| key_data(key_data, key_data + key_data_size), |
| algorithm(algorithm), |
| extractable(extractable), |
| usages(usages) {} |
| |
| const blink::WebCryptoKeyFormat format; |
| const std::vector<uint8_t> 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, |
| const unsigned char* signature, |
| unsigned int signature_size, |
| const unsigned char* data, |
| unsigned int data_size, |
| const blink::WebCryptoResult& result) |
| : BaseState(result), |
| algorithm(algorithm), |
| key(key), |
| signature(signature, signature + signature_size), |
| data(data, data + data_size), |
| verify_result(false) {} |
| |
| const blink::WebCryptoAlgorithm algorithm; |
| const blink::WebCryptoKey key; |
| const std::vector<uint8_t> signature; |
| const std::vector<uint8_t> 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, |
| 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, |
| const blink::WebCryptoResult& result) |
| : BaseState(result), |
| format(format), |
| wrapped_key(wrapped_key, wrapped_key + wrapped_key_size), |
| wrapping_key(wrapping_key), |
| unwrap_algorithm(unwrap_algorithm), |
| unwrapped_key_algorithm(unwrapped_key_algorithm), |
| extractable(extractable), |
| usages(usages) {} |
| |
| const blink::WebCryptoKeyFormat format; |
| const std::vector<uint8_t> 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; |
| }; |
| |
| // -------------------------------------------------------------------- |
| // Wrapper functions |
| // -------------------------------------------------------------------- |
| // |
| // * The methods named Do*() run on the crypto thread. |
| // * The methods named Do*Reply() run on the target Blink thread |
| |
| void DoEncryptReply(scoped_ptr<EncryptState> state) { |
| CompleteWithBufferOrError(state->status, state->buffer, &state->result); |
| } |
| |
| void DoEncrypt(scoped_ptr<EncryptState> passed_state) { |
| 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, Passed(&passed_state))); |
| } |
| |
| void DoDecryptReply(scoped_ptr<DecryptState> state) { |
| CompleteWithBufferOrError(state->status, state->buffer, &state->result); |
| } |
| |
| void DoDecrypt(scoped_ptr<DecryptState> passed_state) { |
| 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, Passed(&passed_state))); |
| } |
| |
| void DoDigestReply(scoped_ptr<DigestState> state) { |
| CompleteWithBufferOrError(state->status, state->buffer, &state->result); |
| } |
| |
| void DoDigest(scoped_ptr<DigestState> passed_state) { |
| 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, Passed(&passed_state))); |
| } |
| |
| void DoGenerateKeyReply(scoped_ptr<GenerateKeyState> state) { |
| if (state->status.IsError()) { |
| CompleteWithError(state->status, &state->result); |
| } else { |
| state->generate_key_result.Complete(&state->result); |
| } |
| } |
| |
| void DoGenerateKey(scoped_ptr<GenerateKeyState> passed_state) { |
| 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, Passed(&passed_state))); |
| } |
| |
| void DoImportKeyReply(scoped_ptr<ImportKeyState> state) { |
| CompleteWithKeyOrError(state->status, state->key, &state->result); |
| } |
| |
| void DoImportKey(scoped_ptr<ImportKeyState> passed_state) { |
| 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, Passed(&passed_state))); |
| } |
| |
| void DoExportKeyReply(scoped_ptr<ExportKeyState> state) { |
| if (state->format != blink::WebCryptoKeyFormatJwk) { |
| 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*>(vector_as_array(&state->buffer)), |
| state->buffer.size()); |
| } |
| } |
| |
| void DoExportKey(scoped_ptr<ExportKeyState> passed_state) { |
| 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, Passed(&passed_state))); |
| } |
| |
| void DoSignReply(scoped_ptr<SignState> state) { |
| CompleteWithBufferOrError(state->status, state->buffer, &state->result); |
| } |
| |
| void DoSign(scoped_ptr<SignState> passed_state) { |
| 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, Passed(&passed_state))); |
| } |
| |
| void DoVerifyReply(scoped_ptr<VerifySignatureState> state) { |
| if (state->status.IsError()) { |
| CompleteWithError(state->status, &state->result); |
| } else { |
| state->result.completeWithBoolean(state->verify_result); |
| } |
| } |
| |
| void DoVerify(scoped_ptr<VerifySignatureState> passed_state) { |
| 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, Passed(&passed_state))); |
| } |
| |
| void DoWrapKeyReply(scoped_ptr<WrapKeyState> state) { |
| CompleteWithBufferOrError(state->status, state->buffer, &state->result); |
| } |
| |
| void DoWrapKey(scoped_ptr<WrapKeyState> passed_state) { |
| 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, Passed(&passed_state))); |
| } |
| |
| void DoUnwrapKeyReply(scoped_ptr<UnwrapKeyState> state) { |
| CompleteWithKeyOrError(state->status, state->unwrapped_key, &state->result); |
| } |
| |
| void DoUnwrapKey(scoped_ptr<UnwrapKeyState> passed_state) { |
| 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, Passed(&passed_state))); |
| } |
| |
| } // namespace |
| |
| WebCryptoImpl::WebCryptoImpl() { |
| } |
| |
| WebCryptoImpl::~WebCryptoImpl() { |
| } |
| |
| void WebCryptoImpl::encrypt(const blink::WebCryptoAlgorithm& algorithm, |
| const blink::WebCryptoKey& key, |
| const unsigned char* data, |
| unsigned int data_size, |
| blink::WebCryptoResult result) { |
| DCHECK(!algorithm.isNull()); |
| |
| scoped_ptr<EncryptState> state( |
| new EncryptState(algorithm, key, data, data_size, result)); |
| if (!CryptoThreadPool::PostTask(FROM_HERE, |
| base::Bind(DoEncrypt, Passed(&state)))) { |
| CompleteWithThreadPoolError(&result); |
| } |
| } |
| |
| void WebCryptoImpl::decrypt(const blink::WebCryptoAlgorithm& algorithm, |
| const blink::WebCryptoKey& key, |
| const unsigned char* data, |
| unsigned int data_size, |
| blink::WebCryptoResult result) { |
| DCHECK(!algorithm.isNull()); |
| |
| scoped_ptr<DecryptState> state( |
| new DecryptState(algorithm, key, data, data_size, result)); |
| if (!CryptoThreadPool::PostTask(FROM_HERE, |
| base::Bind(DoDecrypt, Passed(&state)))) { |
| CompleteWithThreadPoolError(&result); |
| } |
| } |
| |
| void WebCryptoImpl::digest(const blink::WebCryptoAlgorithm& algorithm, |
| const unsigned char* data, |
| unsigned int data_size, |
| blink::WebCryptoResult result) { |
| DCHECK(!algorithm.isNull()); |
| |
| scoped_ptr<DigestState> state(new DigestState( |
| algorithm, blink::WebCryptoKey::createNull(), data, data_size, result)); |
| if (!CryptoThreadPool::PostTask(FROM_HERE, |
| base::Bind(DoDigest, Passed(&state)))) { |
| CompleteWithThreadPoolError(&result); |
| } |
| } |
| |
| void WebCryptoImpl::generateKey(const blink::WebCryptoAlgorithm& algorithm, |
| bool extractable, |
| blink::WebCryptoKeyUsageMask usages, |
| blink::WebCryptoResult result) { |
| DCHECK(!algorithm.isNull()); |
| |
| scoped_ptr<GenerateKeyState> state( |
| new GenerateKeyState(algorithm, extractable, usages, result)); |
| if (!CryptoThreadPool::PostTask(FROM_HERE, |
| base::Bind(DoGenerateKey, Passed(&state)))) { |
| CompleteWithThreadPoolError(&result); |
| } |
| } |
| |
| void WebCryptoImpl::importKey(blink::WebCryptoKeyFormat format, |
| const unsigned char* key_data, |
| unsigned int key_data_size, |
| const blink::WebCryptoAlgorithm& algorithm, |
| bool extractable, |
| blink::WebCryptoKeyUsageMask usages, |
| blink::WebCryptoResult result) { |
| scoped_ptr<ImportKeyState> state(new ImportKeyState( |
| format, key_data, key_data_size, algorithm, extractable, usages, result)); |
| if (!CryptoThreadPool::PostTask(FROM_HERE, |
| base::Bind(DoImportKey, Passed(&state)))) { |
| CompleteWithThreadPoolError(&result); |
| } |
| } |
| |
| void WebCryptoImpl::exportKey(blink::WebCryptoKeyFormat format, |
| const blink::WebCryptoKey& key, |
| blink::WebCryptoResult result) { |
| scoped_ptr<ExportKeyState> state(new ExportKeyState(format, key, result)); |
| if (!CryptoThreadPool::PostTask(FROM_HERE, |
| base::Bind(DoExportKey, Passed(&state)))) { |
| CompleteWithThreadPoolError(&result); |
| } |
| } |
| |
| void WebCryptoImpl::sign(const blink::WebCryptoAlgorithm& algorithm, |
| const blink::WebCryptoKey& key, |
| const unsigned char* data, |
| unsigned int data_size, |
| blink::WebCryptoResult result) { |
| scoped_ptr<SignState> state( |
| new SignState(algorithm, key, data, data_size, result)); |
| if (!CryptoThreadPool::PostTask(FROM_HERE, |
| base::Bind(DoSign, Passed(&state)))) { |
| CompleteWithThreadPoolError(&result); |
| } |
| } |
| |
| void WebCryptoImpl::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) { |
| scoped_ptr<VerifySignatureState> state(new VerifySignatureState( |
| algorithm, key, signature, signature_size, data, data_size, result)); |
| if (!CryptoThreadPool::PostTask(FROM_HERE, |
| base::Bind(DoVerify, 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) { |
| scoped_ptr<WrapKeyState> state( |
| new WrapKeyState(format, key, wrapping_key, wrap_algorithm, result)); |
| if (!CryptoThreadPool::PostTask(FROM_HERE, |
| base::Bind(DoWrapKey, Passed(&state)))) { |
| CompleteWithThreadPoolError(&result); |
| } |
| } |
| |
| void WebCryptoImpl::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) { |
| scoped_ptr<UnwrapKeyState> state(new UnwrapKeyState(format, |
| wrapped_key, |
| wrapped_key_size, |
| wrapping_key, |
| unwrap_algorithm, |
| unwrapped_key_algorithm, |
| extractable, |
| usages, |
| result)); |
| if (!CryptoThreadPool::PostTask(FROM_HERE, |
| base::Bind(DoUnwrapKey, Passed(&state)))) { |
| CompleteWithThreadPoolError(&result); |
| } |
| } |
| |
| blink::WebCryptoDigestor* WebCryptoImpl::createDigestor( |
| blink::WebCryptoAlgorithmId algorithm_id) { |
| return webcrypto::CreateDigestor(algorithm_id).release(); |
| } |
| |
| 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) { |
| // TODO(eroman): Rather than do the import immediately on the current thread, |
| // it could defer to the crypto thread. |
| 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 content |