Chromium Code Reviews| Index: content/child/webcrypto/webcrypto_impl.cc |
| diff --git a/content/child/webcrypto/webcrypto_impl.cc b/content/child/webcrypto/webcrypto_impl.cc |
| index cc18630e4a7c402400a9d796c6c9ea4380f06ff7..984512ee19eaabddf4afaeda4a7200d8c328f703 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,79 @@ using webcrypto::Status; |
| namespace { |
| +// --------------------- |
| +// Threading |
| +// --------------------- |
| +// |
| +// WebCrypto operations can be slow. For instance generating an RSA key can |
| +// takes hundreds of milliseconds. |
|
Ryan Sleevi
2014/04/18 00:51:26
"hundreds of milliseconds to several seconds" (eg:
eroman
2014/04/18 18:45:56
Done.
|
| +// |
| +// 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. |
|
Ryan Sleevi
2014/04/18 00:51:26
s/blink/Blink/
|
| +// |
| +// 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 |
|
Ryan Sleevi
2014/04/18 00:51:26
s/handle() /handle(), /
s/type may/type, may/
eroman
2014/04/18 18:45:56
Done.
|
| +// used from the webcrypto thread). |
| +// |
| +// * blink::WebCryptoResult is NOT threadsafe and should only be operated on |
| +// the target blink thread. |
|
Ryan Sleevi
2014/04/18 00:51:26
s/blink/Blink/
|
| +// |
| +// TODO(eroman): In the current design the WebCryptoResult object may be |
| +// destroyed from the webcrypto worker pool if the blink worker |
|
Ryan Sleevi
2014/04/18 00:51:26
s/blink/Blink/
|
| +// thread has vanished by the time the operation completes. This |
| +// requires further investigation since WebCryptoResult itself is |
| +// not thread safe... However if the worker thread has been |
| +// stopped then the potential for races seems limited. |
| +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> crypto_thread_pool = |
|
Ryan Sleevi
2014/04/18 00:51:26
LeakyLazyInstance
eroman
2014/04/18 18:45:56
Done.
|
| + 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); |
| +} |
| + |
| +const char kFailedPostingToThreadPool[] = |
| + "Failed posting to crypto worker pool"; |
| + |
| void CompleteWithError(const Status& status, blink::WebCryptoResult* result) { |
| DCHECK(status.IsError()); |
| if (status.HasErrorDetails()) |
| @@ -27,6 +109,33 @@ void CompleteWithError(const Status& status, blink::WebCryptoResult* result) { |
| result->completeWithError(); |
| } |
| +void CompleteWithBuffer(const Status& status, |
| + const std::vector<uint8>& buffer, |
| + blink::WebCryptoResult* result) { |
| + if (status.IsError()) |
| + CompleteWithError(status, result); |
| + else { |
|
Ryan Sleevi
2014/04/18 00:51:26
use braces on 115 and 117 to match 117
eroman
2014/04/18 18:45:56
Done.
|
| + 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 CompleteWithKey(const Status& status, |
| + const blink::WebCryptoKey& key, |
| + blink::WebCryptoResult* result) { |
| + if (status.IsError()) |
| + CompleteWithError(status, result); |
| + else { |
| + result->completeWithKey(key); |
| + } |
|
Ryan Sleevi
2014/04/18 00:51:26
inconsistent braces. Brace ALL the things or brace
eroman
2014/04/18 18:45:56
Done.
I agree.
Not sure how this happened, proba
|
| +} |
| + |
| bool IsAlgorithmAsymmetric(const blink::WebCryptoAlgorithm& algorithm) { |
| // TODO(padolph): include all other asymmetric algorithms once they are |
| // defined, e.g. EC and DH. |
| @@ -35,11 +144,399 @@ bool IsAlgorithmAsymmetric(const blink::WebCryptoAlgorithm& algorithm) { |
| algorithm.id() == blink::WebCryptoAlgorithmIdRsaOaep); |
| } |
| +// Blink WebWorker threads do not have an associated task runner. |
| +scoped_refptr<base::TaskRunner> GetCurrentBlinkThread() { |
| + if (base::ThreadTaskRunnerHandle::IsSet()) |
| + return base::ThreadTaskRunnerHandle::Get(); |
| + return WorkerThreadTaskRunner::current(); |
| +} |
|
Ryan Sleevi
2014/04/18 00:51:26
This comment and this function do not make sense i
eroman
2014/04/18 18:45:56
Changed the comment to hopefully clarify things:
|
| + |
| +// -------------------------------------------------------------------- |
| +// 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_asymetric(false) {} |
| + |
| + const blink::WebCryptoAlgorithm algorithm; |
| + const bool extractable; |
| + const blink::WebCryptoKeyUsageMask usage_mask; |
| + |
| + // If |is_asymetric| is false, then |public_key| is understood to mean the |
|
Ryan Sleevi
2014/04/18 00:51:26
asymmetric
eroman
2014/04/18 18:45:56
Done throughout.
|
| + // symmetric key, and |private_key| is unused. |
| + blink::WebCryptoKey public_key; |
| + blink::WebCryptoKey private_key; |
| + bool is_asymetric; |
|
Ryan Sleevi
2014/04/18 00:51:26
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) { |
| + CompleteWithBuffer(state->status, state->buffer, &state->result); |
| +} |
| + |
| +void DoEncrypt(scoped_ptr<EncryptState> state) { |
| + state->status = webcrypto::Encrypt(state->algorithm, |
| + state->key, |
| + webcrypto::CryptoData(state->data), |
| + &state->buffer); |
| + state->origin_thread->PostTask(FROM_HERE, |
| + base::Bind(DoEncryptReply, Passed(&state))); |
| +} |
| + |
| +void DoDecryptReply(scoped_ptr<DecryptState> state) { |
| + CompleteWithBuffer(state->status, state->buffer, &state->result); |
| +} |
| + |
| +void DoDecrypt(scoped_ptr<DecryptState> state) { |
| + state->status = webcrypto::Decrypt(state->algorithm, |
| + state->key, |
| + webcrypto::CryptoData(state->data), |
| + &state->buffer); |
| + state->origin_thread->PostTask(FROM_HERE, |
| + base::Bind(DoDecryptReply, Passed(&state))); |
| +} |
| + |
| +void DoDigestReply(scoped_ptr<DigestState> state) { |
| + CompleteWithBuffer(state->status, state->buffer, &state->result); |
| +} |
| + |
| +void DoDigest(scoped_ptr<DigestState> state) { |
| + state->status = webcrypto::Digest( |
| + state->algorithm, webcrypto::CryptoData(state->data), &state->buffer); |
| + state->origin_thread->PostTask(FROM_HERE, |
| + base::Bind(DoDigestReply, Passed(&state))); |
| +} |
| + |
| +void DoGenerateKeyReply(scoped_ptr<GenerateKeyState> state) { |
| + if (state->status.IsError()) { |
| + CompleteWithError(state->status, &state->result); |
|
Ryan Sleevi
2014/04/18 00:51:26
Why do you allow CompleteWithError() here and in D
eroman
2014/04/18 18:45:56
Agreed. Done
|
| + } else { |
| + if (state->is_asymetric) |
| + state->result.completeWithKeyPair(state->public_key, state->private_key); |
| + else |
| + state->result.completeWithKey(state->public_key); |
| + } |
| +} |
| + |
| +void DoGenerateKey(scoped_ptr<GenerateKeyState> state) { |
| + state->is_asymetric = IsAlgorithmAsymmetric(state->algorithm); |
| + if (state->is_asymetric) { |
| + state->status = webcrypto::GenerateKeyPair(state->algorithm, |
| + state->extractable, |
| + state->usage_mask, |
| + &state->public_key, |
| + &state->private_key); |
| + |
| + 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); |
| + |
| + 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(&state))); |
| +} |
| + |
| +void DoImportKeyReply(scoped_ptr<ImportKeyState> state) { |
| + CompleteWithKey(state->status, state->key, &state->result); |
| +} |
| + |
| +void DoImportKey(scoped_ptr<ImportKeyState> state) { |
| + state->status = webcrypto::ImportKey(state->format, |
| + webcrypto::CryptoData(state->key_data), |
| + state->algorithm, |
| + state->extractable, |
| + state->usage_mask, |
| + &state->key); |
| + 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(&state))); |
| +} |
| + |
| +void DoExportKeyReply(scoped_ptr<ExportKeyState> state) { |
| + CompleteWithBuffer(state->status, state->buffer, &state->result); |
| +} |
| + |
| +void DoExportKey(scoped_ptr<ExportKeyState> state) { |
| + state->status = |
| + webcrypto::ExportKey(state->format, state->key, &state->buffer); |
| + state->origin_thread->PostTask(FROM_HERE, |
| + base::Bind(DoExportKeyReply, Passed(&state))); |
| +} |
| + |
| +void DoSignReply(scoped_ptr<SignState> state) { |
| + CompleteWithBuffer(state->status, state->buffer, &state->result); |
| +} |
| + |
| +void DoSign(scoped_ptr<SignState> state) { |
| + state->status = webcrypto::Sign(state->algorithm, |
| + state->key, |
| + webcrypto::CryptoData(state->data), |
| + &state->buffer); |
| + |
| + state->origin_thread->PostTask(FROM_HERE, |
| + base::Bind(DoSignReply, 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> state) { |
| + 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(&state))); |
| +} |
| + |
| +void DoWrapKeyReply(scoped_ptr<WrapKeyState> state) { |
| + CompleteWithBuffer(state->status, state->buffer, &state->result); |
| +} |
| + |
| +void DoWrapKey(scoped_ptr<WrapKeyState> state) { |
| + // 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(&state))); |
| +} |
| + |
| +void DoUnwrapKeyReply(scoped_ptr<UnwrapKeyState> state) { |
| + CompleteWithKey(state->status, state->unwrapped_key, &state->result); |
| +} |
| + |
| +void DoUnwrapKey(scoped_ptr<UnwrapKeyState> state) { |
| + 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(&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, |
| @@ -47,13 +544,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)))) { |
| + result.completeWithError(kFailedPostingToThreadPool); |
| + } |
| } |
| void WebCryptoImpl::decrypt(const blink::WebCryptoAlgorithm& algorithm, |
| @@ -62,13 +559,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)))) { |
| + result.completeWithError(kFailedPostingToThreadPool); |
| + } |
| } |
| void WebCryptoImpl::digest(const blink::WebCryptoAlgorithm& algorithm, |
| @@ -76,13 +573,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)))) { |
| + result.completeWithError(kFailedPostingToThreadPool); |
| + } |
| } |
| void WebCryptoImpl::generateKey(const blink::WebCryptoAlgorithm& algorithm, |
| @@ -90,37 +587,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)))) { |
| + result.completeWithError(kFailedPostingToThreadPool); |
| } |
| } |
| @@ -131,33 +603,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)))) { |
| + result.completeWithError(kFailedPostingToThreadPool); |
| } |
| } |
| 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)))) { |
| + result.completeWithError(kFailedPostingToThreadPool); |
| + } |
| } |
| void WebCryptoImpl::sign(const blink::WebCryptoAlgorithm& algorithm, |
| @@ -165,14 +631,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)))) { |
| + result.completeWithError(kFailedPostingToThreadPool); |
| + } |
| } |
| void WebCryptoImpl::verifySignature(const blink::WebCryptoAlgorithm& algorithm, |
| @@ -182,18 +646,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)))) { |
| + result.completeWithError(kFailedPostingToThreadPool); |
| + } |
| } |
| void WebCryptoImpl::wrapKey(blink::WebCryptoKeyFormat format, |
| @@ -201,14 +659,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)))) { |
| + result.completeWithError(kFailedPostingToThreadPool); |
| + } |
| } |
| void WebCryptoImpl::unwrapKey( |
| @@ -221,32 +677,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)))) { |
| + result.completeWithError(kFailedPostingToThreadPool); |
| + } |
| } |
| blink::WebCryptoDigestor* WebCryptoImpl::createDigestor( |
| @@ -262,21 +705,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 |