Chromium Code Reviews| Index: Source/modules/crypto/SubtleCrypto.cpp |
| diff --git a/Source/modules/crypto/SubtleCrypto.cpp b/Source/modules/crypto/SubtleCrypto.cpp |
| index e0e75ccb25244f1a819295c82288f3ccc6ddaa04..247d3eff0938c14827c383217fe35d0cc89b1f58 100644 |
| --- a/Source/modules/crypto/SubtleCrypto.cpp |
| +++ b/Source/modules/crypto/SubtleCrypto.cpp |
| @@ -31,107 +31,132 @@ |
| #include "config.h" |
| #include "modules/crypto/SubtleCrypto.h" |
| +#include "V8Key.h" // NOTE: This must appear before ScriptPromiseResolver to define toV8() |
| +#include "bindings/v8/ScriptPromiseResolver.h" |
| #include "core/dom/ExceptionCode.h" |
| #include "modules/crypto/CryptoOperation.h" |
| +#include "modules/crypto/Key.h" |
| #include "modules/crypto/NormalizeAlgorithm.h" |
| #include "public/platform/Platform.h" |
| -#include "public/platform/WebArrayBuffer.h" // FIXME: temporary |
| #include "public/platform/WebCrypto.h" |
| -#include "wtf/ArrayBuffer.h" |
| #include "wtf/ArrayBufferView.h" |
| -#include "wtf/SHA1.h" // FIXME: temporary |
| - |
| namespace WebCore { |
| namespace { |
| -// FIXME: The following are temporary implementations of what *should* go on the |
| -// embedder's side. Since SHA1 is easily implemented, this serves as |
| -// a useful proof of concept to get layout tests up and running and |
| -// returning correct results, until the embedder's side is implemented. |
| -//------------------------------------------------------------------------------ |
| -class DummyOperation : public WebKit::WebCryptoOperation { |
| -public: |
| - explicit DummyOperation(WebKit::WebCryptoOperationResult* result) : m_result(result) { } |
| - |
| - virtual void process(const unsigned char* bytes, size_t size) OVERRIDE |
| - { |
| - m_result->completeWithError(); |
| - delete this; |
| - } |
| - |
| - virtual void abort() OVERRIDE |
| - { |
| - delete this; |
| +// FIXME: Temporary |
| +PassRefPtr<CryptoOperation> doDummyOperation(const Dictionary& rawAlgorithm, AlgorithmOperation operationType, ExceptionCode& ec) |
|
abarth-chromium
2013/07/23 06:22:07
Like "get", "do" is a weak verb. Perhaps "dummyOp
|
| +{ |
| + WebKit::WebCrypto* platformCrypto = WebKit::Platform::current()->crypto(); |
| + if (!platformCrypto) { |
| + ec = NotSupportedError; |
| + return 0; |
| } |
| - virtual void finish() OVERRIDE |
| - { |
| - m_result->completeWithError(); |
| - delete this; |
| - } |
| + WebKit::WebCryptoAlgorithm algorithm; |
| + if (!normalizeAlgorithm(rawAlgorithm, operationType, algorithm, ec)) |
| + return 0; |
| -protected: |
| - WebKit::WebCryptoOperationResult* m_result; |
| -}; |
| + RefPtr<CryptoOperation> op = CryptoOperation::create(algorithm, &ec); |
| + platformCrypto->digest(algorithm, op.get()); |
| + return op.release(); |
| +} |
| -class MockSha1Operation : public DummyOperation { |
| +class KeyOperation : public WebKit::WebCryptoKeyOperationResult { |
| public: |
| - explicit MockSha1Operation(WebKit::WebCryptoOperationResult* result) : DummyOperation(result) { } |
| - |
| - virtual void process(const unsigned char* bytes, size_t size) OVERRIDE |
| + KeyOperation(ScriptPromiseResolver* resolver, ExceptionCode* ec) |
| + : m_state(Initializing) |
| + , m_impl(0) |
| + , m_promiseResolver(resolver) |
| + , m_exceptionCode(ec) |
| { |
| - m_sha1.addBytes(bytes, size); |
| } |
| - virtual void finish() OVERRIDE |
| - { |
| - Vector<uint8_t, 20> hash; |
| - m_sha1.computeHash(hash); |
| + ~KeyOperation(); |
| - WebKit::WebArrayBuffer buffer = WebKit::WebArrayBuffer::create(hash.size(), 1); |
| - memcpy(buffer.data(), hash.data(), hash.size()); |
| - |
| - m_result->completeWithArrayBuffer(buffer); |
| - delete this; |
| - } |
| + // Implementation of WebKit::WebCryptoKeyOperationResult. |
| + virtual void initializationFailed() OVERRIDE; |
| + virtual void initializationSucceeded(WebKit::WebCryptoKeyOperation*) OVERRIDE; |
| + virtual void completeWithError() OVERRIDE; |
| + virtual void completeWithKey(const WebKit::WebCryptoKey&) OVERRIDE; |
| private: |
| - SHA1 m_sha1; |
| + enum State { |
| + Initializing, |
| + InProgress, |
| + Done, |
| + }; |
| + |
| + State m_state; |
| + WebKit::WebCryptoKeyOperation* m_impl; |
| + ExceptionCode* m_exceptionCode; |
|
abarth-chromium
2013/07/23 06:22:07
I don't understand how KeyOperation can hold a poi
eroman
2013/07/23 06:53:41
It is a little bit tricky, but the m_exceptionCode
abarth-chromium
2013/07/23 07:06:14
That's too tricky. Is there a simpler design?
|
| + RefPtr<ScriptPromiseResolver> m_promiseResolver; |
| }; |
| -class MockPlatformCrypto : public WebKit::WebCrypto { |
| -public: |
| - virtual void digest(const WebKit::WebCryptoAlgorithm& algorithm, WebKit::WebCryptoOperationResult* result) OVERRIDE |
| - { |
| - if (algorithm.id() == WebKit::WebCryptoAlgorithmIdSha1) { |
| - result->initializationSucceded(new MockSha1Operation(result)); |
| - } else { |
| - // Don't fail synchronously, since existing layout tests rely on |
| - // digest for testing algorithm normalization. |
| - result->initializationSucceded(new DummyOperation(result)); |
| - } |
| +KeyOperation::~KeyOperation() |
| +{ |
| + // Abort any inprogress operation. |
| + switch (m_state) { |
| + case Initializing: |
| + ASSERT_NOT_REACHED(); |
| + break; |
| + case InProgress: |
| + // This will cause m_impl to be deleted. |
| + m_state = Done; |
| + m_impl->abort(); |
| + m_impl = 0; |
| + case Done: |
| + ASSERT(!m_impl); |
| + break; |
| } |
| -}; |
| +} |
| -WebKit::WebCrypto* mockPlatformCrypto() |
| +void KeyOperation::initializationFailed() |
| { |
| - DEFINE_STATIC_LOCAL(MockPlatformCrypto, crypto, ()); |
| - return &crypto; |
| + ASSERT(m_state == Initializing); |
| + |
| + *m_exceptionCode = NotSupportedError; |
| + |
| + m_exceptionCode = 0; |
| + m_state = Done; |
| + delete this; |
|
abarth-chromium
2013/07/23 06:22:07
This line is suspicious and indicates a bad memory
|
| } |
| -PassRefPtr<CryptoOperation> doDummyOperation(const Dictionary& rawAlgorithm, AlgorithmOperation operationType, ExceptionCode& ec) |
| +void KeyOperation::initializationSucceeded(WebKit::WebCryptoKeyOperation* operationImpl) |
| { |
| - WebKit::WebCryptoAlgorithm algorithm; |
| - if (!normalizeAlgorithm(rawAlgorithm, operationType, algorithm, ec)) |
| - return 0; |
| + ASSERT(m_state == Initializing); |
| + ASSERT(operationImpl); |
| + ASSERT(!m_impl); |
| - RefPtr<CryptoOperation> op = CryptoOperation::create(algorithm, &ec); |
| - op->initializationSucceded(new DummyOperation(op.get())); |
| - return op.release(); |
| + m_exceptionCode = 0; |
| + m_impl = operationImpl; |
| + m_state = InProgress; |
| +} |
| + |
| +void KeyOperation::completeWithError() |
| +{ |
| + ASSERT(m_state == Initializing || m_state == InProgress); |
| + |
| + m_exceptionCode = 0; |
| + m_impl = 0; |
| + m_state = Done; |
| + |
| + m_promiseResolver->reject(ScriptValue::createNull()); |
| + delete this; |
| +} |
| + |
| +void KeyOperation::completeWithKey(const WebKit::WebCryptoKey& key) |
| +{ |
| + ASSERT(m_state == Initializing || m_state == InProgress); |
| + |
| + m_exceptionCode = 0; |
| + m_impl = 0; |
| + m_state = Done; |
| + |
| + m_promiseResolver->fulfill(Key::create(key)); |
| + delete this; |
| } |
| -//------------------------------------------------------------------------------ |
| } // namespace |
| @@ -162,7 +187,7 @@ PassRefPtr<CryptoOperation> SubtleCrypto::verifySignature(const Dictionary& rawA |
| PassRefPtr<CryptoOperation> SubtleCrypto::digest(const Dictionary& rawAlgorithm, ExceptionCode& ec) |
| { |
| - WebKit::WebCrypto* platformCrypto = mockPlatformCrypto(); |
| + WebKit::WebCrypto* platformCrypto = WebKit::Platform::current()->crypto(); |
| if (!platformCrypto) { |
| ec = NotSupportedError; |
| return 0; |
| @@ -177,4 +202,45 @@ PassRefPtr<CryptoOperation> SubtleCrypto::digest(const Dictionary& rawAlgorithm, |
| return op.release(); |
| } |
| +ScriptObject SubtleCrypto::importKey(const String& rawFormat, ArrayBufferView* keyData, const Dictionary& rawAlgorithm, bool extractable, const Vector<String>& rawKeyUsages, ExceptionCode& ec) |
| +{ |
| + WebKit::WebCrypto* platformCrypto = WebKit::Platform::current()->crypto(); |
| + if (!platformCrypto) { |
| + ec = NotSupportedError; |
| + return ScriptObject(); |
| + } |
| + |
| + WebKit::WebCryptoKeyUsageMask keyUsages; |
| + if (!Key::parseUsageMask(rawKeyUsages, keyUsages)) { |
| + ec = TypeError; |
| + return ScriptObject(); |
| + } |
| + |
| + WebKit::WebCryptoKeyFormat format; |
| + if (!Key::parseFormat(rawFormat, format)) { |
| + ec = TypeError; |
| + return ScriptObject(); |
| + } |
| + |
| + WebKit::WebCryptoAlgorithm algorithm; |
| + if (!normalizeAlgorithmForImportKey(rawAlgorithm, algorithm, ec)) |
| + return ScriptObject(); |
| + |
| + const unsigned char* keyDataBytes = static_cast<unsigned char*>(keyData->baseAddress()); |
| + |
| + RefPtr<ScriptPromiseResolver> promiseResolver = ScriptPromiseResolver::create(); |
| + |
| + // The |op| object is deleted upon completion of the underlying operation |
| + // (i.e. when platformCrypto->importKey() notifies completion). |
| + // |
| + // FIXME: KeyOperation is never aborted. It should probably be aborted when |
| + // the SubtleCrypto object that started it gets deleted. The concern being |
| + // if the operation eventually does complete, the ScriptPromiseResolver |
| + // might no longer be valid because the context it belonged to got torn |
| + // down. |
| + KeyOperation* op = new KeyOperation(promiseResolver.get(), &ec); |
|
abarth-chromium
2013/07/23 06:22:07
This is a "naked new", which is where the bad memo
eroman
2013/07/23 06:53:41
I'll think about this some more and see what else
abarth-chromium
2013/07/23 07:06:14
We might want to change CryptoOperation to follow
|
| + platformCrypto->importKey(format, keyDataBytes, keyData->byteLength(), algorithm, extractable, keyUsages, op); |
| + return promiseResolver->promise(); |
| +} |
| + |
| } // namespace WebCore |