Title: [159644] trunk
Revision
159644
Author
[email protected]
Date
2013-11-21 13:55:20 -0800 (Thu, 21 Nov 2013)

Log Message

Implement WebCrypto wrapKey
https://bugs.webkit.org/show_bug.cgi?id=124738

Reviewed by Anders Carlsson.

Source/WebCore: 

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.

LayoutTests: 

* 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.

Modified Paths

Added Paths

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);
 };
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to