Index: Source/bindings/v8/SerializedScriptValue.cpp |
diff --git a/Source/bindings/v8/SerializedScriptValue.cpp b/Source/bindings/v8/SerializedScriptValue.cpp |
index dac52fa7e192b763ce6973b4ad172d6eee799c1e..18e6458e4640cd124fc0e428e7fae6d582366381 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 = keyLengthBytes:uint32_t, 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,51 @@ enum ArrayBufferViewSubTag { |
DataViewTag = '?' |
}; |
+enum CryptoKeySubTag { |
+ AesKeyTag = 1, |
+ HmacKeyTag = 2, |
+ RsaKeyTag = 3, |
+ RsaHashedKeyTag = 4, |
+ // Maximum allowed value is 255 |
+}; |
+ |
+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, |
+ Sha256Tag = 6, |
+ Sha384Tag = 7, |
+ Sha512Tag = 8, |
+ AesGcmTag = 9, |
+ RsaOaepTag = 10, |
+ AesCtrTag = 11, |
+ AesKwTag = 12, |
+ // 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 +481,37 @@ public: |
doWriteFile(*fileList.item(i)); |
} |
+ bool writeCryptoKey(const blink::WebCryptoKey& key) |
+ { |
+ append(static_cast<uint8_t>(CryptoKeyTag)); |
+ |
+ 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)) |
+ return false; |
+ |
+ doWriteUint32(keyData.size()); |
+ append(keyData.data(), keyData.size()); |
+ return true; |
+ } |
+ |
void writeArrayBuffer(const ArrayBuffer& arrayBuffer) |
{ |
append(ArrayBufferTag); |
@@ -593,6 +683,116 @@ private: |
doWriteString(stringUTF8.data(), stringUTF8.length()); |
} |
+ void doWriteHmacKey(const blink::WebCryptoKey& key) |
+ { |
+ ASSERT(key.algorithm().paramsType() == blink::WebCryptoKeyAlgorithmParamsTypeHmac); |
+ |
+ append(static_cast<uint8_t>(HmacKeyTag)); |
+ ASSERT(!(key.algorithm().hmacParams()->lengthBits() % 8)); |
+ doWriteUint32(key.algorithm().hmacParams()->lengthBits() / 8); |
+ 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 |
+ // it fit in 1 byte. |
+ ASSERT(!(key.algorithm().aesParams()->lengthBits() % 8)); |
+ doWriteUint32(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::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 << 6) + 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 +1298,14 @@ private: |
m_blobDataHandles.add(fileList->item(i)->uuid(), fileList->item(i)->blobDataHandle()); |
} |
+ bool writeCryptoKey(v8::Handle<v8::Value> value) |
+ { |
+ Key* key = V8Key::toNative(value.As<v8::Object>()); |
+ if (!key) |
+ return 0; |
+ return m_writer.writeCryptoKey(key->key()); |
+ } |
+ |
void writeImageData(v8::Handle<v8::Value> value) |
{ |
ImageData* imageData = V8ImageData::toNative(value.As<v8::Object>()); |
@@ -1293,7 +1501,10 @@ 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 (V8ImageData::hasInstance(value, m_isolate)) |
+ else if (V8Key::hasInstance(value, m_isolate)) { |
+ if (!writeCryptoKey(value)) |
+ return handleError(DataCloneError, "Couldn't serialize key data", next); |
+ } else if (V8ImageData::hasInstance(value, m_isolate)) |
writeImageData(value); |
else if (value->IsRegExp()) |
writeRegExp(value); |
@@ -1446,6 +1657,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 +2125,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 +2270,163 @@ private: |
return BlobDataHandle::create(uuid, type, size); |
} |
+ bool doReadHmacKey(blink::WebCryptoKeyAlgorithm& algorithm, blink::WebCryptoKeyType& type) |
+ { |
+ uint32_t lengthBytes; |
+ if (!doReadUint32(&lengthBytes)) |
+ return false; |
+ blink::WebCryptoAlgorithmId hash; |
+ if (!doReadAlgorithmId(hash)) |
+ return false; |
+ algorithm = blink::WebCryptoKeyAlgorithm::createHmac(hash, lengthBytes * 8); |
+ 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 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 << 6) + 1, UpdateMe); |
+ const uint32_t allPossibleUsages = ExtractableUsage | EncryptUsage | DecryptUsage | SignUsage | VerifyUsage | DeriveKeyUsage | WrapKeyUsage | UnwrapKeyUsage; |
+ |
+ uint32_t rawUsages; |
+ if (!doReadUint32(&rawUsages)) |
+ return false; |
+ |
+ // Make sure it doesn't contain an unrecognized usage value. |
+ if (rawUsages & ~allPossibleUsages) |
+ 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; |
+ |
+ return true; |
+ } |
+ |
const uint8_t* m_buffer; |
const unsigned m_length; |
unsigned m_position; |