Diff
Modified: trunk/LayoutTests/ChangeLog (159643 => 159644)
--- trunk/LayoutTests/ChangeLog 2013-11-21 21:11:06 UTC (rev 159643)
+++ trunk/LayoutTests/ChangeLog 2013-11-21 21:55:20 UTC (rev 159644)
@@ -1,3 +1,19 @@
+2013-11-21 Alexey Proskuryakov <[email protected]>
+
+ Implement WebCrypto wrapKey
+ https://bugs.webkit.org/show_bug.cgi?id=124738
+
+ Reviewed by Anders Carlsson.
+
+ * crypto/subtle/aes-cbc-wrap-rsa-expected.txt: Added.
+ * crypto/subtle/aes-cbc-wrap-rsa-non-extractable-expected.txt: Added.
+ * crypto/subtle/aes-cbc-wrap-rsa-non-extractable.html: Added.
+ * crypto/subtle/aes-cbc-wrap-rsa.html: Added.
+
+ * crypto/subtle/aes-export-key-expected.txt:
+ * crypto/subtle/hmac-export-key-expected.txt:
+ There is no longer a console message, the error is in an exception.
+
2013-11-21 Radu Stavila <[email protected]>
Added test for :hover and _javascript_ events on the visual overflow of a region.
Added: trunk/LayoutTests/crypto/subtle/aes-cbc-wrap-rsa-expected.txt (0 => 159644)
--- trunk/LayoutTests/crypto/subtle/aes-cbc-wrap-rsa-expected.txt (rev 0)
+++ trunk/LayoutTests/crypto/subtle/aes-cbc-wrap-rsa-expected.txt 2013-11-21 21:55:20 UTC (rev 159644)
@@ -0,0 +1,14 @@
+Test wrapping an RSA key with AES-CBC.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Importing a key to wrap...
+PASS key.algorithm.name is 'rsassa-pkcs1-v1_5'
+Importing a key encryption key...
+PASS wrappingKey.algorithm.name is 'aes-cbc'
+PASS wrappedKey.toString() is '[object ArrayBuffer]'
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Property changes on: trunk/LayoutTests/crypto/subtle/aes-cbc-wrap-rsa-expected.txt
___________________________________________________________________
Added: svn:mime-type
Added: svn:eol-style
Added: trunk/LayoutTests/crypto/subtle/aes-cbc-wrap-rsa-non-extractable-expected.txt (0 => 159644)
--- trunk/LayoutTests/crypto/subtle/aes-cbc-wrap-rsa-non-extractable-expected.txt (rev 0)
+++ trunk/LayoutTests/crypto/subtle/aes-cbc-wrap-rsa-non-extractable-expected.txt 2013-11-21 21:55:20 UTC (rev 159644)
@@ -0,0 +1,15 @@
+Test wrapping an RSA key with AES-CBC.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Importing a key to wrap...
+PASS key.algorithm.name is 'rsassa-pkcs1-v1_5'
+Importing a key encryption key...
+PASS wrappingKey.algorithm.name is 'aes-cbc'
+wrapping the key...
+PASS Rejected
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Property changes on: trunk/LayoutTests/crypto/subtle/aes-cbc-wrap-rsa-non-extractable-expected.txt
___________________________________________________________________
Added: svn:mime-type
Added: svn:eol-style
Added: trunk/LayoutTests/crypto/subtle/aes-cbc-wrap-rsa-non-extractable.html (0 => 159644)
--- trunk/LayoutTests/crypto/subtle/aes-cbc-wrap-rsa-non-extractable.html (rev 0)
+++ trunk/LayoutTests/crypto/subtle/aes-cbc-wrap-rsa-non-extractable.html 2013-11-21 21:55:20 UTC (rev 159644)
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<script src=""
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+
+<script>
+description("Test wrapping 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 jwkKeyAsArrayBuffer = asciiToUint8Array(JSON.stringify(publicKeyJSON));
+var wrappingKeyOctets = hexStringToUint8Array("2a00e0e776e94e4dc89bf947cebdebe1");
+
+debug("Importing a key to wrap...");
+crypto.subtle.importKey("jwk", jwkKeyAsArrayBuffer, null, extractable, ["sign", "verify"]).then(function(result) {
+ key = result;
+ shouldBe("key.algorithm.name", "'rsassa-pkcs1-v1_5'");
+ debug("Importing a key encryption key...");
+ return crypto.subtle.importKey("raw", wrappingKeyOctets, "AES-CBC", nonExtractable, ["wrapKey"]);
+}).then(function(result) {
+ wrappingKey = result;
+ shouldBe("wrappingKey.algorithm.name", "'aes-cbc'");
+ var wrapAlgorithm = {name: "AES-CBC", iv: hexStringToUint8Array("000102030405060708090a0b0c0d0e0f")};
+ debug("wrapping the key...");
+ return crypto.subtle.wrapKey("jwk", key, wrappingKey, wrapAlgorithm);
+}).then(undefined, function() {
+ testPassed("Rejected");
+ finishJSTest();
+});
+
+</script>
+
+<script src=""
+</body>
+</html>
Property changes on: trunk/LayoutTests/crypto/subtle/aes-cbc-wrap-rsa-non-extractable.html
___________________________________________________________________
Added: svn:mime-type
Added: trunk/LayoutTests/crypto/subtle/aes-cbc-wrap-rsa.html (0 => 159644)
--- trunk/LayoutTests/crypto/subtle/aes-cbc-wrap-rsa.html (rev 0)
+++ trunk/LayoutTests/crypto/subtle/aes-cbc-wrap-rsa.html 2013-11-21 21:55:20 UTC (rev 159644)
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<script src=""
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+
+<script>
+description("Test wrapping 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: true,
+ use: "sig"
+};
+
+var jwkKeyAsArrayBuffer = asciiToUint8Array(JSON.stringify(publicKeyJSON));
+var wrappingKeyOctets = hexStringToUint8Array("2a00e0e776e94e4dc89bf947cebdebe1");
+
+debug("Importing a key to wrap...");
+crypto.subtle.importKey("jwk", jwkKeyAsArrayBuffer, null, extractable, ["sign", "verify"]).then(function(result) {
+ key = result;
+ shouldBe("key.algorithm.name", "'rsassa-pkcs1-v1_5'");
+ debug("Importing a key encryption key...");
+ return crypto.subtle.importKey("raw", wrappingKeyOctets, "AES-CBC", nonExtractable, ["wrapKey"]);
+}).then(function(result) {
+ wrappingKey = result;
+ shouldBe("wrappingKey.algorithm.name", "'aes-cbc'");
+ var wrapAlgorithm = {name: "AES-CBC", iv: hexStringToUint8Array("000102030405060708090a0b0c0d0e0f")};
+ return crypto.subtle.wrapKey("jwk", key, wrappingKey, wrapAlgorithm);
+}).then(function(result) {
+ wrappedKey = result;
+ shouldBe("wrappedKey.toString()", "'[object ArrayBuffer]'");
+ finishJSTest();
+});
+
+</script>
+
+<script src=""
+</body>
+</html>
Property changes on: trunk/LayoutTests/crypto/subtle/aes-cbc-wrap-rsa.html
___________________________________________________________________
Added: svn:mime-type
Modified: trunk/LayoutTests/crypto/subtle/aes-export-key-expected.txt (159643 => 159644)
--- trunk/LayoutTests/crypto/subtle/aes-export-key-expected.txt 2013-11-21 21:11:06 UTC (rev 159643)
+++ trunk/LayoutTests/crypto/subtle/aes-export-key-expected.txt 2013-11-21 21:55:20 UTC (rev 159644)
@@ -1,5 +1,3 @@
-CONSOLE MESSAGE: Key is not extractable
-CONSOLE MESSAGE: Key is not extractable
Test exporting an AES key.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
Modified: trunk/LayoutTests/crypto/subtle/hmac-export-key-expected.txt (159643 => 159644)
--- trunk/LayoutTests/crypto/subtle/hmac-export-key-expected.txt 2013-11-21 21:11:06 UTC (rev 159643)
+++ trunk/LayoutTests/crypto/subtle/hmac-export-key-expected.txt 2013-11-21 21:55:20 UTC (rev 159644)
@@ -1,5 +1,3 @@
-CONSOLE MESSAGE: Key is not extractable
-CONSOLE MESSAGE: Key is not extractable
Test exporting an AES key.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
Modified: trunk/Source/WebCore/ChangeLog (159643 => 159644)
--- trunk/Source/WebCore/ChangeLog 2013-11-21 21:11:06 UTC (rev 159643)
+++ trunk/Source/WebCore/ChangeLog 2013-11-21 21:55:20 UTC (rev 159644)
@@ -1,5 +1,24 @@
2013-11-21 Alexey Proskuryakov <[email protected]>
+ Implement WebCrypto wrapKey
+ https://bugs.webkit.org/show_bug.cgi?id=124738
+
+ Reviewed by Anders Carlsson.
+
+ Tests: crypto/subtle/aes-cbc-wrap-rsa-non-extractable.html
+ crypto/subtle/aes-cbc-wrap-rsa.html
+
+ * bindings/js/JSSubtleCryptoCustom.cpp:
+ (WebCore::exportKey): Factored out the actual operation that can be chained with
+ encryption for wrapKey.
+ (WebCore::JSSubtleCrypto::exportKey):
+ (WebCore::JSSubtleCrypto::wrapKey):
+ (WebCore::JSSubtleCrypto::unwrapKey): Fixed a memory leak in failure code path.
+
+ * crypto/SubtleCrypto.idl: Added wrapKey.
+
+2013-11-21 Alexey Proskuryakov <[email protected]>
+
Implement WebCrypto unwrapKey
https://bugs.webkit.org/show_bug.cgi?id=124725
Modified: trunk/Source/WebCore/bindings/js/JSSubtleCryptoCustom.cpp (159643 => 159644)
--- trunk/Source/WebCore/bindings/js/JSSubtleCryptoCustom.cpp 2013-11-21 21:11:06 UTC (rev 159643)
+++ trunk/Source/WebCore/bindings/js/JSSubtleCryptoCustom.cpp 2013-11-21 21:55:20 UTC (rev 159644)
@@ -563,6 +563,38 @@
return promise;
}
+static void exportKey(ExecState* exec, CryptoKeyFormat keyFormat, const CryptoKey& key, CryptoAlgorithm::VectorCallback callback, CryptoAlgorithm::VoidCallback failureCallback)
+{
+ if (!key.extractable()) {
+ throwTypeError(exec, "Key is not extractable");
+ return;
+ }
+
+ switch (keyFormat) {
+ case CryptoKeyFormat::Raw: {
+ Vector<uint8_t> result;
+ if (CryptoKeySerializationRaw::serialize(key, result))
+ callback(result);
+ else
+ failureCallback();
+ break;
+ }
+ case CryptoKeyFormat::JWK: {
+ String result = JSCryptoKeySerializationJWK::serialize(exec, key);
+ if (exec->hadException())
+ return;
+ CString utf8String = result.utf8(StrictConversion);
+ Vector<uint8_t> resultBuffer;
+ resultBuffer.append(utf8String.data(), utf8String.length());
+ callback(resultBuffer);
+ break;
+ }
+ default:
+ throwTypeError(exec, "Unsupported key format for export");
+ break;
+ }
+}
+
JSValue JSSubtleCrypto::exportKey(ExecState* exec)
{
if (exec->argumentCount() < 2)
@@ -581,35 +613,83 @@
JSPromise* promise = JSPromise::createWithResolver(exec->vm(), globalObject());
PromiseWrapper promiseWrapper(globalObject(), promise);
- if (!key->extractable()) {
- m_impl->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Key is not extractable");
+ auto successCallback = [promiseWrapper](const Vector<uint8_t>& result) mutable {
+ promiseWrapper.fulfill(result);
+ };
+ auto failureCallback = [promiseWrapper]() mutable {
promiseWrapper.reject(nullptr);
- return promise;
+ };
+
+ WebCore::exportKey(exec, keyFormat, *key, successCallback, failureCallback);
+ if (exec->hadException())
+ return jsUndefined();
+
+ return promise;
+}
+
+JSValue JSSubtleCrypto::wrapKey(ExecState* exec)
+{
+ if (exec->argumentCount() < 4)
+ return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec));
+
+ CryptoKeyFormat keyFormat;
+ if (!cryptoKeyFormatFromJSValue(exec, exec->argument(0), keyFormat)) {
+ ASSERT(exec->hadException());
+ return jsUndefined();
}
- switch (keyFormat) {
- case CryptoKeyFormat::Raw: {
- Vector<uint8_t> result;
- if (CryptoKeySerializationRaw::serialize(*key, result))
- promiseWrapper.fulfill(result);
- else {
- m_impl->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Key cannot be exported to raw format");
+ RefPtr<CryptoKey> key = toCryptoKey(exec->uncheckedArgument(1));
+ if (!key)
+ return throwTypeError(exec);
+
+ RefPtr<CryptoKey> wrappingKey = toCryptoKey(exec->uncheckedArgument(2));
+ if (!key)
+ return throwTypeError(exec);
+
+
+ auto algorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(3));
+ if (!algorithm) {
+ ASSERT(exec->hadException());
+ return jsUndefined();
+ }
+
+ auto parameters = JSCryptoAlgorithmDictionary::createParametersForEncrypt(exec, algorithm->identifier(), exec->uncheckedArgument(3));
+ if (!parameters) {
+ ASSERT(exec->hadException());
+ return jsUndefined();
+ }
+
+ JSPromise* promise = JSPromise::createWithResolver(exec->vm(), globalObject());
+ PromiseWrapper promiseWrapper(globalObject(), promise);
+
+ CryptoAlgorithm* algorithmPtr = algorithm.release();
+ CryptoAlgorithmParameters* parametersPtr = parameters.release();
+
+ auto exportSuccessCallback = [keyFormat, algorithmPtr, parametersPtr, wrappingKey, promiseWrapper](const Vector<uint8_t>& exportedKeyData) mutable {
+ auto encryptSuccessCallback = [promiseWrapper](const Vector<uint8_t>& encryptedData) mutable {
+ promiseWrapper.fulfill(encryptedData);
+ };
+ auto encryptFailureCallback = [promiseWrapper]() mutable {
promiseWrapper.reject(nullptr);
+ };
+ ExceptionCode ec = 0;
+ algorithmPtr->encryptForWrapKey(*parametersPtr, *wrappingKey, std::make_pair(exportedKeyData.data(), exportedKeyData.size()), std::move(encryptSuccessCallback), std::move(encryptFailureCallback), ec);
+ if (ec) {
+ // FIXME: Report failure details to console, and possibly to calling script once there is a standardized way to pass errors to WebCrypto promise reject functions.
+ encryptFailureCallback();
}
- break;
- }
- case CryptoKeyFormat::JWK: {
- String result = JSCryptoKeySerializationJWK::serialize(exec, *key);
- if (exec->hadException())
- return jsUndefined();
- CString utf8String = result.utf8(StrictConversion);
- Vector<uint8_t> resultBuffer;
- resultBuffer.append(utf8String.data(), utf8String.length());
- promiseWrapper.fulfill(resultBuffer);
- break;
- }
- default:
- throwTypeError(exec, "Unsupported key format for export");
+ };
+
+ auto exportFailureCallback = [promiseWrapper, algorithmPtr, parametersPtr]() mutable {
+ delete algorithmPtr;
+ delete parametersPtr;
+ promiseWrapper.reject(nullptr);
+ };
+
+ ExceptionCode ec = 0;
+ WebCore::exportKey(exec, keyFormat, *key, exportSuccessCallback, exportFailureCallback);
+ if (ec) {
+ setDOMException(exec, ec);
return jsUndefined();
}
@@ -693,25 +773,30 @@
CryptoAlgorithm* unwrappedKeyAlgorithmPtr = unwrappedKeyAlgorithm.release();
CryptoAlgorithmParameters* unwrappedKeyAlgorithmParametersPtr = unwrappedKeyAlgorithmParameters.release();
- auto failureCallback = [promiseWrapper]() mutable {
- promiseWrapper.reject(nullptr);
- };
-
- auto successCallback = [domGlobalObject, keyFormat, unwrappedKeyAlgorithmPtr, unwrappedKeyAlgorithmParametersPtr, extractable, keyUsages, promiseWrapper, failureCallback](const Vector<uint8_t>& result) mutable {
+ auto decryptSuccessCallback = [domGlobalObject, keyFormat, unwrappedKeyAlgorithmPtr, unwrappedKeyAlgorithmParametersPtr, extractable, keyUsages, promiseWrapper](const Vector<uint8_t>& result) mutable {
auto importSuccessCallback = [promiseWrapper](CryptoKey& key) mutable {
promiseWrapper.fulfill(&key);
};
+ auto importFailureCallback = [promiseWrapper]() mutable {
+ promiseWrapper.reject(nullptr);
+ };
ExecState* exec = domGlobalObject->globalExec();
- WebCore::importKey(exec, keyFormat, std::make_pair(result.data(), result.size()), unwrappedKeyAlgorithmPtr, unwrappedKeyAlgorithmParametersPtr, extractable, keyUsages, importSuccessCallback, failureCallback);
+ WebCore::importKey(exec, keyFormat, std::make_pair(result.data(), result.size()), unwrappedKeyAlgorithmPtr, unwrappedKeyAlgorithmParametersPtr, extractable, keyUsages, importSuccessCallback, importFailureCallback);
if (exec->hadException()) {
// FIXME: Report exception details to console, and possibly to calling script once there is a standardized way to pass errors to WebCrypto promise reject functions.
exec->clearException();
- failureCallback();
+ importFailureCallback();
}
};
+ auto decryptFailureCallback = [promiseWrapper, unwrappedKeyAlgorithmPtr, unwrappedKeyAlgorithmParametersPtr]() mutable {
+ delete unwrappedKeyAlgorithmPtr;
+ delete unwrappedKeyAlgorithmParametersPtr;
+ promiseWrapper.reject(nullptr);
+ };
+
ExceptionCode ec = 0;
- unwrapAlgorithm->decryptForUnwrapKey(*unwrapAlgorithmParameters, *unwrappingKey, wrappedKeyData, std::move(successCallback), std::move(failureCallback), ec);
+ unwrapAlgorithm->decryptForUnwrapKey(*unwrapAlgorithmParameters, *unwrappingKey, wrappedKeyData, std::move(decryptSuccessCallback), std::move(decryptFailureCallback), ec);
if (ec) {
setDOMException(exec, ec);
return jsUndefined();
Modified: trunk/Source/WebCore/crypto/SubtleCrypto.idl (159643 => 159644)
--- trunk/Source/WebCore/crypto/SubtleCrypto.idl 2013-11-21 21:11:06 UTC (rev 159643)
+++ trunk/Source/WebCore/crypto/SubtleCrypto.idl 2013-11-21 21:55:20 UTC (rev 159644)
@@ -37,5 +37,6 @@
[Custom] Promise generateKey(AlgorithmIdentifier algorithm, optional boolean extractable, optional KeyUsage[] keyUsages);
[Custom] Promise importKey(KeyFormat format, CryptoOperationData keyData, AlgorithmIdentifier? algorithm, optional boolean extractable, optional KeyUsage[] keyUsages);
[Custom] Promise exportKey(KeyFormat format, Key key);
+ [Custom] Promise wrapKey(KeyFormat format, Key key, Key wrappingKey, AlgorithmIdentifier wrapAlgorithm);
[Custom] Promise unwrapKey(KeyFormat format, CryptoOperationData wrappedKey, Key unwrappingKey, AlgorithmIdentifier unwrapAlgorithm, AlgorithmIdentifier? unwrappedKeyAlgorithm, optional boolean extractable, optional KeyUsage[] keyUsages);
};