X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fcontent%2Fchild%2Fwebcrypto%2Fwebcrypto_impl.cc;h=8891689f509cf907f3ae210f530207ced04c255a;hb=004985e17e624662a4c85c76a7654039dc83f028;hp=076df0d4a3e14296ef9ca7f06f6207f9d6fffd60;hpb=2f108dbacb161091e42a3479f4e171339b7e7623;p=platform%2Fframework%2Fweb%2Fcrosswalk.git diff --git a/src/content/child/webcrypto/webcrypto_impl.cc b/src/content/child/webcrypto/webcrypto_impl.cc index 076df0d..8891689 100644 --- a/src/content/child/webcrypto/webcrypto_impl.cc +++ b/src/content/child/webcrypto/webcrypto_impl.cc @@ -4,11 +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" @@ -18,12 +28,110 @@ 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 worker_pool_; + scoped_refptr task_runner_; +}; + +base::LazyInstance::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()); - if (status.HasErrorDetails()) - result->completeWithError(blink::WebString::fromUTF8(status.ToString())); - else - result->completeWithError(); + + result->completeWithError(status.error_type(), + blink::WebString::fromUTF8(status.error_details())); +} + +void CompleteWithBufferOrError(const Status& status, + const std::vector& 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) { @@ -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 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 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 data; + + std::vector 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 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 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 signature; + const std::vector 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 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 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 state) { + CompleteWithBufferOrError(state->status, state->buffer, &state->result); +} + +void DoEncrypt(scoped_ptr 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 state) { + CompleteWithBufferOrError(state->status, state->buffer, &state->result); +} + +void DoDecrypt(scoped_ptr 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 state) { + CompleteWithBufferOrError(state->status, state->buffer, &state->result); +} + +void DoDigest(scoped_ptr 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 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 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 state) { + CompleteWithKeyOrError(state->status, state->key, &state->result); +} + +void DoImportKey(scoped_ptr 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 state) { + CompleteWithBufferOrError(state->status, state->buffer, &state->result); +} + +void DoExportKey(scoped_ptr 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 state) { + CompleteWithBufferOrError(state->status, state->buffer, &state->result); +} + +void DoSign(scoped_ptr 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 state) { + if (state->status.IsError()) { + CompleteWithError(state->status, &state->result); + } else { + state->result.completeWithBoolean(state->verify_result); + } +} + +void DoVerify(scoped_ptr 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 state) { + CompleteWithBufferOrError(state->status, state->buffer, &state->result); +} + +void DoWrapKey(scoped_ptr 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 state) { + CompleteWithKeyOrError(state->status, state->unwrapped_key, &state->result); +} + +void DoUnwrapKey(scoped_ptr 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 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 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 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 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 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 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 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 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 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,24 @@ 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 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( @@ -256,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& key_data) { - Status status = webcrypto::SerializeKeyForClone(key, &key_data); - return status.IsSuccess(); + return webcrypto::SerializeKeyForClone(key, &key_data); } } // namespace content