Commit 19cf70fd authored by ap@apple.com's avatar ap@apple.com

Implement WebCrypto unwrapKey

https://bugs.webkit.org/show_bug.cgi?id=124725

Reviewed by Anders Carlsson.

Source/WebCore: 

Tests: crypto/subtle/aes-cbc-unwrap-failure.html
       crypto/subtle/aes-cbc-unwrap-rsa.html

* bindings/js/JSCryptoAlgorithmDictionary.cpp:
* bindings/js/JSCryptoAlgorithmDictionary.h:
Removed calls for wrap/unwrap parameter parsing, these are just the same as encrypt/decrypt.

* bindings/js/JSCryptoOperationData.cpp:
(WebCore::cryptoOperationDataFromJSValue):
* bindings/js/JSCryptoOperationData.h:
* crypto/CryptoKeySerialization.h:
More Vector<char> elimination.

* bindings/js/JSDOMPromise.cpp:
* bindings/js/JSDOMPromise.h:
Removed unneccessary copy constructor and assignment operator, they are no diffdrent
than compiler generated ones.

* bindings/js/JSSubtleCryptoCustom.cpp:
(WebCore::cryptoKeyUsagesFromJSValue): Minor style fixes.
(WebCore::JSSubtleCrypto::encrypt): Ditto.
(WebCore::JSSubtleCrypto::decrypt): Ditto.
(WebCore::JSSubtleCrypto::sign): Ditto.
(WebCore::JSSubtleCrypto::verify): Ditto.
(WebCore::JSSubtleCrypto::generateKey): Ditto.
(WebCore::importKey): Separated actual import operation and the parts that read
arguments from ExecState, and call the promise. Logically, this should be outside
of bindings code even, but JWK makes that quite challenging.
(WebCore::JSSubtleCrypto::importKey): This only does the more mundane arguments
and return parts now.
(WebCore::JSSubtleCrypto::exportKey): Minor style fixes.
(WebCore::JSSubtleCrypto::unwrapKey): Chain decrypt and import.

* crypto/CryptoAlgorithm.cpp:
(WebCore::CryptoAlgorithm::encryptForWrapKey):
(WebCore::CryptoAlgorithm::decryptForUnwrapKey):
* crypto/CryptoAlgorithm.h:
There are algorithms that expose wrap/unwrap, but not encrypt/decrypt. These will
override these new functions, and leave encrypt/decrypt to raise NOT_SUPPORTED_ERR.

* crypto/SubtleCrypto.idl: Added unwrapKey.

LayoutTests: 

* crypto/subtle/aes-cbc-unwrap-failure-expected.txt: Added.
* crypto/subtle/aes-cbc-unwrap-failure.html: Added.
* crypto/subtle/aes-cbc-unwrap-rsa-expected.txt: Added.
* crypto/subtle/aes-cbc-unwrap-rsa.html: Added.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@159637 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent f3a4f0a7
2013-11-21 Alexey Proskuryakov <ap@apple.com>
Implement WebCrypto unwrapKey
https://bugs.webkit.org/show_bug.cgi?id=124725
Reviewed by Anders Carlsson.
* crypto/subtle/aes-cbc-unwrap-failure-expected.txt: Added.
* crypto/subtle/aes-cbc-unwrap-failure.html: Added.
* crypto/subtle/aes-cbc-unwrap-rsa-expected.txt: Added.
* crypto/subtle/aes-cbc-unwrap-rsa.html: Added.
2013-11-21 Radu Stavila <stavila@adobe.com>
Added test for the overflow of a region being painted across multiple tiles.
......
Test unwrapping an RSA key with AES-CBC.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
Importing an unwrapping key...
PASS unwrappingKey.algorithm.name is 'aes-cbc'
Unwrapping a key...
PASS Promise rejected
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE html>
<html>
<head>
<script src="../../resources/js-test-pre.js"></script>
<script src="resources/common.js"></script>
</head>
<body>
<p id="description"></p>
<div id="console"></div>
<script>
description("Test unwrapping an RSA key with AES-CBC.");
jsTestIsAsync = true;
var extractable = true;
var nonExtractable = false;
var unwrappingKeyOctets = hexStringToUint8Array("2a00e0e776e94e4dc89bf947cebdebe1");
var wrappedKey = hexStringToUint8Array("b490dedb3abc3fd545e146538e6cc3ca"); // An empty encrypted JSON.
debug("Importing an unwrapping key...");
crypto.subtle.importKey("raw", unwrappingKeyOctets, "AES-CBC", nonExtractable, ["unwrapKey"]).then(function(result) {
unwrappingKey = result;
shouldBe("unwrappingKey.algorithm.name", "'aes-cbc'");
var unwrapAlgorithm = {name: "AES-CBC", iv: hexStringToUint8Array("000102030405060708090a0b0c0d0e0f")};
debug("Unwrapping a key...");
return crypto.subtle.unwrapKey("jwk", wrappedKey, unwrappingKey, unwrapAlgorithm, null, extractable, ["sign", "verify", "encrypt", "decrypt", "wrap", "unwrap"]);
}).then(undefined, function(result) {
testPassed("Promise rejected");
finishJSTest();
});
</script>
<script src="../../resources/js-test-post.js"></script>
</body>
</html>
Test unwrapping an RSA key with AES-CBC.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
Importing an unwrapping key...
PASS unwrappingKey.algorithm.name is 'aes-cbc'
Unwrapping a key...
PASS unwrappedKey.toString() is '[object Key]'
PASS unwrappedKey.type is 'public'
PASS unwrappedKey.usages is ['sign','verify']
PASS unwrappedKey.algorithm.name is 'rsassa-pkcs1-v1_5'
PASS unwrappedKey.algorithm.modulusLength is 2048
PASS Base64URL.stringify(unwrappedKey.algorithm.publicExponent) is publicKeyJSON.e
PASS unwrappedKey.algorithm.hash.name is 'sha-256'
PASS unwrappedKey.extractable is false
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE html>
<html>
<head>
<script src="../../resources/js-test-pre.js"></script>
<script src="resources/common.js"></script>
</head>
<body>
<p id="description"></p>
<div id="console"></div>
<script>
description("Test unwrapping an RSA key with AES-CBC.");
jsTestIsAsync = true;
var extractable = true;
var nonExtractable = false;
var publicKeyJSON = {
kty: "RSA",
alg: "RS256",
n: "rcCUCv7Oc1HVam1DIhCzqknThWawOp8QLk8Ziy2p10ByjQFCajoFiyuAWl-R1WXZaf4xitLRracT9agpzIzc-MbLSHIGgWQGO21lGiImy5ftZ-D8bHAqRz2y15pzD4c4CEou7XSSLDoRnR0QG5MsDhD6s2gV9mwHkrtkCxtMWdBi-77as8wGmlNRldcOSgZDLK8UnCSgA1OguZ989bFyc8tOOEIb0xUSfPSz3LPSCnyYz68aDjmKVeNH-ig857OScyWbGyEy3Biw64qun3juUlNWsJ3zngkOdteYWytx5Qr4XKNs6R-Myyq72KUp02mJDZiiyiglxML_i3-_CeecCw",
e: "AQAB",
extractable: false,
use: "sig"
};
var unwrappingKeyOctets = hexStringToUint8Array("2a00e0e776e94e4dc89bf947cebdebe1");
var wrappedKey = hexStringToUint8Array("3511f6028db04ea97e7cfad3c4cc60837bceff25cb6c88292fbcb4547570afdc32e4003fe4d65f1e7df60dc1fdb3df36c3f58ab228e33aa31005852d46d0c2ad1318435a071bbb5bbb05650ea63d551698b0c040dd95ed0d379b5e2eccb545ae5620acb8051174cd2ad647328ad99dcd462fec40748724eb1e68f209f779faa2c35b4d4d1b6604a74e62a1846249ea6192954a5af10c71ebfea79948142441ed307e9f52e797a51a8007a6f87b57c51f9e7eef54b7e4a1f818ba6ac25ee5935c23b3253d6d9d222262c79ccdb7147d9c07527c22fe7a4ab91af20479edf5930b3c053c0a0b27092cfb53203633d01dcf6e333b5be7c1933c321c953f962b934ebefd9df8cca6c0a25fcd5fb96105435c42d9902406f82bc8daa8ec12fa85d9afa65adbfe3f60828ef64adaf43ad8e3b0af104cbfafd994323732bba08f84d5cac1d157b276233dffecafe47942b83c85ead6d5886c6badf534d4a32d3f545e8032dd5e419d7bff3acde2c37a96fc34fda8747d89500bf9f7ef45873c6b3b274197c184fe91badeeddf5045f982ecc66b61e0c4d75fd496c61ffcbb36e079faf20aa0c05cd12742aefdf1f6a39c4a9c5a");
debug("Importing an unwrapping key...");
crypto.subtle.importKey("raw", unwrappingKeyOctets, "AES-CBC", nonExtractable, ["unwrapKey"]).then(function(result) {
unwrappingKey = result;
shouldBe("unwrappingKey.algorithm.name", "'aes-cbc'");
var unwrapAlgorithm = {name: "AES-CBC", iv: hexStringToUint8Array("000102030405060708090a0b0c0d0e0f")};
debug("Unwrapping a key...");
return crypto.subtle.unwrapKey("jwk", wrappedKey, unwrappingKey, unwrapAlgorithm, null, extractable, ["sign", "verify", "encrypt", "decrypt", "wrap", "unwrap"]);
}).then(function(result) {
unwrappedKey = result;
shouldBe("unwrappedKey.toString()", "'[object Key]'");
shouldBe("unwrappedKey.type", "'public'");
shouldBe("unwrappedKey.usages", "['sign','verify']");
shouldBe("unwrappedKey.algorithm.name", "'rsassa-pkcs1-v1_5'");
shouldBe("unwrappedKey.algorithm.modulusLength", "2048");
shouldBe("Base64URL.stringify(unwrappedKey.algorithm.publicExponent)", "publicKeyJSON.e");
shouldBe("unwrappedKey.algorithm.hash.name", "'sha-256'");
shouldBe("unwrappedKey.extractable", "false");
finishJSTest();
});
</script>
<script src="../../resources/js-test-post.js"></script>
</body>
</html>
2013-11-21 Alexey Proskuryakov <ap@apple.com>
Implement WebCrypto unwrapKey
https://bugs.webkit.org/show_bug.cgi?id=124725
Reviewed by Anders Carlsson.
Tests: crypto/subtle/aes-cbc-unwrap-failure.html
crypto/subtle/aes-cbc-unwrap-rsa.html
* bindings/js/JSCryptoAlgorithmDictionary.cpp:
* bindings/js/JSCryptoAlgorithmDictionary.h:
Removed calls for wrap/unwrap parameter parsing, these are just the same as encrypt/decrypt.
* bindings/js/JSCryptoOperationData.cpp:
(WebCore::cryptoOperationDataFromJSValue):
* bindings/js/JSCryptoOperationData.h:
* crypto/CryptoKeySerialization.h:
More Vector<char> elimination.
* bindings/js/JSDOMPromise.cpp:
* bindings/js/JSDOMPromise.h:
Removed unneccessary copy constructor and assignment operator, they are no diffdrent
than compiler generated ones.
* bindings/js/JSSubtleCryptoCustom.cpp:
(WebCore::cryptoKeyUsagesFromJSValue): Minor style fixes.
(WebCore::JSSubtleCrypto::encrypt): Ditto.
(WebCore::JSSubtleCrypto::decrypt): Ditto.
(WebCore::JSSubtleCrypto::sign): Ditto.
(WebCore::JSSubtleCrypto::verify): Ditto.
(WebCore::JSSubtleCrypto::generateKey): Ditto.
(WebCore::importKey): Separated actual import operation and the parts that read
arguments from ExecState, and call the promise. Logically, this should be outside
of bindings code even, but JWK makes that quite challenging.
(WebCore::JSSubtleCrypto::importKey): This only does the more mundane arguments
and return parts now.
(WebCore::JSSubtleCrypto::exportKey): Minor style fixes.
(WebCore::JSSubtleCrypto::unwrapKey): Chain decrypt and import.
* crypto/CryptoAlgorithm.cpp:
(WebCore::CryptoAlgorithm::encryptForWrapKey):
(WebCore::CryptoAlgorithm::decryptForUnwrapKey):
* crypto/CryptoAlgorithm.h:
There are algorithms that expose wrap/unwrap, but not encrypt/decrypt. These will
override these new functions, and leave encrypt/decrypt to raise NOT_SUPPORTED_ERR.
* crypto/SubtleCrypto.idl: Added unwrapKey.
2013-11-21 Robert Sipka <sipka@inf.u-szeged.hu>
[curl]Improve ssl certificate storage and check
......@@ -584,64 +584,6 @@ std::unique_ptr<CryptoAlgorithmParameters> JSCryptoAlgorithmDictionary::createPa
}
}
std::unique_ptr<CryptoAlgorithmParameters> JSCryptoAlgorithmDictionary::createParametersForWrapKey(ExecState* exec, CryptoAlgorithmIdentifier algorithm, JSValue)
{
switch (algorithm) {
case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5:
case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5:
case CryptoAlgorithmIdentifier::RSA_PSS:
case CryptoAlgorithmIdentifier::RSA_OAEP:
case CryptoAlgorithmIdentifier::ECDSA:
case CryptoAlgorithmIdentifier::ECDH:
case CryptoAlgorithmIdentifier::AES_CTR:
case CryptoAlgorithmIdentifier::AES_CBC:
case CryptoAlgorithmIdentifier::AES_CMAC:
case CryptoAlgorithmIdentifier::AES_GCM:
case CryptoAlgorithmIdentifier::AES_CFB:
case CryptoAlgorithmIdentifier::HMAC:
case CryptoAlgorithmIdentifier::DH:
case CryptoAlgorithmIdentifier::SHA_1:
case CryptoAlgorithmIdentifier::SHA_224:
case CryptoAlgorithmIdentifier::SHA_256:
case CryptoAlgorithmIdentifier::SHA_384:
case CryptoAlgorithmIdentifier::SHA_512:
case CryptoAlgorithmIdentifier::CONCAT:
case CryptoAlgorithmIdentifier::HKDF_CTR:
case CryptoAlgorithmIdentifier::PBKDF2:
setDOMException(exec, NOT_SUPPORTED_ERR);
return nullptr;
}
}
std::unique_ptr<CryptoAlgorithmParameters> JSCryptoAlgorithmDictionary::createParametersForUnwrapKey(ExecState* exec, CryptoAlgorithmIdentifier algorithm, JSValue)
{
switch (algorithm) {
case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5:
case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5:
case CryptoAlgorithmIdentifier::RSA_PSS:
case CryptoAlgorithmIdentifier::RSA_OAEP:
case CryptoAlgorithmIdentifier::ECDSA:
case CryptoAlgorithmIdentifier::ECDH:
case CryptoAlgorithmIdentifier::AES_CTR:
case CryptoAlgorithmIdentifier::AES_CBC:
case CryptoAlgorithmIdentifier::AES_CMAC:
case CryptoAlgorithmIdentifier::AES_GCM:
case CryptoAlgorithmIdentifier::AES_CFB:
case CryptoAlgorithmIdentifier::HMAC:
case CryptoAlgorithmIdentifier::DH:
case CryptoAlgorithmIdentifier::SHA_1:
case CryptoAlgorithmIdentifier::SHA_224:
case CryptoAlgorithmIdentifier::SHA_256:
case CryptoAlgorithmIdentifier::SHA_384:
case CryptoAlgorithmIdentifier::SHA_512:
case CryptoAlgorithmIdentifier::CONCAT:
case CryptoAlgorithmIdentifier::HKDF_CTR:
case CryptoAlgorithmIdentifier::PBKDF2:
setDOMException(exec, NOT_SUPPORTED_ERR);
return nullptr;
}
}
}
#endif // ENABLE(SUBTLE_CRYPTO)
......@@ -53,8 +53,6 @@ public:
static std::unique_ptr<CryptoAlgorithmParameters> createParametersForDeriveBits(JSC::ExecState*, CryptoAlgorithmIdentifier, JSC::JSValue);
static std::unique_ptr<CryptoAlgorithmParameters> createParametersForImportKey(JSC::ExecState*, CryptoAlgorithmIdentifier, JSC::JSValue);
static std::unique_ptr<CryptoAlgorithmParameters> createParametersForExportKey(JSC::ExecState*, CryptoAlgorithmIdentifier, JSC::JSValue);
static std::unique_ptr<CryptoAlgorithmParameters> createParametersForWrapKey(JSC::ExecState*, CryptoAlgorithmIdentifier, JSC::JSValue);
static std::unique_ptr<CryptoAlgorithmParameters> createParametersForUnwrapKey(JSC::ExecState*, CryptoAlgorithmIdentifier, JSC::JSValue);
};
}
......
......@@ -37,9 +37,9 @@ namespace WebCore {
bool cryptoOperationDataFromJSValue(ExecState* exec, JSValue value, CryptoOperationData& result)
{
if (ArrayBuffer* buffer = toArrayBuffer(value))
result = std::make_pair(static_cast<char*>(buffer->data()), buffer->byteLength());
result = std::make_pair(static_cast<uint8_t*>(buffer->data()), buffer->byteLength());
else if (RefPtr<ArrayBufferView> bufferView = toArrayBufferView(value))
result = std::make_pair(static_cast<char*>(bufferView->baseAddress()), bufferView->byteLength());
result = std::make_pair(static_cast<uint8_t*>(bufferView->baseAddress()), bufferView->byteLength());
else {
throwTypeError(exec, "Only ArrayBuffer and ArrayBufferView objects can be passed as CryptoOperationData");
return false;
......
......@@ -35,7 +35,7 @@ class JSValue;
namespace WebCore {
typedef std::pair<const char*, size_t> CryptoOperationData;
typedef std::pair<const uint8_t*, size_t> CryptoOperationData;
bool cryptoOperationDataFromJSValue(JSC::ExecState*, JSC::JSValue, CryptoOperationData&);
......
......@@ -34,17 +34,4 @@ PromiseWrapper::PromiseWrapper(JSDOMGlobalObject* globalObject, JSC::JSPromise*
{
}
PromiseWrapper::PromiseWrapper(const PromiseWrapper& other)
: m_globalObject(other.m_globalObject)
, m_promise(other.m_promise)
{
}
PromiseWrapper& PromiseWrapper::operator=(const PromiseWrapper& other)
{
m_globalObject = other.m_globalObject;
m_promise = other.m_promise;
return *this;
}
}
......@@ -40,9 +40,6 @@ class PromiseWrapper {
public:
PromiseWrapper(JSDOMGlobalObject*, JSC::JSPromise*);
PromiseWrapper(const PromiseWrapper&);
PromiseWrapper& operator=(const PromiseWrapper&);
template<class FulfillResultType>
void fulfill(const FulfillResultType&);
......
......@@ -102,9 +102,9 @@ static bool cryptoKeyUsagesFromJSValue(ExecState* exec, JSValue value, CryptoKey
result = 0;
JSC::JSArray* array = asArray(value);
JSArray* array = asArray(value);
for (size_t i = 0; i < array->length(); ++i) {
JSC::JSValue element = array->getIndex(exec, i);
JSValue element = array->getIndex(exec, i);
String usageString = element.toString(exec)->value(exec);
if (exec->hadException())
return false;
......@@ -150,7 +150,7 @@ JSValue JSSubtleCrypto::encrypt(ExecState* exec)
return throwTypeError(exec);
if (!key->allows(CryptoKeyUsageEncrypt)) {
m_impl->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Key usages does not include 'encrypt'");
m_impl->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Key usages do not include 'encrypt'");
setDOMException(exec, NOT_SUPPORTED_ERR);
return jsUndefined();
}
......@@ -202,7 +202,7 @@ JSValue JSSubtleCrypto::decrypt(ExecState* exec)
return throwTypeError(exec);
if (!key->allows(CryptoKeyUsageDecrypt)) {
m_impl->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Key usages does not include 'decrypt'");
m_impl->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Key usages do not include 'decrypt'");
setDOMException(exec, NOT_SUPPORTED_ERR);
return jsUndefined();
}
......@@ -254,7 +254,7 @@ JSValue JSSubtleCrypto::sign(ExecState* exec)
return throwTypeError(exec);
if (!key->allows(CryptoKeyUsageSign)) {
m_impl->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Key usages does not include 'sign'");
m_impl->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Key usages do not include 'sign'");
setDOMException(exec, NOT_SUPPORTED_ERR);
return jsUndefined();
}
......@@ -306,7 +306,7 @@ JSValue JSSubtleCrypto::verify(ExecState* exec)
return throwTypeError(exec);
if (!key->allows(CryptoKeyUsageVerify)) {
m_impl->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Key usages does not include 'verify'");
m_impl->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Key usages do not include 'verify'");
setDOMException(exec, NOT_SUPPORTED_ERR);
return jsUndefined();
}
......@@ -384,7 +384,7 @@ JSValue JSSubtleCrypto::digest(ExecState* exec)
return promise;
}
JSValue JSSubtleCrypto::generateKey(JSC::ExecState* exec)
JSValue JSSubtleCrypto::generateKey(ExecState* exec)
{
if (exec->argumentCount() < 1)
return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec));
......@@ -440,37 +440,10 @@ JSValue JSSubtleCrypto::generateKey(JSC::ExecState* exec)
return promise;
}
JSValue JSSubtleCrypto::importKey(JSC::ExecState* exec)
static void importKey(ExecState* exec, CryptoKeyFormat keyFormat, CryptoOperationData data, CryptoAlgorithm* algorithmPtr, CryptoAlgorithmParameters* parametersPtr, bool extractable, CryptoKeyUsage keyUsages, CryptoAlgorithm::KeyCallback callback, CryptoAlgorithm::VoidCallback failureCallback)
{
if (exec->argumentCount() < 3)
return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec));
CryptoKeyFormat keyFormat;
if (!cryptoKeyFormatFromJSValue(exec, exec->argument(0), keyFormat)) {
ASSERT(exec->hadException());
return jsUndefined();
}
CryptoOperationData data;
if (!cryptoOperationDataFromJSValue(exec, exec->uncheckedArgument(1), data)) {
ASSERT(exec->hadException());
return jsUndefined();
}
std::unique_ptr<CryptoAlgorithm> algorithm;
std::unique_ptr<CryptoAlgorithmParameters> parameters;
if (!exec->uncheckedArgument(2).isNull()) {
algorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(2));
if (!algorithm) {
ASSERT(exec->hadException());
return jsUndefined();
}
parameters = JSCryptoAlgorithmDictionary::createParametersForImportKey(exec, algorithm->identifier(), exec->uncheckedArgument(2));
if (!parameters) {
ASSERT(exec->hadException());
return jsUndefined();
}
}
std::unique_ptr<CryptoAlgorithm> algorithm(algorithmPtr);
std::unique_ptr<CryptoAlgorithmParameters> parameters(parametersPtr);
std::unique_ptr<CryptoKeySerialization> keySerialization;
switch (keyFormat) {
......@@ -481,16 +454,16 @@ JSValue JSSubtleCrypto::importKey(JSC::ExecState* exec)
String jwkString = String::fromUTF8(data.first, data.second);
if (jwkString.isNull()) {
throwTypeError(exec, "JWK JSON serialization is not valid UTF-8");
return jsUndefined();
return;
}
keySerialization = JSCryptoKeySerializationJWK::create(exec, jwkString);
if (exec->hadException())
return jsUndefined();
return;
break;
}
default:
throwTypeError(exec, "Unsupported key format for import");
return jsUndefined();
return;
}
ASSERT(keySerialization);
......@@ -498,26 +471,73 @@ JSValue JSSubtleCrypto::importKey(JSC::ExecState* exec)
if (!keySerialization->reconcileAlgorithm(algorithm, parameters)) {
if (!exec->hadException())
throwTypeError(exec, "Algorithm specified in key is not compatible with one passed to importKey as argument");
return jsUndefined();
return;
}
if (exec->hadException())
return jsUndefined();
return;
if (!algorithm) {
throwTypeError(exec, "Neither key nor function argument has crypto algorithm specified");
return jsUndefined();
return;
}
ASSERT(parameters);
keySerialization->reconcileExtractable(extractable);
if (exec->hadException())
return;
keySerialization->reconcileUsages(keyUsages);
if (exec->hadException())
return;
auto keyData = keySerialization->keyData();
if (exec->hadException())
return;
ExceptionCode ec = 0;
algorithm->importKey(*parameters, *keyData, extractable, keyUsages, std::move(callback), std::move(failureCallback), ec);
if (ec)
setDOMException(exec, ec);
}
JSValue JSSubtleCrypto::importKey(ExecState* exec)
{
if (exec->argumentCount() < 3)
return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec));
CryptoKeyFormat keyFormat;
if (!cryptoKeyFormatFromJSValue(exec, exec->argument(0), keyFormat)) {
ASSERT(exec->hadException());
return jsUndefined();
}
CryptoOperationData data;
if (!cryptoOperationDataFromJSValue(exec, exec->uncheckedArgument(1), data)) {
ASSERT(exec->hadException());
return jsUndefined();
}
std::unique_ptr<CryptoAlgorithm> algorithm;
std::unique_ptr<CryptoAlgorithmParameters> parameters;
if (!exec->uncheckedArgument(2).isNull()) {
algorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(2));
if (!algorithm) {
ASSERT(exec->hadException());
return jsUndefined();
}
parameters = JSCryptoAlgorithmDictionary::createParametersForImportKey(exec, algorithm->identifier(), exec->uncheckedArgument(2));
if (!parameters) {
ASSERT(exec->hadException());
return jsUndefined();
}
}
bool extractable = false;
if (exec->argumentCount() >= 4) {
extractable = exec->uncheckedArgument(3).toBoolean(exec);
if (exec->hadException())
return jsUndefined();
}
keySerialization->reconcileExtractable(extractable);
if (exec->hadException())
return jsUndefined();
CryptoKeyUsage keyUsages = 0;
if (exec->argumentCount() >= 5) {
......@@ -526,13 +546,6 @@ JSValue JSSubtleCrypto::importKey(JSC::ExecState* exec)
return jsUndefined();
}
}
keySerialization->reconcileUsages(keyUsages);
if (exec->hadException())
return jsUndefined();
auto keyData = keySerialization->keyData();
if (exec->hadException())
return jsUndefined();
JSPromise* promise = JSPromise::createWithResolver(exec->vm(), globalObject());
PromiseWrapper promiseWrapper(globalObject(), promise);
......@@ -543,17 +556,14 @@ JSValue JSSubtleCrypto::importKey(JSC::ExecState* exec)
promiseWrapper.reject(nullptr);
};
ExceptionCode ec = 0;
algorithm->importKey(*parameters, *keyData, extractable, keyUsages, std::move(successCallback), std::move(failureCallback), ec);
if (ec) {
setDOMException(exec, ec);
WebCore::importKey(exec, keyFormat, data, algorithm.release(), parameters.release(), extractable, keyUsages, successCallback, failureCallback);
if (exec->hadException())
return jsUndefined();
}
return promise;
}
JSValue JSSubtleCrypto::exportKey(JSC::ExecState* exec)
JSValue JSSubtleCrypto::exportKey(ExecState* exec)
{
if (exec->argumentCount() < 2)
return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec));
......@@ -579,7 +589,7 @@ JSValue JSSubtleCrypto::exportKey(JSC::ExecState* exec)
switch (keyFormat) {
case CryptoKeyFormat::Raw: {
Vector<unsigned char> result;
Vector<uint8_t> result;
if (CryptoKeySerializationRaw::serialize(*key, result))
promiseWrapper.fulfill(result);
else {
......@@ -593,7 +603,7 @@ JSValue JSSubtleCrypto::exportKey(JSC::ExecState* exec)
if (exec->hadException())
return jsUndefined();
CString utf8String = result.utf8(StrictConversion);
Vector<unsigned char> resultBuffer;
Vector<uint8_t> resultBuffer;
resultBuffer.append(utf8String.data(), utf8String.length());
promiseWrapper.fulfill(resultBuffer);
break;
......@@ -606,6 +616,110 @@ JSValue JSSubtleCrypto::exportKey(JSC::ExecState* exec)
return promise;
}
JSValue JSSubtleCrypto::unwrapKey(ExecState* exec)
{
if (exec->argumentCount() < 5)
return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec));
CryptoKeyFormat keyFormat;
if (!cryptoKeyFormatFromJSValue(exec, exec->argument(0), keyFormat)) {
ASSERT(exec->hadException());
return jsUndefined();
}
CryptoOperationData wrappedKeyData;
if (!cryptoOperationDataFromJSValue(exec, exec->uncheckedArgument(1), wrappedKeyData)) {
ASSERT(exec->hadException());
return jsUndefined();
}
RefPtr<CryptoKey> unwrappingKey = toCryptoKey(exec->uncheckedArgument(2));
if (!unwrappingKey)
return throwTypeError(exec);
if (!unwrappingKey->allows(CryptoKeyUsageUnwrapKey)) {
m_impl->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Key usages do not include 'unwrapKey'");
setDOMException(exec, NOT_SUPPORTED_ERR);
return jsUndefined();
}
std::unique_ptr<CryptoAlgorithm> unwrapAlgorithm;
std::unique_ptr<CryptoAlgorithmParameters> unwrapAlgorithmParameters;
unwrapAlgorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(3));
if (!unwrapAlgorithm) {
ASSERT(exec->hadException());