Chromium Code Reviews| Index: Source/bindings/v8/SerializedScriptValue.cpp |
| diff --git a/Source/bindings/v8/SerializedScriptValue.cpp b/Source/bindings/v8/SerializedScriptValue.cpp |
| index f74f462fe7421a1f5396cefb9f3b719c1e5c2bef..745015953700350faa83f0f37ceca721f1d93c26 100644 |
| --- a/Source/bindings/v8/SerializedScriptValue.cpp |
| +++ b/Source/bindings/v8/SerializedScriptValue.cpp |
| @@ -36,6 +36,7 @@ |
| #include "V8File.h" |
| #include "V8FileList.h" |
| #include "V8ImageData.h" |
| +#include "V8Key.h" |
| #include "V8MessagePort.h" |
| #include "bindings/v8/ExceptionState.h" |
| #include "bindings/v8/ScriptScope.h" |
| @@ -63,6 +64,10 @@ |
| #include "core/html/canvas/DataView.h" |
| #include "heap/Handle.h" |
| #include "platform/SharedBuffer.h" |
| +#include "public/platform/Platform.h" |
| +#include "public/platform/WebCrypto.h" |
| +#include "public/platform/WebCryptoKey.h" |
| +#include "public/platform/WebCryptoKeyAlgorithm.h" |
| #include "wtf/ArrayBuffer.h" |
| #include "wtf/ArrayBufferContents.h" |
| #include "wtf/ArrayBufferView.h" |
| @@ -209,6 +214,15 @@ enum SerializationTag { |
| ArrayBufferTag = 'B', // byteLength:uint32_t, data:byte[byteLength] -> ArrayBuffer (ref) |
| ArrayBufferTransferTag = 't', // index:uint32_t -> ArrayBuffer. For ArrayBuffer transfer |
| ArrayBufferViewTag = 'V', // subtag:byte, byteOffset:uint32_t, byteLength:uint32_t -> ArrayBufferView (ref). Consumes an ArrayBuffer from the top of the deserialization stack. |
| + CryptoKeyTag = 'K', // subtag:byte, props, usages:uint32_t, keyDataLength:uint32_t, keyData:byte[keyDataLength] |
| + // If subtag=AesKeyTag: |
| + // props = keyLengthBytes:uint32_t, algorithmId:uint32_t |
| + // If subtag=HmacKeyTag: |
| + // props = hashId:uint32_t |
| + // If subtag=RsaKeyTag: |
| + // props = algorithmId:uint32_t, type:uint32_t, modulusLengthBits:uint32_t, publicExponentLength:uint32_t, publicExponent:byte[publicExponentLength] |
| + // If subtag=RsaHashedKeyTag: |
| + // props = <same as for RsaKeyTag>, hashId:uint32_t |
| ObjectReferenceTag = '^', // ref:uint32_t -> reference table[ref] |
| GenerateFreshObjectTag = 'o', // -> empty object allocated an object ID and pushed onto the open stack (ref) |
| GenerateFreshSparseArrayTag = 'a', // length:uint32_t -> empty array[length] allocated an object ID and pushed onto the open stack (ref) |
| @@ -234,6 +248,52 @@ enum ArrayBufferViewSubTag { |
| DataViewTag = '?' |
| }; |
| +enum CryptoKeySubTag { |
| + AesKeyTag = 1, |
| + HmacKeyTag = 2, |
| + RsaKeyTag = 3, |
| + RsaHashedKeyTag = 4, |
| + // Maximum allowed value is 255 |
|
jsbell
2014/03/13 20:16:07
(C++11 enum classes, some day!)
|
| +}; |
| + |
| +enum AssymetricCryptoKeyType { |
| + PublicKeyType = 1, |
| + PrivateKeyType = 2, |
| + // Maximum allowed value is 2^32-1 |
| +}; |
| + |
| +enum CryptoKeyAlgorithmTag { |
| + AesCbcTag = 1, |
| + HmacTag = 2, |
| + RsaSsaPkcs1v1_5Tag = 3, |
| + RsaEsPkcs1v1_5Tag = 4, |
| + Sha1Tag = 5, |
| + Sha224Tag = 6, |
| + Sha256Tag = 7, |
| + Sha384Tag = 8, |
| + Sha512Tag = 9, |
| + AesGcmTag = 10, |
| + RsaOaepTag = 11, |
| + AesCtrTag = 12, |
| + AesKwTag = 13, |
| + // Maximum allowed value is 2^32-1 |
| +}; |
| + |
| +enum CryptoKeyUsage { |
| + // Extractability is not a "usage" in the WebCryptoKeyUsages sense, however |
| + // it fits conveniently into this bitfield. |
| + ExtractableUsage = 1 << 0, |
| + |
| + EncryptUsage = 1 << 1, |
| + DecryptUsage = 1 << 2, |
| + SignUsage = 1 << 3, |
| + VerifyUsage = 1 << 4, |
| + DeriveKeyUsage = 1 << 5, |
| + WrapKeyUsage = 1 << 6, |
| + UnwrapKeyUsage = 1 << 7, |
| + // Maximum allowed value is 1 << 31 |
| +}; |
| + |
| static bool shouldCheckForCycles(int depth) |
| { |
| ASSERT(depth >= 0); |
| @@ -422,6 +482,39 @@ public: |
| doWriteFile(*fileList.item(i)); |
| } |
| + bool writeCryptoKey(const blink::WebCryptoKey& key, String& errorMessage) |
| + { |
| + append(static_cast<uint8_t>(CryptoKeyTag)); |
|
jsbell
2014/03/13 20:16:07
None of the other append(XXXXTag) calls bother wit
eroman
2014/03/14 05:24:33
I copied this from surrounding code where I see lo
|
| + |
| + switch (key.algorithm().paramsType()) { |
| + case blink::WebCryptoKeyAlgorithmParamsTypeAes: |
| + doWriteAesKey(key); |
| + break; |
| + case blink::WebCryptoKeyAlgorithmParamsTypeHmac: |
| + doWriteHmacKey(key); |
| + break; |
| + case blink::WebCryptoKeyAlgorithmParamsTypeRsa: |
| + case blink::WebCryptoKeyAlgorithmParamsTypeRsaHashed: |
| + doWriteRsaKey(key); |
| + break; |
| + case blink::WebCryptoKeyAlgorithmParamsTypeNone: |
| + ASSERT_NOT_REACHED(); |
| + return false; |
| + } |
| + |
| + doWriteKeyUsages(key.usages(), key.extractable()); |
| + |
| + blink::WebVector<uint8_t> keyData; |
| + if (!blink::Platform::current()->crypto()->serializeKeyForClone(key, keyData)) { |
| + errorMessage = "Couldn't export the key data"; |
| + return false; |
| + } |
| + |
| + doWriteUint32(keyData.size()); |
| + append(keyData.data(), keyData.size()); |
| + return true; |
| + } |
| + |
| void writeArrayBuffer(const ArrayBuffer& arrayBuffer) |
| { |
| append(ArrayBufferTag); |
| @@ -593,6 +686,115 @@ private: |
| doWriteString(stringUTF8.data(), stringUTF8.length()); |
| } |
| + void doWriteHmacKey(const blink::WebCryptoKey& key) |
| + { |
| + ASSERT(key.algorithm().paramsType() == blink::WebCryptoKeyAlgorithmParamsTypeHmac); |
| + |
| + append(static_cast<uint8_t>(HmacKeyTag)); |
| + doWriteAlgorithmId(key.algorithm().hmacParams()->hash().id()); |
| + } |
| + |
| + void doWriteAesKey(const blink::WebCryptoKey& key) |
| + { |
| + ASSERT(key.algorithm().paramsType() == blink::WebCryptoKeyAlgorithmParamsTypeAes); |
| + |
| + append(static_cast<uint8_t>(AesKeyTag)); |
| + doWriteAlgorithmId(key.algorithm().id()); |
| + // Converting the key length from bits to bytes is lossless and makes |
|
jsbell
2014/03/13 20:16:07
ASSERT((key.algorithm().aesParams()->lengthBits()
eroman
2014/03/14 05:24:33
Done.
|
| + // it fit in 1 byte. |
| + doWriteUint32(static_cast<uint8_t>(key.algorithm().aesParams()->lengthBits() / 8)); |
| + } |
| + |
| + void doWriteRsaKey(const blink::WebCryptoKey& key) |
| + { |
| + if (key.algorithm().rsaHashedParams()) |
| + append(static_cast<uint8_t>(RsaHashedKeyTag)); |
| + else |
| + append(static_cast<uint8_t>(RsaKeyTag)); |
| + |
| + doWriteAlgorithmId(key.algorithm().id()); |
| + |
| + switch (key.type()) { |
| + case blink::WebCryptoKeyTypePublic: |
| + doWriteUint32(PublicKeyType); |
| + break; |
| + case blink::WebCryptoKeyTypePrivate: |
| + doWriteUint32(PrivateKeyType); |
| + break; |
| + case blink::WebCryptoKeyTypeSecret: |
| + ASSERT_NOT_REACHED(); |
| + } |
| + |
| + const blink::WebCryptoRsaKeyAlgorithmParams* params = key.algorithm().rsaParams(); |
| + doWriteUint32(params->modulusLengthBits()); |
| + doWriteUint32(params->publicExponent().size()); |
| + append(params->publicExponent().data(), params->publicExponent().size()); |
| + |
| + if (key.algorithm().rsaHashedParams()) |
| + doWriteAlgorithmId(key.algorithm().rsaHashedParams()->hash().id()); |
| + } |
| + |
| + void doWriteAlgorithmId(blink::WebCryptoAlgorithmId id) |
| + { |
| + switch (id) { |
| + case blink::WebCryptoAlgorithmIdAesCbc: |
| + return doWriteUint32(AesCbcTag); |
| + case blink::WebCryptoAlgorithmIdHmac: |
| + return doWriteUint32(HmacTag); |
| + case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: |
| + return doWriteUint32(RsaSsaPkcs1v1_5Tag); |
| + case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5: |
| + return doWriteUint32(RsaEsPkcs1v1_5Tag); |
| + case blink::WebCryptoAlgorithmIdSha1: |
| + return doWriteUint32(Sha1Tag); |
| + case blink::WebCryptoAlgorithmIdSha224: |
| + return doWriteUint32(Sha224Tag); |
| + case blink::WebCryptoAlgorithmIdSha256: |
| + return doWriteUint32(Sha256Tag); |
| + case blink::WebCryptoAlgorithmIdSha384: |
| + return doWriteUint32(Sha384Tag); |
| + case blink::WebCryptoAlgorithmIdSha512: |
| + return doWriteUint32(Sha512Tag); |
| + case blink::WebCryptoAlgorithmIdAesGcm: |
| + return doWriteUint32(AesGcmTag); |
| + case blink::WebCryptoAlgorithmIdRsaOaep: |
| + return doWriteUint32(RsaOaepTag); |
| + case blink::WebCryptoAlgorithmIdAesCtr: |
| + return doWriteUint32(AesCtrTag); |
| + case blink::WebCryptoAlgorithmIdAesKw: |
| + return doWriteUint32(AesKwTag); |
| + } |
| + ASSERT_NOT_REACHED(); |
| + } |
| + |
| + void doWriteKeyUsages(const blink::WebCryptoKeyUsageMask usages, bool extractable) |
| + { |
| + // Reminder to update this when adding new key usages. |
| + COMPILE_ASSERT(blink::EndOfWebCryptoKeyUsage == (1 << 7) + 1, UpdateMe); |
| + |
| + uint32_t value = 0; |
| + |
| + if (extractable) |
| + value |= ExtractableUsage; |
| + |
| + if (usages & blink::WebCryptoKeyUsageEncrypt) |
| + value |= EncryptUsage; |
| + if (usages & blink::WebCryptoKeyUsageDecrypt) |
| + value |= DecryptUsage; |
| + if (usages & blink::WebCryptoKeyUsageSign) |
| + value |= SignUsage; |
| + if (usages & blink::WebCryptoKeyUsageVerify) |
| + value |= VerifyUsage; |
| + if (usages & blink::WebCryptoKeyUsageDeriveKey) |
| + value |= DeriveKeyUsage; |
| + if (usages & blink::WebCryptoKeyUsageWrapKey) |
| + value |= WrapKeyUsage; |
| + if (usages & blink::WebCryptoKeyUsageUnwrapKey) |
| + value |= UnwrapKeyUsage; |
| + |
| + doWriteUint32(value); |
| + } |
| + |
| int bytesNeededToWireEncode(uint32_t value) |
| { |
| int bytes = 1; |
| @@ -1098,6 +1300,18 @@ private: |
| m_blobDataHandles.add(fileList->item(i)->uuid(), fileList->item(i)->blobDataHandle()); |
| } |
| + StateBase* writeCryptoKey(v8::Handle<v8::Value> value, StateBase* next) |
| + { |
| + Key* key = V8Key::toNative(value.As<v8::Object>()); |
| + if (!key) |
| + return 0; |
| + |
| + String errorMessage; |
| + if (!m_writer.writeCryptoKey(key->key(), errorMessage)) |
| + return handleError(DataCloneError, errorMessage, next); |
| + return 0; |
| + } |
| + |
| void writeImageData(v8::Handle<v8::Value> value) |
| { |
| ImageData* imageData = V8ImageData::toNative(value.As<v8::Object>()); |
| @@ -1293,6 +1507,8 @@ Serializer::StateBase* Serializer::doSerialize(v8::Handle<v8::Value> value, Stat |
| return writeDOMFileSystem(value, next); |
| else if (V8FileList::hasInstance(value, m_isolate)) |
| writeFileList(value); |
| + else if (V8Key::hasInstance(value, m_isolate)) |
| + return writeCryptoKey(value, next); |
|
jsbell
2014/03/13 20:16:07
The only reason StateBase is passed to/returned fr
eroman
2014/03/14 05:24:33
Done.
|
| else if (V8ImageData::hasInstance(value, m_isolate)) |
| writeImageData(value); |
| else if (value->IsRegExp()) |
| @@ -1446,6 +1662,11 @@ public: |
| return false; |
| creator.pushObjectReference(*value); |
| break; |
| + case CryptoKeyTag: |
| + if (!readCryptoKey(value)) |
| + return false; |
| + creator.pushObjectReference(*value); |
| + break; |
| case ImageDataTag: |
| if (!readImageData(value)) |
| return false; |
| @@ -1909,6 +2130,62 @@ private: |
| return true; |
| } |
| + bool readCryptoKey(v8::Handle<v8::Value>* value) |
| + { |
| + uint32_t rawKeyType; |
| + if (!doReadUint32(&rawKeyType)) |
| + return false; |
| + |
| + blink::WebCryptoKeyAlgorithm algorithm; |
| + blink::WebCryptoKeyType type; |
| + |
| + switch (static_cast<CryptoKeySubTag>(rawKeyType)) { |
| + case AesKeyTag: |
| + if (!doReadAesKey(algorithm, type)) |
| + return false; |
| + break; |
| + case HmacKeyTag: |
| + if (!doReadHmacKey(algorithm, type)) |
| + return false; |
| + break; |
| + case RsaKeyTag: |
| + if (!doReadRsaKey(false, algorithm, type)) |
| + return false; |
| + break; |
| + case RsaHashedKeyTag: |
| + if (!doReadRsaKey(true, algorithm, type)) |
| + return false; |
| + break; |
| + default: |
| + return false; |
| + } |
| + |
| + blink::WebCryptoKeyUsageMask usages; |
| + bool extractable; |
| + if (!doReadKeyUsages(usages, extractable)) |
| + return false; |
| + |
| + uint32_t keyDataLength; |
| + if (!doReadUint32(&keyDataLength)) |
| + return false; |
| + |
| + if (m_position + keyDataLength > m_length) |
| + return false; |
| + |
| + const uint8_t* keyData = m_buffer + m_position; |
| + m_position += keyDataLength; |
| + |
| + blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
| + if (!blink::Platform::current()->crypto()->deserializeKeyForClone( |
| + algorithm, type, extractable, usages, keyData, keyDataLength, key)) { |
| + return false; |
| + } |
| + |
| + RefPtrWillBeRawPtr<Key> k = Key::create(key); |
| + *value = toV8(k.release(), v8::Handle<v8::Object>(), m_isolate); |
| + return true; |
| + } |
| + |
| PassRefPtrWillBeRawPtr<File> doReadFileHelper() |
| { |
| if (m_version < 3) |
| @@ -1998,6 +2275,161 @@ private: |
| return BlobDataHandle::create(uuid, type, size); |
| } |
| + bool doReadHmacKey(blink::WebCryptoKeyAlgorithm& algorithm, blink::WebCryptoKeyType& type) |
| + { |
| + blink::WebCryptoAlgorithmId hash; |
| + if (!doReadAlgorithmId(hash)) |
| + return false; |
| + algorithm = blink::WebCryptoKeyAlgorithm::createHmac(hash); |
| + type = blink::WebCryptoKeyTypeSecret; |
| + return !algorithm.isNull(); |
| + } |
| + |
| + bool doReadAesKey(blink::WebCryptoKeyAlgorithm& algorithm, blink::WebCryptoKeyType& type) |
| + { |
| + blink::WebCryptoAlgorithmId id; |
| + if (!doReadAlgorithmId(id)) |
| + return false; |
| + uint32_t lengthBytes; |
| + if (!doReadUint32(&lengthBytes)) |
| + return false; |
| + algorithm = blink::WebCryptoKeyAlgorithm::createAes(id, lengthBytes * 8); |
| + type = blink::WebCryptoKeyTypeSecret; |
| + return !algorithm.isNull(); |
| + } |
| + |
| + bool doReadRsaKey(bool hasHash, blink::WebCryptoKeyAlgorithm& algorithm, blink::WebCryptoKeyType& type) |
| + { |
| + blink::WebCryptoAlgorithmId id; |
| + if (!doReadAlgorithmId(id)) |
| + return false; |
| + |
| + uint32_t rawType; |
| + if (!doReadUint32(&rawType)) |
| + return false; |
| + |
| + switch (static_cast<AssymetricCryptoKeyType>(rawType)) { |
| + case PublicKeyType: |
| + type = blink::WebCryptoKeyTypePublic; |
| + break; |
| + case PrivateKeyType: |
| + type = blink::WebCryptoKeyTypePrivate; |
| + break; |
| + default: |
| + return false; |
| + } |
| + |
| + uint32_t modulusLengthBits; |
| + if (!doReadUint32(&modulusLengthBits)) |
| + return false; |
| + |
| + uint32_t publicExponentSize; |
| + if (!doReadUint32(&publicExponentSize)) |
| + return false; |
| + |
| + if (m_position + publicExponentSize > m_length) |
| + return false; |
| + |
| + const uint8_t* publicExponent = m_buffer + m_position; |
| + m_position += publicExponentSize; |
| + |
| + if (hasHash) { |
| + blink::WebCryptoAlgorithmId hash; |
| + if (!doReadAlgorithmId(hash)) |
| + return false; |
| + algorithm = blink::WebCryptoKeyAlgorithm::createRsaHashed(id, modulusLengthBits, publicExponent, publicExponentSize, hash); |
| + } else { |
| + algorithm = blink::WebCryptoKeyAlgorithm::createRsa(id, modulusLengthBits, publicExponent, publicExponentSize); |
| + } |
| + |
| + return !algorithm.isNull(); |
| + } |
| + |
| + bool doReadAlgorithmId(blink::WebCryptoAlgorithmId& id) |
| + { |
| + uint32_t rawId; |
| + if (!doReadUint32(&rawId)) |
| + return false; |
| + |
| + switch (static_cast<CryptoKeyAlgorithmTag>(rawId)) { |
| + case AesCbcTag: |
| + id = blink::WebCryptoAlgorithmIdAesCbc; |
| + return true; |
| + case HmacTag: |
| + id = blink::WebCryptoAlgorithmIdHmac; |
| + return true; |
| + case RsaSsaPkcs1v1_5Tag: |
| + id = blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5; |
| + return true; |
| + case RsaEsPkcs1v1_5Tag: |
| + id = blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5; |
| + return true; |
| + case Sha1Tag: |
| + id = blink::WebCryptoAlgorithmIdSha1; |
| + return true; |
| + case Sha224Tag: |
| + id = blink::WebCryptoAlgorithmIdSha224; |
| + return true; |
| + case Sha256Tag: |
| + id = blink::WebCryptoAlgorithmIdSha256; |
| + return true; |
| + case Sha384Tag: |
| + id = blink::WebCryptoAlgorithmIdSha384; |
| + return true; |
| + case Sha512Tag: |
| + id = blink::WebCryptoAlgorithmIdSha512; |
| + return true; |
| + case AesGcmTag: |
| + id = blink::WebCryptoAlgorithmIdAesGcm; |
| + return true; |
| + case RsaOaepTag: |
| + id = blink::WebCryptoAlgorithmIdRsaOaep; |
| + return true; |
| + case AesCtrTag: |
| + id = blink::WebCryptoAlgorithmIdAesCtr; |
| + return true; |
| + case AesKwTag: |
| + id = blink::WebCryptoAlgorithmIdAesKw; |
| + return true; |
| + } |
| + |
| + return false; |
| + } |
| + |
| + bool doReadKeyUsages(blink::WebCryptoKeyUsageMask& usages, bool& extractable) |
| + { |
| + // Reminder to update this when adding new key usages. |
| + COMPILE_ASSERT(blink::EndOfWebCryptoKeyUsage == (1 << 7) + 1, UpdateMe); |
| + |
| + uint32_t rawUsages; |
| + if (!doReadUint32(&rawUsages)) |
| + return false; |
| + |
| + usages = 0; |
| + |
| + extractable = rawUsages & ExtractableUsage; |
| + |
| + if (rawUsages & EncryptUsage) |
| + usages |= blink::WebCryptoKeyUsageEncrypt; |
| + if (rawUsages & DecryptUsage) |
| + usages |= blink::WebCryptoKeyUsageDecrypt; |
| + if (rawUsages & SignUsage) |
| + usages |= blink::WebCryptoKeyUsageSign; |
| + if (rawUsages & VerifyUsage) |
| + usages |= blink::WebCryptoKeyUsageVerify; |
| + if (rawUsages & DeriveKeyUsage) |
| + usages |= blink::WebCryptoKeyUsageDeriveKey; |
| + if (rawUsages & WrapKeyUsage) |
| + usages |= blink::WebCryptoKeyUsageWrapKey; |
| + if (rawUsages & UnwrapKeyUsage) |
| + usages |= blink::WebCryptoKeyUsageUnwrapKey; |
| + |
| + // Note that if the serialized data contained an unrecognized usage it |
| + // is silenty discarded here rather than erroring. |
|
jsbell
2014/03/13 20:16:07
Why? If that's the case, there could be subtle dif
eroman
2014/03/14 05:24:33
Done.
Sorry, it was laziness on my part.
Do you
jsbell
2014/03/14 16:33:46
I don't think we have those elsewhere. File a trac
|
| + |
| + return true; |
| + } |
| + |
| const uint8_t* m_buffer; |
| const unsigned m_length; |
| unsigned m_position; |