WebCrypto keys should support structured clone
https://bugs.webkit.org/show_bug.cgi?id=125590
Reviewed by Oliver Hunt.
Source/WebCore:
Tests: crypto/subtle/aes-postMessage.html
crypto/subtle/hmac-postMessage.html
crypto/subtle/postMessage-worker.html
crypto/subtle/rsa-postMessage.html
* crypto/CryptoAlgorithmIdentifier.h:
(WebCore::CryptoAlgorithmIdentifier):
* bindings/js/JSCryptoAlgorithmDictionary.cpp:
(WebCore::JSCryptoAlgorithmDictionary::createParametersForEncrypt):
(WebCore::JSCryptoAlgorithmDictionary::createParametersForDecrypt):
(WebCore::JSCryptoAlgorithmDictionary::createParametersForSign):
(WebCore::JSCryptoAlgorithmDictionary::createParametersForVerify):
(WebCore::JSCryptoAlgorithmDictionary::createParametersForDigest):
(WebCore::JSCryptoAlgorithmDictionary::createParametersForGenerateKey):
(WebCore::JSCryptoAlgorithmDictionary::createParametersForDeriveKey):
(WebCore::JSCryptoAlgorithmDictionary::createParametersForDeriveBits):
(WebCore::JSCryptoAlgorithmDictionary::createParametersForImportKey):
(WebCore::JSCryptoAlgorithmDictionary::createParametersForExportKey):
AES_KW was added to WebCrypto spec editor's draft yesterday night. Now that we're
adding a matching enum for structired clone serialization, it's as good a time as
any to update the order of values to match.
* bindings/js/SerializedScriptValue.cpp:
(WebCore::countUsages):
(WebCore::CloneSerializer::dumpIfTerminal):
(WebCore::CloneSerializer::write):
(WebCore::CloneDeserializer::read):
(WebCore::CloneDeserializer::readHMACKey):
(WebCore::CloneDeserializer::readAESKey):
(WebCore::CloneDeserializer::readRSAKey):
(WebCore::CloneDeserializer::readCryptoKey):
(WebCore::CloneDeserializer::readTerminal):
Added serialization/deserialization for CryptoKey. This doesn't update version
number, because we don't currently store structured clones in persistent storage -
and even if we did, we wouldn't want to invalidate everything users already stored.
* crypto/CryptoAlgorithmRegistry.cpp:
(WebCore::CryptoAlgorithmRegistry::shared):
(WebCore::registryMutex):
(WebCore::CryptoAlgorithmRegistry::getIdentifierForName):
(WebCore::CryptoAlgorithmRegistry::nameForIdentifier):
(WebCore::CryptoAlgorithmRegistry::create):
(WebCore::CryptoAlgorithmRegistry::registerAlgorithm):
* crypto/CryptoKey.idl:
With structured clone, it is now possible to send a Key to a web worker. That's
of no practical use because the crypto API is not exposed in workers, but we
shouldn't crash anyway.
* crypto/keys/CryptoKeyAES.cpp:
(WebCore::CryptoKeyAES::CryptoKeyAES):
(WebCore::CryptoKeyAES::isValidAESAlgorithm):
* crypto/keys/CryptoKeyAES.h:
Exposed isValidAESAlgorithm, so that a caller could know whether the constructor
will assert.
* CMakeLists.txt:
* GNUmakefile.am:
* WebCore.vcxproj/WebCore.vcxproj.filters:
* WebCore.vcxproj/WebCoreCommon.props:
Added crypto/keys to search paths to avoid build breakage.
LayoutTests:
* crypto/subtle/aes-postMessage-expected.txt: Added.
* crypto/subtle/aes-postMessage.html: Added.
* crypto/subtle/hmac-postMessage-expected.txt: Added.
* crypto/subtle/hmac-postMessage.html: Added.
* crypto/subtle/postMessage-worker-expected.txt: Added.
* crypto/subtle/postMessage-worker.html: Added.
* crypto/subtle/rsa-postMessage-expected.txt: Added.
* crypto/subtle/rsa-postMessage.html: Added.
* crypto/subtle/resources/postMessage-worker.js: Added.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@160455 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/bindings/js/SerializedScriptValue.cpp b/Source/WebCore/bindings/js/SerializedScriptValue.cpp
index 6f86c8b..26d8e3b 100644
--- a/Source/WebCore/bindings/js/SerializedScriptValue.cpp
+++ b/Source/WebCore/bindings/js/SerializedScriptValue.cpp
@@ -28,11 +28,17 @@
#include "SerializedScriptValue.h"
#include "Blob.h"
+#include "CryptoKeyAES.h"
+#include "CryptoKeyDataOctetSequence.h"
+#include "CryptoKeyDataRSAComponents.h"
+#include "CryptoKeyHMAC.h"
+#include "CryptoKeyRSA.h"
#include "ExceptionCode.h"
#include "File.h"
#include "FileList.h"
#include "ImageData.h"
#include "JSBlob.h"
+#include "JSCryptoKey.h"
#include "JSDOMGlobalObject.h"
#include "JSFile.h"
#include "JSFileList.h"
@@ -117,6 +123,9 @@
SetObjectTag = 29,
MapObjectTag = 30,
NonMapPropertiesTag = 31,
+#if ENABLE(SUBTLE_CRYPTO)
+ CryptoKeyTag = 32,
+#endif
ErrorTag = 255
};
@@ -156,6 +165,72 @@
}
+#if ENABLE(SUBTLE_CRYPTO)
+
+ENUM_CLASS(CryptoKeyClassSubtag) {
+ HMAC = 0,
+ AES = 1,
+ RSA = 2
+};
+const uint8_t cryptoKeyClassSubtagMaximumValue = 2;
+
+ENUM_CLASS(CryptoKeyAsymmetricTypeSubtag) {
+ Public = 0,
+ Private = 1
+};
+const uint8_t cryptoKeyAsymmetricTypeSubtagMaximumValue = 1;
+
+ENUM_CLASS(CryptoKeyUsageTag) {
+ Encrypt = 0,
+ Decrypt = 1,
+ Sign = 2,
+ Verify = 3,
+ DeriveKey = 4,
+ DeriveBits = 5,
+ WrapKey = 6,
+ UnwrapKey = 7
+};
+const uint8_t cryptoKeyUsageTagMaximumValue = 7;
+
+ENUM_CLASS(CryptoAlgorithmIdentifierTag) {
+ RSAES_PKCS1_v1_5 = 0,
+ RSASSA_PKCS1_v1_5 = 1,
+ RSA_PSS = 2,
+ RSA_OAEP = 3,
+ ECDSA = 4,
+ ECDH = 5,
+ AES_CTR = 6,
+ AES_CBC = 7,
+ AES_CMAC = 8,
+ AES_GCM = 9,
+ AES_CFB = 10,
+ AES_KW = 11,
+ HMAC = 12,
+ DH = 13,
+ SHA_1 = 14,
+ SHA_224 = 15,
+ SHA_256 = 16,
+ SHA_384 = 17,
+ SHA_512 = 18,
+ CONCAT = 19,
+ HKDF_CTR = 20,
+ PBKDF2 = 21,
+};
+const uint8_t cryptoAlgorithmIdentifierTagMaximumValue = 21;
+
+static unsigned countUsages(CryptoKeyUsage usages)
+{
+ // Fast bit count algorithm for sparse bit maps.
+ unsigned count = 0;
+ while (usages) {
+ usages = usages & (usages - 1);
+ ++count;
+ }
+ return count;
+}
+
+#endif
+
/* CurrentVersion tracks the serialization version so that persistent stores
* are able to correctly bail out in the case of encountering newer formats.
*
@@ -217,8 +292,9 @@
* | ObjectReference
* | MessagePortReferenceTag <value:uint32_t>
* | ArrayBuffer
- * | ArrayBufferViewTag ArrayBufferViewSubtag <byteOffset:uint32_t> <byteLenght:uint32_t> (ArrayBuffer | ObjectReference)
+ * | ArrayBufferViewTag ArrayBufferViewSubtag <byteOffset:uint32_t> <byteLength:uint32_t> (ArrayBuffer | ObjectReference)
* | ArrayBufferTransferTag <value:uint32_t>
+ * | CryptoKeyTag <extractable:int32_t> <usagesCount:uint32_t> <usages:byte{usagesCount}> CryptoKeyClassSubtag (CryptoKeyHMAC | CryptoKeyAES | CryptoKeyRSA)
*
* String :-
* EmptyStringTag
@@ -255,6 +331,28 @@
*
* ArrayBuffer :-
* ArrayBufferTag <length:uint32_t> <contents:byte{length}>
+ *
+ * CryptoKeyHMAC :-
+ * <keySize:uint32_t> <keyData:byte{keySize}> CryptoAlgorithmIdentifierTag // Algorithm tag inner hash function.
+ *
+ * CryptoKeyAES :-
+ * CryptoAlgorithmIdentifierTag <keySize:uint32_t> <keyData:byte{keySize}>
+ *
+ * CryptoKeyRSA :-
+ * CryptoAlgorithmIdentifierTag <isRestrictedToHash:int32_t> CryptoAlgorithmIdentifierTag? CryptoKeyAsymmetricTypeSubtag CryptoKeyRSAPublicComponents CryptoKeyRSAPrivateComponents?
+ *
+ * CryptoKeyRSAPublicComponents :-
+ * <modulusSize:uint32_t> <modulus:byte{modulusSize}> <exponentSize:uint32_t> <exponent:byte{exponentSize}>
+ *
+ * CryptoKeyRSAPrivateComponents :-
+ * <privateExponentSize:uint32_t> <privateExponent:byte{privateExponentSize}> <primeCount:uint32_t> FirstPrimeInfo? PrimeInfo{primeCount - 1}
+ *
+ * // CRT data could be computed from prime factors. It is only serialized to reuse a code path that's needed for JWK.
+ * FirstPrimeInfo :-
+ * <factorSize:uint32_t> <factor:byte{factorSize}> <crtExponentSize:uint32_t> <crtExponent:byte{crtExponentSize}>
+ *
+ * PrimeInfo :-
+ * <factorSize:uint32_t> <factor:byte{factorSize}> <crtExponentSize:uint32_t> <crtExponent:byte{crtExponentSize}> <crtCoefficientSize:uint32_t> <crtCoefficient:byte{crtCoefficientSize}>
*/
typedef pair<JSC::JSValue, SerializationReturnCode> DeserializationResult;
@@ -724,6 +822,13 @@
recordObject(obj);
return success;
}
+#if ENABLE(SUBTLE_CRYPTO)
+ if (CryptoKey* key = toCryptoKey(obj)) {
+ write(CryptoKeyTag);
+ write(key);
+ return true;
+ }
+#endif
return false;
}
@@ -742,6 +847,28 @@
writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
}
+#if ENABLE(SUBTLE_CRYPTO)
+ void write(CryptoKeyClassSubtag tag)
+ {
+ writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
+ }
+
+ void write(CryptoKeyAsymmetricTypeSubtag tag)
+ {
+ writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
+ }
+
+ void write(CryptoKeyUsageTag tag)
+ {
+ writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
+ }
+
+ void write(CryptoAlgorithmIdentifierTag tag)
+ {
+ writeLittleEndian<uint8_t>(m_buffer, static_cast<uint8_t>(tag));
+ }
+#endif
+
void write(uint8_t c)
{
writeLittleEndian(m_buffer, c);
@@ -834,6 +961,13 @@
write(Identifier(m_exec, str));
}
+ void write(const Vector<uint8_t>& vector)
+ {
+ uint32_t size = vector.size();
+ write(size);
+ writeLittleEndian(m_buffer, vector.data(), size);
+ }
+
void write(const File* file)
{
m_blobURLs.append(file->url());
@@ -842,6 +976,166 @@
write(file->type());
}
+#if ENABLE(SUBTLE_CRYPTO)
+ void write(CryptoAlgorithmIdentifier algorithm)
+ {
+ switch (algorithm) {
+ case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5:
+ write(CryptoAlgorithmIdentifierTag::RSAES_PKCS1_v1_5);
+ break;
+ case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5:
+ write(CryptoAlgorithmIdentifierTag::RSASSA_PKCS1_v1_5);
+ break;
+ case CryptoAlgorithmIdentifier::RSA_PSS:
+ write(CryptoAlgorithmIdentifierTag::RSA_PSS);
+ break;
+ case CryptoAlgorithmIdentifier::RSA_OAEP:
+ write(CryptoAlgorithmIdentifierTag::RSA_OAEP);
+ break;
+ case CryptoAlgorithmIdentifier::ECDSA:
+ write(CryptoAlgorithmIdentifierTag::ECDSA);
+ break;
+ case CryptoAlgorithmIdentifier::ECDH:
+ write(CryptoAlgorithmIdentifierTag::ECDH);
+ break;
+ case CryptoAlgorithmIdentifier::AES_CTR:
+ write(CryptoAlgorithmIdentifierTag::AES_CTR);
+ break;
+ case CryptoAlgorithmIdentifier::AES_CBC:
+ write(CryptoAlgorithmIdentifierTag::AES_CBC);
+ break;
+ case CryptoAlgorithmIdentifier::AES_CMAC:
+ write(CryptoAlgorithmIdentifierTag::AES_CMAC);
+ break;
+ case CryptoAlgorithmIdentifier::AES_GCM:
+ write(CryptoAlgorithmIdentifierTag::AES_GCM);
+ break;
+ case CryptoAlgorithmIdentifier::AES_CFB:
+ write(CryptoAlgorithmIdentifierTag::AES_CFB);
+ break;
+ case CryptoAlgorithmIdentifier::AES_KW:
+ write(CryptoAlgorithmIdentifierTag::AES_KW);
+ break;
+ case CryptoAlgorithmIdentifier::HMAC:
+ write(CryptoAlgorithmIdentifierTag::HMAC);
+ break;
+ case CryptoAlgorithmIdentifier::DH:
+ write(CryptoAlgorithmIdentifierTag::DH);
+ break;
+ case CryptoAlgorithmIdentifier::SHA_1:
+ write(CryptoAlgorithmIdentifierTag::SHA_1);
+ break;
+ case CryptoAlgorithmIdentifier::SHA_224:
+ write(CryptoAlgorithmIdentifierTag::SHA_224);
+ break;
+ case CryptoAlgorithmIdentifier::SHA_256:
+ write(CryptoAlgorithmIdentifierTag::SHA_256);
+ break;
+ case CryptoAlgorithmIdentifier::SHA_384:
+ write(CryptoAlgorithmIdentifierTag::SHA_384);
+ break;
+ case CryptoAlgorithmIdentifier::SHA_512:
+ write(CryptoAlgorithmIdentifierTag::SHA_512);
+ break;
+ case CryptoAlgorithmIdentifier::CONCAT:
+ write(CryptoAlgorithmIdentifierTag::CONCAT);
+ break;
+ case CryptoAlgorithmIdentifier::HKDF_CTR:
+ write(CryptoAlgorithmIdentifierTag::HKDF_CTR);
+ break;
+ case CryptoAlgorithmIdentifier::PBKDF2:
+ write(CryptoAlgorithmIdentifierTag::PBKDF2);
+ break;
+ }
+ }
+
+ void write(CryptoKeyDataRSAComponents::Type type)
+ {
+ switch (type) {
+ case CryptoKeyDataRSAComponents::Type::Public:
+ write(CryptoKeyAsymmetricTypeSubtag::Public);
+ return;
+ case CryptoKeyDataRSAComponents::Type::Private:
+ write(CryptoKeyAsymmetricTypeSubtag::Private);
+ return;
+ }
+ }
+
+ void write(const CryptoKeyDataRSAComponents& key)
+ {
+ write(key.type());
+ write(key.modulus());
+ write(key.exponent());
+ if (key.type() == CryptoKeyDataRSAComponents::Type::Public)
+ return;
+
+ write(key.privateExponent());
+
+ unsigned primeCount = key.hasAdditionalPrivateKeyParameters() ? key.otherPrimeInfos().size() + 2 : 0;
+ write(primeCount);
+ if (!primeCount)
+ return;
+
+ write(key.firstPrimeInfo().primeFactor);
+ write(key.firstPrimeInfo().factorCRTExponent);
+ write(key.secondPrimeInfo().primeFactor);
+ write(key.secondPrimeInfo().factorCRTExponent);
+ write(key.secondPrimeInfo().factorCRTCoefficient);
+ for (unsigned i = 2; i < primeCount; ++i) {
+ write(key.otherPrimeInfos()[i].primeFactor);
+ write(key.otherPrimeInfos()[i].factorCRTExponent);
+ write(key.otherPrimeInfos()[i].factorCRTCoefficient);
+ }
+ }
+
+ void write(const CryptoKey* key)
+ {
+ write(key->extractable());
+
+ CryptoKeyUsage usages = key->usagesBitmap();
+ write(countUsages(usages));
+ if (usages & CryptoKeyUsageEncrypt)
+ write(CryptoKeyUsageTag::Encrypt);
+ if (usages & CryptoKeyUsageDecrypt)
+ write(CryptoKeyUsageTag::Decrypt);
+ if (usages & CryptoKeyUsageSign)
+ write(CryptoKeyUsageTag::Sign);
+ if (usages & CryptoKeyUsageVerify)
+ write(CryptoKeyUsageTag::Verify);
+ if (usages & CryptoKeyUsageDeriveKey)
+ write(CryptoKeyUsageTag::DeriveKey);
+ if (usages & CryptoKeyUsageDeriveBits)
+ write(CryptoKeyUsageTag::DeriveBits);
+ if (usages & CryptoKeyUsageWrapKey)
+ write(CryptoKeyUsageTag::WrapKey);
+ if (usages & CryptoKeyUsageUnwrapKey)
+ write(CryptoKeyUsageTag::UnwrapKey);
+
+ switch (key->keyClass()) {
+ case CryptoKeyClass::HMAC:
+ write(CryptoKeyClassSubtag::HMAC);
+ write(toCryptoKeyHMAC(key)->key());
+ write(toCryptoKeyHMAC(key)->hashAlgorithmIdentifier());
+ break;
+ case CryptoKeyClass::AES:
+ write(CryptoKeyClassSubtag::AES);
+ write(key->algorithmIdentifier());
+ write(toCryptoKeyAES(key)->key());
+ break;
+ case CryptoKeyClass::RSA:
+ write(CryptoKeyClassSubtag::RSA);
+ write(key->algorithmIdentifier());
+ CryptoAlgorithmIdentifier hash;
+ bool isRestrictedToHash = toCryptoKeyRSA(key)->isRestrictedToHash(hash);
+ write(isRestrictedToHash);
+ if (isRestrictedToHash)
+ write(hash);
+ write(toCryptoKeyDataRSAComponents(*key->exportData()));
+ break;
+ }
+ }
+#endif
+
void write(const uint8_t* data, unsigned length)
{
m_buffer.append(data, length);
@@ -1453,6 +1747,307 @@
}
}
+ bool read(Vector<uint8_t>& result)
+ {
+ ASSERT(result.isEmpty());
+ uint32_t size;
+ if (!read(size))
+ return false;
+ if (m_ptr + size > m_end)
+ return false;
+ result.append(m_ptr, size);
+ m_ptr += size;
+ return true;
+ }
+
+#if ENABLE(SUBTLE_CRYPTO)
+ bool read(CryptoAlgorithmIdentifier& result)
+ {
+ uint8_t algorithmTag;
+ if (!read(algorithmTag))
+ return false;
+ if (algorithmTag > cryptoAlgorithmIdentifierTagMaximumValue)
+ return false;
+ switch (static_cast<CryptoAlgorithmIdentifierTag>(algorithmTag)) {
+ case CryptoAlgorithmIdentifierTag::RSAES_PKCS1_v1_5:
+ result = CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5;
+ break;
+ case CryptoAlgorithmIdentifierTag::RSASSA_PKCS1_v1_5:
+ result = CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5;
+ break;
+ case CryptoAlgorithmIdentifierTag::RSA_PSS:
+ result = CryptoAlgorithmIdentifier::RSA_PSS;
+ break;
+ case CryptoAlgorithmIdentifierTag::RSA_OAEP:
+ result = CryptoAlgorithmIdentifier::RSA_OAEP;
+ break;
+ case CryptoAlgorithmIdentifierTag::ECDSA:
+ result = CryptoAlgorithmIdentifier::ECDSA;
+ break;
+ case CryptoAlgorithmIdentifierTag::ECDH:
+ result = CryptoAlgorithmIdentifier::ECDH;
+ break;
+ case CryptoAlgorithmIdentifierTag::AES_CTR:
+ result = CryptoAlgorithmIdentifier::AES_CTR;
+ break;
+ case CryptoAlgorithmIdentifierTag::AES_CBC:
+ result = CryptoAlgorithmIdentifier::AES_CBC;
+ break;
+ case CryptoAlgorithmIdentifierTag::AES_CMAC:
+ result = CryptoAlgorithmIdentifier::AES_CMAC;
+ break;
+ case CryptoAlgorithmIdentifierTag::AES_GCM:
+ result = CryptoAlgorithmIdentifier::AES_GCM;
+ break;
+ case CryptoAlgorithmIdentifierTag::AES_CFB:
+ result = CryptoAlgorithmIdentifier::AES_CFB;
+ break;
+ case CryptoAlgorithmIdentifierTag::AES_KW:
+ result = CryptoAlgorithmIdentifier::AES_KW;
+ break;
+ case CryptoAlgorithmIdentifierTag::HMAC:
+ result = CryptoAlgorithmIdentifier::HMAC;
+ break;
+ case CryptoAlgorithmIdentifierTag::DH:
+ result = CryptoAlgorithmIdentifier::DH;
+ break;
+ case CryptoAlgorithmIdentifierTag::SHA_1:
+ result = CryptoAlgorithmIdentifier::SHA_1;
+ break;
+ case CryptoAlgorithmIdentifierTag::SHA_224:
+ result = CryptoAlgorithmIdentifier::SHA_224;
+ break;
+ case CryptoAlgorithmIdentifierTag::SHA_256:
+ result = CryptoAlgorithmIdentifier::SHA_256;
+ break;
+ case CryptoAlgorithmIdentifierTag::SHA_384:
+ result = CryptoAlgorithmIdentifier::SHA_384;
+ break;
+ case CryptoAlgorithmIdentifierTag::SHA_512:
+ result = CryptoAlgorithmIdentifier::SHA_512;
+ break;
+ case CryptoAlgorithmIdentifierTag::CONCAT:
+ result = CryptoAlgorithmIdentifier::CONCAT;
+ break;
+ case CryptoAlgorithmIdentifierTag::HKDF_CTR:
+ result = CryptoAlgorithmIdentifier::HKDF_CTR;
+ break;
+ case CryptoAlgorithmIdentifierTag::PBKDF2:
+ result = CryptoAlgorithmIdentifier::PBKDF2;
+ break;
+ }
+ return true;
+ }
+
+ bool read(CryptoKeyClassSubtag& result)
+ {
+ uint8_t tag;
+ if (!read(tag))
+ return false;
+ if (tag > cryptoKeyClassSubtagMaximumValue)
+ return false;
+ result = static_cast<CryptoKeyClassSubtag>(tag);
+ return true;
+ }
+
+ bool read(CryptoKeyUsageTag& result)
+ {
+ uint8_t tag;
+ if (!read(tag))
+ return false;
+ if (tag > cryptoKeyUsageTagMaximumValue)
+ return false;
+ result = static_cast<CryptoKeyUsageTag>(tag);
+ return true;
+ }
+
+ bool read(CryptoKeyAsymmetricTypeSubtag& result)
+ {
+ uint8_t tag;
+ if (!read(tag))
+ return false;
+ if (tag > cryptoKeyAsymmetricTypeSubtagMaximumValue)
+ return false;
+ result = static_cast<CryptoKeyAsymmetricTypeSubtag>(tag);
+ return true;
+ }
+
+ bool readHMACKey(bool extractable, CryptoKeyUsage usages, RefPtr<CryptoKey>& result)
+ {
+ Vector<uint8_t> keyData;
+ if (!read(keyData))
+ return false;
+ CryptoAlgorithmIdentifier hash;
+ if (!read(hash))
+ return false;
+ result = CryptoKeyHMAC::create(keyData, hash, extractable, usages);
+ return true;
+ }
+
+ bool readAESKey(bool extractable, CryptoKeyUsage usages, RefPtr<CryptoKey>& result)
+ {
+ CryptoAlgorithmIdentifier algorithm;
+ if (!read(algorithm))
+ return false;
+ if (!CryptoKeyAES::isValidAESAlgorithm(algorithm))
+ return false;
+ Vector<uint8_t> keyData;
+ if (!read(keyData))
+ return false;
+ result = CryptoKeyAES::create(algorithm, keyData, extractable, usages);
+ return true;
+ }
+
+ bool readRSAKey(bool extractable, CryptoKeyUsage usages, RefPtr<CryptoKey>& result)
+ {
+ CryptoAlgorithmIdentifier algorithm;
+ if (!read(algorithm))
+ return false;
+
+ int32_t isRestrictedToHash;
+ CryptoAlgorithmIdentifier hash;
+ if (!read(isRestrictedToHash))
+ return false;
+ if (isRestrictedToHash && !read(hash))
+ return false;
+
+ CryptoKeyAsymmetricTypeSubtag type;
+ if (!read(type))
+ return false;
+
+ Vector<uint8_t> modulus;
+ if (!read(modulus))
+ return false;
+ Vector<uint8_t> exponent;
+ if (!read(exponent))
+ return false;
+
+ if (type == CryptoKeyAsymmetricTypeSubtag::Public) {
+ auto keyData = CryptoKeyDataRSAComponents::createPublic(modulus, exponent);
+ auto key = CryptoKeyRSA::create(algorithm, *keyData, extractable, usages);
+ if (isRestrictedToHash)
+ key->restrictToHash(hash);
+ result = std::move(key);
+ return true;
+ }
+
+ Vector<uint8_t> privateExponent;
+ if (!read(privateExponent))
+ return false;
+
+ uint32_t primeCount;
+ if (!read(primeCount))
+ return false;
+
+ if (!primeCount) {
+ auto keyData = CryptoKeyDataRSAComponents::createPrivate(modulus, exponent, privateExponent);
+ auto key = CryptoKeyRSA::create(algorithm, *keyData, extractable, usages);
+ if (isRestrictedToHash)
+ key->restrictToHash(hash);
+ result = std::move(key);
+ return true;
+ }
+
+ if (primeCount < 2)
+ return false;
+
+ CryptoKeyDataRSAComponents::PrimeInfo firstPrimeInfo;
+ CryptoKeyDataRSAComponents::PrimeInfo secondPrimeInfo;
+ Vector<CryptoKeyDataRSAComponents::PrimeInfo> otherPrimeInfos(primeCount - 2);
+
+ if (!read(firstPrimeInfo.primeFactor))
+ return false;
+ if (!read(firstPrimeInfo.factorCRTExponent))
+ return false;
+ if (!read(secondPrimeInfo.primeFactor))
+ return false;
+ if (!read(secondPrimeInfo.factorCRTExponent))
+ return false;
+ if (!read(secondPrimeInfo.factorCRTCoefficient))
+ return false;
+ for (unsigned i = 2; i < primeCount; ++i) {
+ if (!read(otherPrimeInfos[i].primeFactor))
+ return false;
+ if (!read(otherPrimeInfos[i].factorCRTExponent))
+ return false;
+ if (!read(otherPrimeInfos[i].factorCRTCoefficient))
+ return false;
+ }
+
+ auto keyData = CryptoKeyDataRSAComponents::createPrivateWithAdditionalData(modulus, exponent, privateExponent, firstPrimeInfo, secondPrimeInfo, otherPrimeInfos);
+ auto key = CryptoKeyRSA::create(algorithm, *keyData, extractable, usages);
+ if (isRestrictedToHash)
+ key->restrictToHash(hash);
+ result = std::move(key);
+ return true;
+ }
+
+ bool readCryptoKey(JSValue& cryptoKey)
+ {
+ int32_t extractable;
+ if (!read(extractable))
+ return false;
+
+ uint32_t usagesCount;
+ if (!read(usagesCount))
+ return false;
+
+ CryptoKeyUsage usages = 0;
+ for (uint32_t i = 0; i < usagesCount; ++i) {
+ CryptoKeyUsageTag usage;
+ if (!read(usage))
+ return false;
+ switch (usage) {
+ case CryptoKeyUsageTag::Encrypt:
+ usages |= CryptoKeyUsageEncrypt;
+ break;
+ case CryptoKeyUsageTag::Decrypt:
+ usages |= CryptoKeyUsageDecrypt;
+ break;
+ case CryptoKeyUsageTag::Sign:
+ usages |= CryptoKeyUsageSign;
+ break;
+ case CryptoKeyUsageTag::Verify:
+ usages |= CryptoKeyUsageVerify;
+ break;
+ case CryptoKeyUsageTag::DeriveKey:
+ usages |= CryptoKeyUsageDeriveKey;
+ break;
+ case CryptoKeyUsageTag::DeriveBits:
+ usages |= CryptoKeyUsageDeriveBits;
+ break;
+ case CryptoKeyUsageTag::WrapKey:
+ usages |= CryptoKeyUsageWrapKey;
+ break;
+ case CryptoKeyUsageTag::UnwrapKey:
+ usages |= CryptoKeyUsageUnwrapKey;
+ break;
+ }
+ }
+
+ CryptoKeyClassSubtag cryptoKeyClass;
+ if (!read(cryptoKeyClass))
+ return false;
+ RefPtr<CryptoKey> result;
+ switch (cryptoKeyClass) {
+ case CryptoKeyClassSubtag::HMAC:
+ if (!readHMACKey(extractable, usages, result))
+ return false;
+ break;
+ case CryptoKeyClassSubtag::AES:
+ if (!readAESKey(extractable, usages, result))
+ return false;
+ break;
+ case CryptoKeyClassSubtag::RSA:
+ if (!readRSAKey(extractable, usages, result))
+ return false;
+ break;
+ }
+ cryptoKey = getJSValue(result.get());
+ return true;
+ }
+#endif
+
template<class T>
JSValue getJSValue(T* nativeObj)
{
@@ -1658,6 +2253,17 @@
m_gcBuffer.append(arrayBufferView);
return arrayBufferView;
}
+#if ENABLE(SUBTLE_CRYPTO)
+ case CryptoKeyTag: {
+ JSValue cryptoKey;
+ if (!readCryptoKey(cryptoKey)) {
+ fail();
+ return JSValue();
+ }
+ m_gcBuffer.append(cryptoKey);
+ return cryptoKey;
+ }
+#endif
default:
m_ptr--; // Push the tag back
return JSValue();