blob: 50182cdafc96e88d8c8c48ca0e9efe4fc1c7c6b7 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "bindings/modules/v8/ScriptValueSerializerForModules.h"
#include "bindings/core/v8/SerializationTag.h"
#include "bindings/core/v8/V8Binding.h"
#include "bindings/modules/v8/V8CryptoKey.h"
#include "bindings/modules/v8/V8DOMFileSystem.h"
#include "modules/filesystem/DOMFileSystem.h"
#include "public/platform/Platform.h"
namespace blink {
enum CryptoKeyAlgorithmTag {
AesCbcTag = 1,
HmacTag = 2,
RsaSsaPkcs1v1_5Tag = 3,
// ID 4 was used by RsaEs, while still behind experimental flag.
Sha1Tag = 5,
Sha256Tag = 6,
Sha384Tag = 7,
Sha512Tag = 8,
AesGcmTag = 9,
RsaOaepTag = 10,
AesCtrTag = 11,
AesKwTag = 12,
RsaPssTag = 13,
EcdsaTag = 14,
EcdhTag = 15,
HkdfTag = 16,
Pbkdf2Tag = 17,
// Maximum allowed value is 2^32-1
};
enum NamedCurveTag {
P256Tag = 1,
P384Tag = 2,
P521Tag = 3,
};
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,
DeriveBitsUsage = 1 << 8,
// Maximum allowed value is 1 << 31
};
enum CryptoKeySubTag {
AesKeyTag = 1,
HmacKeyTag = 2,
// ID 3 was used by RsaKeyTag, while still behind experimental flag.
RsaHashedKeyTag = 4,
EcKeyTag = 5,
NoParamsKeyTag = 6,
// Maximum allowed value is 255
};
enum AssymetricCryptoKeyType {
PublicKeyType = 1,
PrivateKeyType = 2,
// Maximum allowed value is 2^32-1
};
ScriptValueSerializerForModules::ScriptValueSerializerForModules(SerializedScriptValueWriter& writer, const Transferables* transferables, WebBlobInfoArray* blobInfo, BlobDataHandleMap& blobDataHandles, v8::TryCatch& tryCatch, ScriptState* scriptState)
: ScriptValueSerializer(writer, transferables, blobInfo, blobDataHandles, tryCatch, scriptState)
{
}
ScriptValueSerializer::StateBase* ScriptValueSerializerForModules::writeDOMFileSystem(v8::Local<v8::Value> value, ScriptValueSerializer::StateBase* next)
{
DOMFileSystem* fs = V8DOMFileSystem::toImpl(value.As<v8::Object>());
if (!fs)
return 0;
if (!fs->clonable())
return handleError(DataCloneError, "A FileSystem object could not be cloned.", next);
toSerializedScriptValueWriterForModules(writer()).writeDOMFileSystem(fs->type(), fs->name(), fs->rootURL().getString());
return 0;
}
bool ScriptValueSerializerForModules::writeCryptoKey(v8::Local<v8::Value> value)
{
CryptoKey* key = V8CryptoKey::toImpl(value.As<v8::Object>());
if (!key)
return false;
return toSerializedScriptValueWriterForModules(writer()).writeCryptoKey(key->key());
}
void SerializedScriptValueWriterForModules::writeDOMFileSystem(int type, const String& name, const String& url)
{
append(DOMFileSystemTag);
doWriteUint32(type);
doWriteWebCoreString(name);
doWriteWebCoreString(url);
}
bool SerializedScriptValueWriterForModules::writeCryptoKey(const WebCryptoKey& key)
{
append(static_cast<uint8_t>(CryptoKeyTag));
switch (key.algorithm().paramsType()) {
case WebCryptoKeyAlgorithmParamsTypeAes:
doWriteAesKey(key);
break;
case WebCryptoKeyAlgorithmParamsTypeHmac:
doWriteHmacKey(key);
break;
case WebCryptoKeyAlgorithmParamsTypeRsaHashed:
doWriteRsaHashedKey(key);
break;
case WebCryptoKeyAlgorithmParamsTypeEc:
doWriteEcKey(key);
break;
case WebCryptoKeyAlgorithmParamsTypeNone:
doWriteKeyWithoutParams(key);
break;
}
doWriteKeyUsages(key.usages(), key.extractable());
WebVector<uint8_t> keyData;
if (!Platform::current()->crypto()->serializeKeyForClone(key, keyData))
return false;
doWriteUint32(keyData.size());
append(keyData.data(), keyData.size());
return true;
}
void SerializedScriptValueWriterForModules::doWriteHmacKey(const WebCryptoKey& key)
{
ASSERT(key.algorithm().paramsType() == 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 SerializedScriptValueWriterForModules::doWriteAesKey(const WebCryptoKey& key)
{
ASSERT(key.algorithm().paramsType() == 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 SerializedScriptValueWriterForModules::doWriteRsaHashedKey(const WebCryptoKey& key)
{
ASSERT(key.algorithm().rsaHashedParams());
append(static_cast<uint8_t>(RsaHashedKeyTag));
doWriteAlgorithmId(key.algorithm().id());
doWriteAsymmetricKeyType(key.type());
const WebCryptoRsaHashedKeyAlgorithmParams* params = key.algorithm().rsaHashedParams();
doWriteUint32(params->modulusLengthBits());
doWriteUint32(params->publicExponent().size());
append(params->publicExponent().data(), params->publicExponent().size());
doWriteAlgorithmId(params->hash().id());
}
void SerializedScriptValueWriterForModules::doWriteEcKey(const WebCryptoKey& key)
{
ASSERT(key.algorithm().ecParams());
append(static_cast<uint8_t>(EcKeyTag));
doWriteAlgorithmId(key.algorithm().id());
doWriteAsymmetricKeyType(key.type());
doWriteNamedCurve(key.algorithm().ecParams()->namedCurve());
}
void SerializedScriptValueWriterForModules::doWriteKeyWithoutParams(const WebCryptoKey& key)
{
ASSERT(WebCryptoAlgorithm::isKdf(key.algorithm().id()));
append(static_cast<uint8_t>(NoParamsKeyTag));
doWriteAlgorithmId(key.algorithm().id());
}
void SerializedScriptValueWriterForModules::doWriteAlgorithmId(WebCryptoAlgorithmId id)
{
switch (id) {
case WebCryptoAlgorithmIdAesCbc:
return doWriteUint32(AesCbcTag);
case WebCryptoAlgorithmIdHmac:
return doWriteUint32(HmacTag);
case WebCryptoAlgorithmIdRsaSsaPkcs1v1_5:
return doWriteUint32(RsaSsaPkcs1v1_5Tag);
case WebCryptoAlgorithmIdSha1:
return doWriteUint32(Sha1Tag);
case WebCryptoAlgorithmIdSha256:
return doWriteUint32(Sha256Tag);
case WebCryptoAlgorithmIdSha384:
return doWriteUint32(Sha384Tag);
case WebCryptoAlgorithmIdSha512:
return doWriteUint32(Sha512Tag);
case WebCryptoAlgorithmIdAesGcm:
return doWriteUint32(AesGcmTag);
case WebCryptoAlgorithmIdRsaOaep:
return doWriteUint32(RsaOaepTag);
case WebCryptoAlgorithmIdAesCtr:
return doWriteUint32(AesCtrTag);
case WebCryptoAlgorithmIdAesKw:
return doWriteUint32(AesKwTag);
case WebCryptoAlgorithmIdRsaPss:
return doWriteUint32(RsaPssTag);
case WebCryptoAlgorithmIdEcdsa:
return doWriteUint32(EcdsaTag);
case WebCryptoAlgorithmIdEcdh:
return doWriteUint32(EcdhTag);
case WebCryptoAlgorithmIdHkdf:
return doWriteUint32(HkdfTag);
case WebCryptoAlgorithmIdPbkdf2:
return doWriteUint32(Pbkdf2Tag);
}
ASSERT_NOT_REACHED();
}
void SerializedScriptValueWriterForModules::doWriteAsymmetricKeyType(WebCryptoKeyType keyType)
{
switch (keyType) {
case WebCryptoKeyTypePublic:
doWriteUint32(PublicKeyType);
break;
case WebCryptoKeyTypePrivate:
doWriteUint32(PrivateKeyType);
break;
case WebCryptoKeyTypeSecret:
ASSERT_NOT_REACHED();
}
}
void SerializedScriptValueWriterForModules::doWriteNamedCurve(WebCryptoNamedCurve namedCurve)
{
switch (namedCurve) {
case WebCryptoNamedCurveP256:
return doWriteUint32(P256Tag);
case WebCryptoNamedCurveP384:
return doWriteUint32(P384Tag);
case WebCryptoNamedCurveP521:
return doWriteUint32(P521Tag);
}
ASSERT_NOT_REACHED();
}
void SerializedScriptValueWriterForModules::doWriteKeyUsages(const WebCryptoKeyUsageMask usages, bool extractable)
{
// Reminder to update this when adding new key usages.
static_assert(EndOfWebCryptoKeyUsage == (1 << 7) + 1, "update required when adding new key usages");
uint32_t value = 0;
if (extractable)
value |= ExtractableUsage;
if (usages & WebCryptoKeyUsageEncrypt)
value |= EncryptUsage;
if (usages & WebCryptoKeyUsageDecrypt)
value |= DecryptUsage;
if (usages & WebCryptoKeyUsageSign)
value |= SignUsage;
if (usages & WebCryptoKeyUsageVerify)
value |= VerifyUsage;
if (usages & WebCryptoKeyUsageDeriveKey)
value |= DeriveKeyUsage;
if (usages & WebCryptoKeyUsageWrapKey)
value |= WrapKeyUsage;
if (usages & WebCryptoKeyUsageUnwrapKey)
value |= UnwrapKeyUsage;
if (usages & WebCryptoKeyUsageDeriveBits)
value |= DeriveBitsUsage;
doWriteUint32(value);
}
ScriptValueSerializer::StateBase* ScriptValueSerializerForModules::doSerializeValue(v8::Local<v8::Value> value, ScriptValueSerializer::StateBase* next)
{
bool isDOMFileSystem = V8DOMFileSystem::hasInstance(value, isolate());
if (isDOMFileSystem || V8CryptoKey::hasInstance(value, isolate())) {
v8::Local<v8::Object> jsObject = value.As<v8::Object>();
if (jsObject.IsEmpty())
return handleError(DataCloneError, "An object could not be cloned.", next);
greyObject(jsObject);
if (isDOMFileSystem)
return writeDOMFileSystem(value, next);
if (!writeCryptoKey(value))
return handleError(DataCloneError, "Couldn't serialize key data", next);
return 0;
}
return ScriptValueSerializer::doSerializeValue(value, next);
}
bool SerializedScriptValueReaderForModules::read(v8::Local<v8::Value>* value, ScriptValueCompositeCreator& creator)
{
SerializationTag tag;
if (!readTag(&tag))
return false;
switch (tag) {
case DOMFileSystemTag:
if (!readDOMFileSystem(value))
return false;
creator.pushObjectReference(*value);
break;
case CryptoKeyTag:
if (!readCryptoKey(value))
return false;
creator.pushObjectReference(*value);
break;
default:
return SerializedScriptValueReader::readWithTag(tag, value, creator);
}
return !value->IsEmpty();
}
bool SerializedScriptValueReaderForModules::readDOMFileSystem(v8::Local<v8::Value>* value)
{
uint32_t type;
String name;
String url;
if (!doReadUint32(&type))
return false;
if (!readWebCoreString(&name))
return false;
if (!readWebCoreString(&url))
return false;
DOMFileSystem* fs = DOMFileSystem::create(getScriptState()->getExecutionContext(), name, static_cast<FileSystemType>(type), KURL(ParsedURLString, url));
*value = toV8(fs, getScriptState()->context()->Global(), isolate());
return !value->IsEmpty();
}
bool SerializedScriptValueReaderForModules::readCryptoKey(v8::Local<v8::Value>* value)
{
uint32_t rawKeyType;
if (!doReadUint32(&rawKeyType))
return false;
WebCryptoKeyAlgorithm algorithm;
WebCryptoKeyType type = WebCryptoKeyTypeSecret;
switch (static_cast<CryptoKeySubTag>(rawKeyType)) {
case AesKeyTag:
if (!doReadAesKey(algorithm, type))
return false;
break;
case HmacKeyTag:
if (!doReadHmacKey(algorithm, type))
return false;
break;
case RsaHashedKeyTag:
if (!doReadRsaHashedKey(algorithm, type))
return false;
break;
case EcKeyTag:
if (!doReadEcKey(algorithm, type))
return false;
break;
case NoParamsKeyTag:
if (!doReadKeyWithoutParams(algorithm, type))
return false;
break;
default:
return false;
}
WebCryptoKeyUsageMask usages;
bool extractable;
if (!doReadKeyUsages(usages, extractable))
return false;
uint32_t keyDataLength;
if (!doReadUint32(&keyDataLength))
return false;
if (position() + keyDataLength > length())
return false;
const uint8_t* keyData = allocate(keyDataLength);
WebCryptoKey key = WebCryptoKey::createNull();
if (!Platform::current()->crypto()->deserializeKeyForClone(
algorithm, type, extractable, usages, keyData, keyDataLength, key)) {
return false;
}
*value = toV8(CryptoKey::create(key), getScriptState()->context()->Global(), isolate());
return !value->IsEmpty();
}
bool SerializedScriptValueReaderForModules::doReadHmacKey(WebCryptoKeyAlgorithm& algorithm, WebCryptoKeyType& type)
{
uint32_t lengthBytes;
if (!doReadUint32(&lengthBytes))
return false;
WebCryptoAlgorithmId hash;
if (!doReadAlgorithmId(hash))
return false;
algorithm = WebCryptoKeyAlgorithm::createHmac(hash, lengthBytes * 8);
type = WebCryptoKeyTypeSecret;
return !algorithm.isNull();
}
bool SerializedScriptValueReaderForModules::doReadAesKey(WebCryptoKeyAlgorithm& algorithm, WebCryptoKeyType& type)
{
WebCryptoAlgorithmId id;
if (!doReadAlgorithmId(id))
return false;
uint32_t lengthBytes;
if (!doReadUint32(&lengthBytes))
return false;
algorithm = WebCryptoKeyAlgorithm::createAes(id, lengthBytes * 8);
type = WebCryptoKeyTypeSecret;
return !algorithm.isNull();
}
bool SerializedScriptValueReaderForModules::doReadRsaHashedKey(WebCryptoKeyAlgorithm& algorithm, WebCryptoKeyType& type)
{
WebCryptoAlgorithmId id;
if (!doReadAlgorithmId(id))
return false;
if (!doReadAsymmetricKeyType(type))
return false;
uint32_t modulusLengthBits;
if (!doReadUint32(&modulusLengthBits))
return false;
uint32_t publicExponentSize;
if (!doReadUint32(&publicExponentSize))
return false;
if (position() + publicExponentSize > length())
return false;
const uint8_t* publicExponent = allocate(publicExponentSize);
WebCryptoAlgorithmId hash;
if (!doReadAlgorithmId(hash))
return false;
algorithm = WebCryptoKeyAlgorithm::createRsaHashed(id, modulusLengthBits, publicExponent, publicExponentSize, hash);
return !algorithm.isNull();
}
bool SerializedScriptValueReaderForModules::doReadEcKey(WebCryptoKeyAlgorithm& algorithm, WebCryptoKeyType& type)
{
WebCryptoAlgorithmId id;
if (!doReadAlgorithmId(id))
return false;
if (!doReadAsymmetricKeyType(type))
return false;
WebCryptoNamedCurve namedCurve;
if (!doReadNamedCurve(namedCurve))
return false;
algorithm = WebCryptoKeyAlgorithm::createEc(id, namedCurve);
return !algorithm.isNull();
}
bool SerializedScriptValueReaderForModules::doReadKeyWithoutParams(WebCryptoKeyAlgorithm& algorithm, WebCryptoKeyType& type)
{
WebCryptoAlgorithmId id;
if (!doReadAlgorithmId(id))
return false;
algorithm = WebCryptoKeyAlgorithm::createWithoutParams(id);
type = WebCryptoKeyTypeSecret;
return !algorithm.isNull();
}
bool SerializedScriptValueReaderForModules::doReadAlgorithmId(WebCryptoAlgorithmId& id)
{
uint32_t rawId;
if (!doReadUint32(&rawId))
return false;
switch (static_cast<CryptoKeyAlgorithmTag>(rawId)) {
case AesCbcTag:
id = WebCryptoAlgorithmIdAesCbc;
return true;
case HmacTag:
id = WebCryptoAlgorithmIdHmac;
return true;
case RsaSsaPkcs1v1_5Tag:
id = WebCryptoAlgorithmIdRsaSsaPkcs1v1_5;
return true;
case Sha1Tag:
id = WebCryptoAlgorithmIdSha1;
return true;
case Sha256Tag:
id = WebCryptoAlgorithmIdSha256;
return true;
case Sha384Tag:
id = WebCryptoAlgorithmIdSha384;
return true;
case Sha512Tag:
id = WebCryptoAlgorithmIdSha512;
return true;
case AesGcmTag:
id = WebCryptoAlgorithmIdAesGcm;
return true;
case RsaOaepTag:
id = WebCryptoAlgorithmIdRsaOaep;
return true;
case AesCtrTag:
id = WebCryptoAlgorithmIdAesCtr;
return true;
case AesKwTag:
id = WebCryptoAlgorithmIdAesKw;
return true;
case RsaPssTag:
id = WebCryptoAlgorithmIdRsaPss;
return true;
case EcdsaTag:
id = WebCryptoAlgorithmIdEcdsa;
return true;
case EcdhTag:
id = WebCryptoAlgorithmIdEcdh;
return true;
case HkdfTag:
id = WebCryptoAlgorithmIdHkdf;
return true;
case Pbkdf2Tag:
id = WebCryptoAlgorithmIdPbkdf2;
return true;
}
return false;
}
bool SerializedScriptValueReaderForModules::doReadAsymmetricKeyType(WebCryptoKeyType& type)
{
uint32_t rawType;
if (!doReadUint32(&rawType))
return false;
switch (static_cast<AssymetricCryptoKeyType>(rawType)) {
case PublicKeyType:
type = WebCryptoKeyTypePublic;
return true;
case PrivateKeyType:
type = WebCryptoKeyTypePrivate;
return true;
}
return false;
}
bool SerializedScriptValueReaderForModules::doReadNamedCurve(WebCryptoNamedCurve& namedCurve)
{
uint32_t rawName;
if (!doReadUint32(&rawName))
return false;
switch (static_cast<NamedCurveTag>(rawName)) {
case P256Tag:
namedCurve = WebCryptoNamedCurveP256;
return true;
case P384Tag:
namedCurve = WebCryptoNamedCurveP384;
return true;
case P521Tag:
namedCurve = WebCryptoNamedCurveP521;
return true;
}
return false;
}
bool SerializedScriptValueReaderForModules::doReadKeyUsages(WebCryptoKeyUsageMask& usages, bool& extractable)
{
// Reminder to update this when adding new key usages.
static_assert(EndOfWebCryptoKeyUsage == (1 << 7) + 1, "update required when adding new key usages");
const uint32_t allPossibleUsages = ExtractableUsage | EncryptUsage | DecryptUsage | SignUsage | VerifyUsage | DeriveKeyUsage | WrapKeyUsage | UnwrapKeyUsage | DeriveBitsUsage;
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 |= WebCryptoKeyUsageEncrypt;
if (rawUsages & DecryptUsage)
usages |= WebCryptoKeyUsageDecrypt;
if (rawUsages & SignUsage)
usages |= WebCryptoKeyUsageSign;
if (rawUsages & VerifyUsage)
usages |= WebCryptoKeyUsageVerify;
if (rawUsages & DeriveKeyUsage)
usages |= WebCryptoKeyUsageDeriveKey;
if (rawUsages & WrapKeyUsage)
usages |= WebCryptoKeyUsageWrapKey;
if (rawUsages & UnwrapKeyUsage)
usages |= WebCryptoKeyUsageUnwrapKey;
if (rawUsages & DeriveBitsUsage)
usages |= WebCryptoKeyUsageDeriveBits;
return true;
}
ScriptValueDeserializerForModules::ScriptValueDeserializerForModules(SerializedScriptValueReaderForModules& reader, MessagePortArray* messagePorts, ArrayBufferContentsArray* arrayBufferContents, ImageBitmapContentsArray* imageBitmapContents)
: ScriptValueDeserializer(reader, messagePorts, arrayBufferContents, imageBitmapContents)
{
}
bool ScriptValueDeserializerForModules::read(v8::Local<v8::Value>* value)
{
return toSerializedScriptValueReaderForModules(reader()).read(value, *this);
}
} // namespace blink