| Index: content/child/webcrypto/webcrypto_impl.cc
|
| diff --git a/content/child/webcrypto/webcrypto_impl.cc b/content/child/webcrypto/webcrypto_impl.cc
|
| index 57bdde44568bdf50ec72b1617218c3b52664be86..8891689f509cf907f3ae210f530207ced04c255a 100644
|
| --- a/content/child/webcrypto/webcrypto_impl.cc
|
| +++ b/content/child/webcrypto/webcrypto_impl.cc
|
| @@ -4,12 +4,21 @@
|
|
|
| #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/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/crypto_data.h"
|
| #include "content/child/webcrypto/shared_crypto.h"
|
| #include "content/child/webcrypto/status.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"
|
|
|
| @@ -19,6 +28,78 @@ 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());
|
|
|
| @@ -26,6 +107,33 @@ void CompleteWithError(const Status& status, blink::WebCryptoResult* result) {
|
| blink::WebString::fromUTF8(status.error_details()));
|
| }
|
|
|
| +void CompleteWithBufferOrError(const Status& status,
|
| + const std::vector<uint8>& 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(webcrypto::Uint8VectorStart(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);
|
| + }
|
| +}
|
| +
|
| bool IsAlgorithmAsymmetric(const blink::WebCryptoAlgorithm& algorithm) {
|
| // TODO(padolph): include all other asymmetric algorithms once they are
|
| // defined, e.g. EC and DH.
|
| @@ -34,11 +142,423 @@ bool IsAlgorithmAsymmetric(const blink::WebCryptoAlgorithm& algorithm) {
|
| algorithm.id() == blink::WebCryptoAlgorithmIdRsaOaep);
|
| }
|
|
|
| +// 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) {}
|
| +
|
| + 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> data;
|
| +
|
| + std::vector<uint8> buffer;
|
| +};
|
| +
|
| +typedef EncryptState DecryptState;
|
| +typedef EncryptState DigestState;
|
| +
|
| +struct GenerateKeyState : public BaseState {
|
| + GenerateKeyState(const blink::WebCryptoAlgorithm& algorithm,
|
| + bool extractable,
|
| + blink::WebCryptoKeyUsageMask usage_mask,
|
| + const blink::WebCryptoResult& result)
|
| + : BaseState(result),
|
| + algorithm(algorithm),
|
| + extractable(extractable),
|
| + usage_mask(usage_mask),
|
| + public_key(blink::WebCryptoKey::createNull()),
|
| + private_key(blink::WebCryptoKey::createNull()),
|
| + is_asymmetric(false) {}
|
| +
|
| + const blink::WebCryptoAlgorithm algorithm;
|
| + const bool extractable;
|
| + const blink::WebCryptoKeyUsageMask usage_mask;
|
| +
|
| + // If |is_asymmetric| is false, then |public_key| is understood to mean the
|
| + // symmetric key, and |private_key| is unused.
|
| + blink::WebCryptoKey public_key;
|
| + blink::WebCryptoKey private_key;
|
| + bool is_asymmetric;
|
| +};
|
| +
|
| +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 usage_mask,
|
| + const blink::WebCryptoResult& result)
|
| + : BaseState(result),
|
| + format(format),
|
| + key_data(key_data, key_data + key_data_size),
|
| + algorithm(algorithm),
|
| + extractable(extractable),
|
| + usage_mask(usage_mask),
|
| + key(blink::WebCryptoKey::createNull()) {}
|
| +
|
| + const blink::WebCryptoKeyFormat format;
|
| + const std::vector<uint8> key_data;
|
| + const blink::WebCryptoAlgorithm algorithm;
|
| + const bool extractable;
|
| + const blink::WebCryptoKeyUsageMask usage_mask;
|
| +
|
| + 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> 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> signature;
|
| + const std::vector<uint8> 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> 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),
|
| + unwrapped_key(blink::WebCryptoKey::createNull()) {}
|
| +
|
| + const blink::WebCryptoKeyFormat format;
|
| + const std::vector<uint8> 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();
|
| + 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();
|
| + 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();
|
| + 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 {
|
| + if (state->is_asymmetric)
|
| + state->result.completeWithKeyPair(state->public_key, state->private_key);
|
| + else
|
| + state->result.completeWithKey(state->public_key);
|
| + }
|
| +}
|
| +
|
| +void DoGenerateKey(scoped_ptr<GenerateKeyState> passed_state) {
|
| + GenerateKeyState* state = passed_state.get();
|
| + state->is_asymmetric = IsAlgorithmAsymmetric(state->algorithm);
|
| + if (state->is_asymmetric) {
|
| + state->status = webcrypto::GenerateKeyPair(state->algorithm,
|
| + state->extractable,
|
| + state->usage_mask,
|
| + &state->public_key,
|
| + &state->private_key);
|
| +
|
| + if (state->status.IsSuccess()) {
|
| + DCHECK(state->public_key.handle());
|
| + DCHECK(state->private_key.handle());
|
| + DCHECK_EQ(state->algorithm.id(), state->public_key.algorithm().id());
|
| + DCHECK_EQ(state->algorithm.id(), state->private_key.algorithm().id());
|
| + DCHECK_EQ(true, state->public_key.extractable());
|
| + DCHECK_EQ(state->extractable, state->private_key.extractable());
|
| + DCHECK_EQ(state->usage_mask, state->public_key.usages());
|
| + DCHECK_EQ(state->usage_mask, state->private_key.usages());
|
| + }
|
| + } else {
|
| + blink::WebCryptoKey* key = &state->public_key;
|
| +
|
| + state->status = webcrypto::GenerateSecretKey(
|
| + state->algorithm, state->extractable, state->usage_mask, key);
|
| +
|
| + if (state->status.IsSuccess()) {
|
| + DCHECK(key->handle());
|
| + DCHECK_EQ(state->algorithm.id(), key->algorithm().id());
|
| + DCHECK_EQ(state->extractable, key->extractable());
|
| + DCHECK_EQ(state->usage_mask, key->usages());
|
| + }
|
| + }
|
| +
|
| + 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();
|
| + state->status = webcrypto::ImportKey(state->format,
|
| + webcrypto::CryptoData(state->key_data),
|
| + state->algorithm,
|
| + state->extractable,
|
| + state->usage_mask,
|
| + &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) {
|
| + CompleteWithBufferOrError(state->status, state->buffer, &state->result);
|
| +}
|
| +
|
| +void DoExportKey(scoped_ptr<ExportKeyState> passed_state) {
|
| + ExportKeyState* state = passed_state.get();
|
| + 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();
|
| + 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();
|
| + state->status =
|
| + webcrypto::VerifySignature(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();
|
| + // TODO(eroman): The parameter ordering of webcrypto::WrapKey() is
|
| + // inconsistent with that of blink::WebCrypto::wrapKey().
|
| + state->status = webcrypto::WrapKey(state->format,
|
| + state->wrapping_key,
|
| + state->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();
|
| + 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() { webcrypto::Init(); }
|
| +WebCryptoImpl::WebCryptoImpl() {
|
| + webcrypto::Init();
|
| +}
|
|
|
| -WebCryptoImpl::~WebCryptoImpl() {}
|
| +WebCryptoImpl::~WebCryptoImpl() {
|
| +}
|
|
|
| void WebCryptoImpl::encrypt(const blink::WebCryptoAlgorithm& algorithm,
|
| const blink::WebCryptoKey& key,
|
| @@ -46,13 +566,13 @@ void WebCryptoImpl::encrypt(const blink::WebCryptoAlgorithm& algorithm,
|
| unsigned int data_size,
|
| blink::WebCryptoResult result) {
|
| DCHECK(!algorithm.isNull());
|
| - blink::WebArrayBuffer buffer;
|
| - Status status = webcrypto::Encrypt(
|
| - algorithm, key, webcrypto::CryptoData(data, data_size), &buffer);
|
| - if (status.IsError())
|
| - CompleteWithError(status, &result);
|
| - else
|
| - result.completeWithBuffer(buffer);
|
| +
|
| + 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,
|
| @@ -61,13 +581,13 @@ void WebCryptoImpl::decrypt(const blink::WebCryptoAlgorithm& algorithm,
|
| unsigned int data_size,
|
| blink::WebCryptoResult result) {
|
| DCHECK(!algorithm.isNull());
|
| - blink::WebArrayBuffer buffer;
|
| - Status status = webcrypto::Decrypt(
|
| - algorithm, key, webcrypto::CryptoData(data, data_size), &buffer);
|
| - if (status.IsError())
|
| - CompleteWithError(status, &result);
|
| - else
|
| - result.completeWithBuffer(buffer);
|
| +
|
| + 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,
|
| @@ -75,13 +595,13 @@ void WebCryptoImpl::digest(const blink::WebCryptoAlgorithm& algorithm,
|
| unsigned int data_size,
|
| blink::WebCryptoResult result) {
|
| DCHECK(!algorithm.isNull());
|
| - blink::WebArrayBuffer buffer;
|
| - Status status = webcrypto::Digest(
|
| - algorithm, webcrypto::CryptoData(data, data_size), &buffer);
|
| - if (status.IsError())
|
| - CompleteWithError(status, &result);
|
| - else
|
| - result.completeWithBuffer(buffer);
|
| +
|
| + 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,
|
| @@ -89,37 +609,12 @@ void WebCryptoImpl::generateKey(const blink::WebCryptoAlgorithm& algorithm,
|
| blink::WebCryptoKeyUsageMask usage_mask,
|
| blink::WebCryptoResult result) {
|
| DCHECK(!algorithm.isNull());
|
| - if (IsAlgorithmAsymmetric(algorithm)) {
|
| - blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
|
| - blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
|
| - Status status = webcrypto::GenerateKeyPair(
|
| - algorithm, extractable, usage_mask, &public_key, &private_key);
|
| - if (status.IsError()) {
|
| - CompleteWithError(status, &result);
|
| - } else {
|
| - DCHECK(public_key.handle());
|
| - DCHECK(private_key.handle());
|
| - DCHECK_EQ(algorithm.id(), public_key.algorithm().id());
|
| - DCHECK_EQ(algorithm.id(), private_key.algorithm().id());
|
| - DCHECK_EQ(true, public_key.extractable());
|
| - DCHECK_EQ(extractable, private_key.extractable());
|
| - DCHECK_EQ(usage_mask, public_key.usages());
|
| - DCHECK_EQ(usage_mask, private_key.usages());
|
| - result.completeWithKeyPair(public_key, private_key);
|
| - }
|
| - } else {
|
| - blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
|
| - Status status =
|
| - webcrypto::GenerateSecretKey(algorithm, extractable, usage_mask, &key);
|
| - if (status.IsError()) {
|
| - CompleteWithError(status, &result);
|
| - } else {
|
| - DCHECK(key.handle());
|
| - DCHECK_EQ(algorithm.id(), key.algorithm().id());
|
| - DCHECK_EQ(extractable, key.extractable());
|
| - DCHECK_EQ(usage_mask, key.usages());
|
| - result.completeWithKey(key);
|
| - }
|
| +
|
| + scoped_ptr<GenerateKeyState> state(
|
| + new GenerateKeyState(algorithm, extractable, usage_mask, result));
|
| + if (!CryptoThreadPool::PostTask(FROM_HERE,
|
| + base::Bind(DoGenerateKey, Passed(&state)))) {
|
| + CompleteWithThreadPoolError(&result);
|
| }
|
| }
|
|
|
| @@ -130,33 +625,27 @@ void WebCryptoImpl::importKey(blink::WebCryptoKeyFormat format,
|
| bool extractable,
|
| blink::WebCryptoKeyUsageMask usage_mask,
|
| blink::WebCryptoResult result) {
|
| - blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
|
| - Status status =
|
| - webcrypto::ImportKey(format,
|
| - webcrypto::CryptoData(key_data, key_data_size),
|
| - algorithm,
|
| - extractable,
|
| - usage_mask,
|
| - &key);
|
| - if (status.IsError()) {
|
| - CompleteWithError(status, &result);
|
| - } else {
|
| - DCHECK(key.handle());
|
| - DCHECK(!key.algorithm().isNull());
|
| - DCHECK_EQ(extractable, key.extractable());
|
| - result.completeWithKey(key);
|
| + scoped_ptr<ImportKeyState> state(new ImportKeyState(format,
|
| + key_data,
|
| + key_data_size,
|
| + algorithm,
|
| + extractable,
|
| + usage_mask,
|
| + 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) {
|
| - blink::WebArrayBuffer buffer;
|
| - Status status = webcrypto::ExportKey(format, key, &buffer);
|
| - if (status.IsError())
|
| - CompleteWithError(status, &result);
|
| - else
|
| - result.completeWithBuffer(buffer);
|
| + 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,
|
| @@ -164,14 +653,12 @@ void WebCryptoImpl::sign(const blink::WebCryptoAlgorithm& algorithm,
|
| const unsigned char* data,
|
| unsigned int data_size,
|
| blink::WebCryptoResult result) {
|
| - DCHECK(!algorithm.isNull());
|
| - blink::WebArrayBuffer buffer;
|
| - Status status = webcrypto::Sign(
|
| - algorithm, key, webcrypto::CryptoData(data, data_size), &buffer);
|
| - if (status.IsError())
|
| - CompleteWithError(status, &result);
|
| - else
|
| - result.completeWithBuffer(buffer);
|
| + 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,
|
| @@ -181,18 +668,12 @@ void WebCryptoImpl::verifySignature(const blink::WebCryptoAlgorithm& algorithm,
|
| const unsigned char* data,
|
| unsigned int data_size,
|
| blink::WebCryptoResult result) {
|
| - DCHECK(!algorithm.isNull());
|
| - bool signature_match = false;
|
| - Status status = webcrypto::VerifySignature(
|
| - algorithm,
|
| - key,
|
| - webcrypto::CryptoData(signature, signature_size),
|
| - webcrypto::CryptoData(data, data_size),
|
| - &signature_match);
|
| - if (status.IsError())
|
| - CompleteWithError(status, &result);
|
| - else
|
| - result.completeWithBoolean(signature_match);
|
| + 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,
|
| @@ -200,14 +681,12 @@ void WebCryptoImpl::wrapKey(blink::WebCryptoKeyFormat format,
|
| const blink::WebCryptoKey& wrapping_key,
|
| const blink::WebCryptoAlgorithm& wrap_algorithm,
|
| blink::WebCryptoResult result) {
|
| - blink::WebArrayBuffer buffer;
|
| - // TODO(eroman): Use the same parameter ordering.
|
| - Status status = webcrypto::WrapKey(
|
| - format, wrapping_key, key, wrap_algorithm, &buffer);
|
| - if (status.IsError())
|
| - CompleteWithError(status, &result);
|
| - else
|
| - result.completeWithBuffer(buffer);
|
| + 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(
|
| @@ -220,32 +699,19 @@ void WebCryptoImpl::unwrapKey(
|
| bool extractable,
|
| blink::WebCryptoKeyUsageMask usages,
|
| blink::WebCryptoResult result) {
|
| - blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
|
| - Status status =
|
| - webcrypto::UnwrapKey(format,
|
| - webcrypto::CryptoData(wrapped_key, wrapped_key_size),
|
| - wrapping_key,
|
| - unwrap_algorithm,
|
| - unwrapped_key_algorithm,
|
| - extractable,
|
| - usages,
|
| - &key);
|
| - if (status.IsError())
|
| - CompleteWithError(status, &result);
|
| - else
|
| - result.completeWithKey(key);
|
| -}
|
| -
|
| -bool WebCryptoImpl::digestSynchronous(
|
| - const blink::WebCryptoAlgorithmId algorithm_id,
|
| - const unsigned char* data,
|
| - unsigned int data_size,
|
| - blink::WebArrayBuffer& result) {
|
| - blink::WebCryptoAlgorithm algorithm =
|
| - blink::WebCryptoAlgorithm::adoptParamsAndCreate(algorithm_id, NULL);
|
| - return (webcrypto::Digest(
|
| - algorithm, webcrypto::CryptoData(data, data_size), &result))
|
| - .IsSuccess();
|
| + 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(
|
| @@ -261,21 +727,21 @@ bool WebCryptoImpl::deserializeKeyForClone(
|
| const unsigned char* key_data,
|
| unsigned key_data_size,
|
| blink::WebCryptoKey& key) {
|
| - Status status = webcrypto::DeserializeKeyForClone(
|
| + // 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);
|
| - return status.IsSuccess();
|
| }
|
|
|
| bool WebCryptoImpl::serializeKeyForClone(
|
| const blink::WebCryptoKey& key,
|
| blink::WebVector<unsigned char>& key_data) {
|
| - Status status = webcrypto::SerializeKeyForClone(key, &key_data);
|
| - return status.IsSuccess();
|
| + return webcrypto::SerializeKeyForClone(key, &key_data);
|
| }
|
|
|
| } // namespace content
|
|
|