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 |