[WebCrypto] Implement ECDH DeriveBits operation
authorjiewen_tan@apple.com <jiewen_tan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 9 Mar 2017 04:04:29 +0000 (04:04 +0000)
committerjiewen_tan@apple.com <jiewen_tan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 9 Mar 2017 04:04:29 +0000 (04:04 +0000)
https://bugs.webkit.org/show_bug.cgi?id=169319
<rdar://problem/23789585>

Reviewed by Brent Fulgham.

Source/WebCore:

This patch implements DeriveBits operation of ECDH according to the spec:
https://www.w3.org/TR/WebCryptoAPI/#ecdh-operations.

Tests: crypto/subtle/derive-bits-malformed-parameters.html
       crypto/subtle/ecdh-derive-bits-malformed-parametrs.html
       crypto/subtle/ecdh-generate-key-derive-bits.html
       crypto/subtle/ecdh-import-key-derive-bits-custom-length.html
       crypto/subtle/ecdh-import-key-derive-bits-null-length.html
       crypto/workers/subtle/ecdh-import-key-derive-bits.html

* CMakeLists.txt:
* DerivedSources.make:
* PlatformGTK.cmake:
* PlatformMac.cmake:
* WebCore.xcodeproj/project.pbxproj:
* bindings/js/JSSubtleCryptoCustom.cpp:
(WebCore::normalizeCryptoAlgorithmParameters):
(WebCore::jsSubtleCryptoFunctionDeriveKeyPromise):
(WebCore::jsSubtleCryptoFunctionDeriveBitsPromise):
(WebCore::JSSubtleCrypto::generateKey):
Reorder a bit of the functions.
* crypto/CommonCryptoUtilities.h:
* crypto/CryptoAlgorithm.cpp:
(WebCore::CryptoAlgorithm::deriveBits):
* crypto/CryptoAlgorithm.h:
* crypto/CryptoAlgorithmParameters.h:
* crypto/algorithms/CryptoAlgorithmECDH.cpp:
(WebCore::CryptoAlgorithmECDH::deriveBits):
* crypto/algorithms/CryptoAlgorithmECDH.h:
* crypto/gnutls/CryptoAlgorithmECDHGnuTLS.cpp: Added.
(WebCore::CryptoAlgorithmECDH::platformDeriveBits):
* crypto/keys/CryptoKeyEC.h:
* crypto/mac/CryptoAlgorithmECDHMac.cpp: Added.
(WebCore::CryptoAlgorithmECDH::platformDeriveBits):
* crypto/parameters/CryptoAlgorithmEcdhKeyDeriveParams.h: Added.
* crypto/parameters/EcdhKeyDeriveParams.idl: Added.

LayoutTests:

* TestExpectations:
Refine some comments.
* crypto/subtle/derive-bits-malformed-parameters-expected.txt: Renamed from LayoutTests/crypto/subtle/deriveBits-malformed-parameters-expected.txt.
* crypto/subtle/derive-bits-malformed-parameters.html: Added.
* crypto/subtle/deriveBits-malformed-parameters.html: Removed.
* crypto/subtle/ecdh-derive-bits-malformed-parametrs-expected.txt: Added.
* crypto/subtle/ecdh-derive-bits-malformed-parametrs.html: Added.
* crypto/subtle/ecdh-generate-key-derive-bits-expected.txt: Added.
* crypto/subtle/ecdh-generate-key-derive-bits.html: Added.
* crypto/subtle/ecdh-import-key-derive-bits-custom-length-expected.txt: Added.
* crypto/subtle/ecdh-import-key-derive-bits-custom-length.html: Added.
* crypto/subtle/ecdh-import-key-derive-bits-null-length-expected.txt: Added.
* crypto/subtle/ecdh-import-key-derive-bits-null-length.html: Added.
* crypto/workers/subtle/ecdh-import-key-derive-bits-expected.txt: Added.
* crypto/workers/subtle/ecdh-import-key-derive-bits.html: Added.
* crypto/workers/subtle/resources/ecdh-import-key-derive-bits.js: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@213624 268f45cc-cd09-0410-ab3c-d52691b4dbfc

34 files changed:
LayoutTests/ChangeLog
LayoutTests/TestExpectations
LayoutTests/crypto/subtle/derive-bits-malformed-parameters-expected.txt [moved from LayoutTests/crypto/subtle/deriveBits-malformed-parameters-expected.txt with 55% similarity]
LayoutTests/crypto/subtle/derive-bits-malformed-parameters.html [new file with mode: 0644]
LayoutTests/crypto/subtle/deriveBits-malformed-parameters.html [deleted file]
LayoutTests/crypto/subtle/ecdh-derive-bits-malformed-parametrs-expected.txt [new file with mode: 0644]
LayoutTests/crypto/subtle/ecdh-derive-bits-malformed-parametrs.html [new file with mode: 0644]
LayoutTests/crypto/subtle/ecdh-generate-key-derive-bits-expected.txt [new file with mode: 0644]
LayoutTests/crypto/subtle/ecdh-generate-key-derive-bits.html [new file with mode: 0644]
LayoutTests/crypto/subtle/ecdh-import-key-derive-bits-custom-length-expected.txt [new file with mode: 0644]
LayoutTests/crypto/subtle/ecdh-import-key-derive-bits-custom-length.html [new file with mode: 0644]
LayoutTests/crypto/subtle/ecdh-import-key-derive-bits-null-length-expected.txt [new file with mode: 0644]
LayoutTests/crypto/subtle/ecdh-import-key-derive-bits-null-length.html [new file with mode: 0644]
LayoutTests/crypto/workers/subtle/ecdh-import-key-derive-bits-expected.txt [new file with mode: 0644]
LayoutTests/crypto/workers/subtle/ecdh-import-key-derive-bits.html [new file with mode: 0644]
LayoutTests/crypto/workers/subtle/resources/ecdh-import-key-derive-bits.js [new file with mode: 0644]
Source/WebCore/CMakeLists.txt
Source/WebCore/ChangeLog
Source/WebCore/DerivedSources.make
Source/WebCore/PlatformGTK.cmake
Source/WebCore/PlatformMac.cmake
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/bindings/js/JSSubtleCryptoCustom.cpp
Source/WebCore/crypto/CommonCryptoUtilities.h
Source/WebCore/crypto/CryptoAlgorithm.cpp
Source/WebCore/crypto/CryptoAlgorithm.h
Source/WebCore/crypto/CryptoAlgorithmParameters.h
Source/WebCore/crypto/algorithms/CryptoAlgorithmECDH.cpp
Source/WebCore/crypto/algorithms/CryptoAlgorithmECDH.h
Source/WebCore/crypto/gnutls/CryptoAlgorithmECDHGnuTLS.cpp [new file with mode: 0644]
Source/WebCore/crypto/keys/CryptoKeyEC.h
Source/WebCore/crypto/mac/CryptoAlgorithmECDHMac.cpp [new file with mode: 0644]
Source/WebCore/crypto/parameters/CryptoAlgorithmEcdhKeyDeriveParams.h [new file with mode: 0644]
Source/WebCore/crypto/parameters/EcdhKeyDeriveParams.idl [new file with mode: 0644]

index 3c3e1ce..5867e69 100644 (file)
@@ -1,3 +1,28 @@
+2017-03-08  Jiewen Tan  <jiewen_tan@apple.com>
+
+        [WebCrypto] Implement ECDH DeriveBits operation
+        https://bugs.webkit.org/show_bug.cgi?id=169319
+        <rdar://problem/23789585>
+
+        Reviewed by Brent Fulgham.
+
+        * TestExpectations:
+        Refine some comments.
+        * crypto/subtle/derive-bits-malformed-parameters-expected.txt: Renamed from LayoutTests/crypto/subtle/deriveBits-malformed-parameters-expected.txt.
+        * crypto/subtle/derive-bits-malformed-parameters.html: Added.
+        * crypto/subtle/deriveBits-malformed-parameters.html: Removed.
+        * crypto/subtle/ecdh-derive-bits-malformed-parametrs-expected.txt: Added.
+        * crypto/subtle/ecdh-derive-bits-malformed-parametrs.html: Added.
+        * crypto/subtle/ecdh-generate-key-derive-bits-expected.txt: Added.
+        * crypto/subtle/ecdh-generate-key-derive-bits.html: Added.
+        * crypto/subtle/ecdh-import-key-derive-bits-custom-length-expected.txt: Added.
+        * crypto/subtle/ecdh-import-key-derive-bits-custom-length.html: Added.
+        * crypto/subtle/ecdh-import-key-derive-bits-null-length-expected.txt: Added.
+        * crypto/subtle/ecdh-import-key-derive-bits-null-length.html: Added.
+        * crypto/workers/subtle/ecdh-import-key-derive-bits-expected.txt: Added.
+        * crypto/workers/subtle/ecdh-import-key-derive-bits.html: Added.
+        * crypto/workers/subtle/resources/ecdh-import-key-derive-bits.js: Added.
+
 2017-03-08  John Wilander  <wilander@apple.com>
 
         Resource Load Statistics: Communicate to the network process which domains to partition
index 0ed55e4..561aa58 100644 (file)
@@ -959,7 +959,7 @@ webkit.org/b/159370 [ Debug ] fast/history/page-cache-destroy-document.html [ Sk
 # This test is just way too slow.
 workers/bomb-with-v8.html [ Skip ]
 
-# WebCryptoAPI tests that take too long to complete, need to scale down. webkit.org/b/159638
+# WebCryptoAPI tests that take too long to complete
 imported/w3c/web-platform-tests/WebCryptoAPI/derive_bits_keys/hkdf.worker.html [ Skip ]
 imported/w3c/web-platform-tests/WebCryptoAPI/derive_bits_keys/pbkdf2.worker.html [ Skip ]
 imported/w3c/web-platform-tests/WebCryptoAPI/generateKey/successes_RSA-OAEP.worker.html [ Skip ]
@@ -6,7 +6,8 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE
 PASS crypto.subtle.deriveBits() rejected promise  with TypeError: Not enough arguments.
 PASS crypto.subtle.deriveBits(1) rejected promise  with TypeError: Not enough arguments.
 PASS crypto.subtle.deriveBits(1, 2) rejected promise  with TypeError: Not enough arguments.
-PASS crypto.subtle.deriveBits("ECDH", 2, 3) rejected promise  with NotSupportedError (DOM Exception 9): The operation is not supported..
+PASS crypto.subtle.deriveBits({ name:"ECDH", public:wrongKey }, wrongKey, 128) rejected promise  with InvalidAccessError (DOM Exception 15): CryptoKey doesn't match AlgorithmIdentifier.
+PASS crypto.subtle.deriveBits({ name:"ECDH", public:wrongKey }, wrongKey, 128) rejected promise  with InvalidAccessError (DOM Exception 15): CryptoKey doesn't support bits derivation.
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/LayoutTests/crypto/subtle/derive-bits-malformed-parameters.html b/LayoutTests/crypto/subtle/derive-bits-malformed-parameters.html
new file mode 100644 (file)
index 0000000..54e41e7
--- /dev/null
@@ -0,0 +1,55 @@
+<!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 deriveBits operation with malformed parameters");
+
+
+jsTestIsAsync = true;
+
+var extractable = true;
+var hmacImportParams = {
+    name: "hmac",
+    hash: "sha-1",
+}
+var rawKey = asciiToUint8Array("jnOw99oOZFLIEPMr");
+var jwkKey = {
+    kty: "EC",
+    crv: "P-256",
+    x: "1FSVWieTvikFkG1NOyhkUCaMbdQhxwH6aCu4Ez-sRtA",
+    y: "9jmNTLqM4cjBhdAnHcNI9YQV3O8LFmo-EdZWk8ntAaI",
+    d: "ppxBSov3N8_AUcisAuvmLV4yE8e_L_BLE8bZb9Z1Xjg",
+};
+
+
+// Not enough arguments.
+shouldReject('crypto.subtle.deriveBits()');
+shouldReject('crypto.subtle.deriveBits(1)');
+shouldReject('crypto.subtle.deriveBits(1, 2)');
+
+crypto.subtle.importKey("raw", rawKey, hmacImportParams, extractable, ["sign", "verify"]).then(function(result) {
+    wrongKey = result;
+    // Wrong algorithm identifier.
+    shouldReject('crypto.subtle.deriveBits({ name:"ECDH", public:wrongKey }, wrongKey, 128)');
+
+    return crypto.subtle.importKey("jwk", jwkKey, { name: "ECDH", namedCurve: "P-256" }, extractable, ["deriveKey"]);
+}).then(function(result) {
+    wrongKey = result;
+    // Wrong usage.
+    shouldReject('crypto.subtle.deriveBits({ name:"ECDH", public:wrongKey }, wrongKey, 128)');
+
+    finishJSTest();
+});
+
+</script>
+
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/crypto/subtle/deriveBits-malformed-parameters.html b/LayoutTests/crypto/subtle/deriveBits-malformed-parameters.html
deleted file mode 100644 (file)
index 10150d9..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-<!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 deriveBits operation with malformed parameters");
-
-// Not enough arguments.
-shouldReject('crypto.subtle.deriveBits()');
-shouldReject('crypto.subtle.deriveBits(1)');
-shouldReject('crypto.subtle.deriveBits(1, 2)');
-// Not support.
-shouldReject('crypto.subtle.deriveBits("ECDH", 2, 3)');
-</script>
-
-<script src="../../resources/js-test-post.js"></script>
-</body>
-</html>
diff --git a/LayoutTests/crypto/subtle/ecdh-derive-bits-malformed-parametrs-expected.txt b/LayoutTests/crypto/subtle/ecdh-derive-bits-malformed-parametrs-expected.txt
new file mode 100644 (file)
index 0000000..9e10796
--- /dev/null
@@ -0,0 +1,23 @@
+Test ECDH deriveBits operation with malformed parameters
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS crypto.subtle.deriveBits("ecdh", privateKey, null) rejected promise  with TypeError: Member EcdhKeyDeriveParams.publicKey is required and must be an instance of CryptoKey.
+PASS crypto.subtle.deriveBits({name: "ecdh"}, privateKey, null) rejected promise  with TypeError: Member EcdhKeyDeriveParams.publicKey is required and must be an instance of CryptoKey.
+PASS crypto.subtle.deriveBits({name: "ecdh", public: true}, privateKey, null) rejected promise  with TypeError: Type error.
+PASS crypto.subtle.deriveBits({name: "ecdh", public: null}, privateKey, null) rejected promise  with TypeError: Type error.
+PASS crypto.subtle.deriveBits({name: "ecdh", public: undefined}, privateKey, null) rejected promise  with TypeError: Member EcdhKeyDeriveParams.publicKey is required and must be an instance of CryptoKey.
+PASS crypto.subtle.deriveBits({name: "ecdh", public: Symbol()}, privateKey, null) rejected promise  with TypeError: Type error.
+PASS crypto.subtle.deriveBits({name: "ecdh", public: { }}, privateKey, null) rejected promise  with TypeError: Type error.
+PASS crypto.subtle.deriveBits({name: "ecdh", public: 1}, privateKey, null) rejected promise  with TypeError: Type error.
+PASS crypto.subtle.deriveBits({ name:"ECDH", public:publicKey }, privateKey, 1) rejected promise  with OperationError (DOM Exception 34): The operation failed for an operation-specific reason.
+PASS crypto.subtle.deriveBits({ name:"ECDH", public:publicKey }, publicKey, null) rejected promise  with InvalidAccessError (DOM Exception 15): CryptoKey doesn't support bits derivation.
+PASS crypto.subtle.deriveBits({ name:"ECDH", public:privateKey }, privateKey, null) rejected promise  with InvalidAccessError (DOM Exception 15): The requested operation is not valid for the provided key.
+PASS crypto.subtle.deriveBits({ name:"ECDH", public:fakeKey }, privateKey, null) rejected promise  with InvalidAccessError (DOM Exception 15): The requested operation is not valid for the provided key.
+PASS crypto.subtle.deriveBits({ name:"ECDH", public:publicKeyP384 }, privateKey, null) rejected promise  with InvalidAccessError (DOM Exception 15): The requested operation is not valid for the provided key.
+PASS crypto.subtle.deriveBits({ name:"ECDH", public:publicKey }, privateKey, 384) rejected promise  with OperationError (DOM Exception 34): The operation failed for an operation-specific reason.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/crypto/subtle/ecdh-derive-bits-malformed-parametrs.html b/LayoutTests/crypto/subtle/ecdh-derive-bits-malformed-parametrs.html
new file mode 100644 (file)
index 0000000..a2fd66a
--- /dev/null
@@ -0,0 +1,76 @@
+<!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 ECDH deriveBits operation with malformed parameters");
+
+jsTestIsAsync = true;
+
+var extractable = true;
+var jwkPrivateKey = {
+    kty: "EC",
+    crv: "P-256",
+    x: "1FSVWieTvikFkG1NOyhkUCaMbdQhxwH6aCu4Ez-sRtA",
+    y: "9jmNTLqM4cjBhdAnHcNI9YQV3O8LFmo-EdZWk8ntAaI",
+    d: "ppxBSov3N8_AUcisAuvmLV4yE8e_L_BLE8bZb9Z1Xjg",
+};
+var jwkPublicKey = {
+    kty: "EC",
+    crv: "P-256",
+    x: "1FSVWieTvikFkG1NOyhkUCaMbdQhxwH6aCu4Ez-sRtA",
+    y: "9jmNTLqM4cjBhdAnHcNI9YQV3O8LFmo-EdZWk8ntAaI",
+};
+var jwkPublicKeyP384 = {
+    kty: "EC",
+    crv: "P-384",
+    x: "TEsQRAL-nau4K75XNynuR6fdoTGGm5X1XgOrR5iSziBVqhRYOAteuF8-U0wxN89s",
+    y: "r-Wn9YIXJ_r7uNN5s9eVeXElm6ZcTGvYKg6GtKJXUXuJUZRMF7EIB_H6xpOmthV6",
+};
+var rsaSpkiKey = Base64URL.parse("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwCjRCtFwvSNYMZ07u5SxARxglJl75T7bUZXFsDVxHkMhpNC2RaN4jWE5bwYUDMeD2fVmxhpaUQn/6AbFLh6gHxtwrCfc7rIo/SfDdGd3GkRlXK5xXwGuM6MvP9nuZHaarIyArRFh2U2UZxFlVsKI0pSHo6n58W1fPZ1syOoVEZ/WYE6gLhMMwfpeAm97mro7mekRdMULOV/mR5Ul3CHm9Zt93Dc8GpnPA8bhLiB0VNyGTEMa06nJul4gj1sjxLDoUvZY2EWq7oUUnfLBUYMfiqK0kQcW94wvBrIq2DQUApLyTTbaAOY46TLwX6c8LtubJriYKTC5a9Bb0/7ovTWB0wIDAQAB");
+
+crypto.subtle.importKey("jwk", jwkPrivateKey, { name: "ECDH", namedCurve: "P-256" }, extractable, ["deriveBits"]).then(function(result) {
+    privateKey = result;
+    return crypto.subtle.importKey("jwk", jwkPublicKey, { name: "ECDH", namedCurve: "P-256" }, extractable, [ ]);
+}).then(function(result) {
+    publicKey = result;
+    return crypto.subtle.importKey("spki", rsaSpkiKey, {name: "RSA-OAEP", hash: "sha-1"}, extractable, ["encrypt", "wrapKey"]);
+}).then(function(result) {
+    fakeKey = result;
+    return crypto.subtle.importKey("jwk", jwkPublicKeyP384, { name: "ECDH", namedCurve: "P-384" }, extractable, [ ]);
+}).then(function(result) {
+    publicKeyP384 = result;
+    // Malformed AlgorithmIdentifiers
+    shouldReject('crypto.subtle.deriveBits("ecdh", privateKey, null)');
+    shouldReject('crypto.subtle.deriveBits({name: "ecdh"}, privateKey, null)');
+    shouldReject('crypto.subtle.deriveBits({name: "ecdh", public: true}, privateKey, null)');
+    shouldReject('crypto.subtle.deriveBits({name: "ecdh", public: null}, privateKey, null)');
+    shouldReject('crypto.subtle.deriveBits({name: "ecdh", public: undefined}, privateKey, null)');
+    shouldReject('crypto.subtle.deriveBits({name: "ecdh", public: Symbol()}, privateKey, null)');
+    shouldReject('crypto.subtle.deriveBits({name: "ecdh", public: { }}, privateKey, null)');
+    shouldReject('crypto.subtle.deriveBits({name: "ecdh", public: 1}, privateKey, null)');
+    // Wrong length
+    shouldReject('crypto.subtle.deriveBits({ name:"ECDH", public:publicKey }, privateKey, 1)');
+    // base key is public
+    shouldReject('crypto.subtle.deriveBits({ name:"ECDH", public:publicKey }, publicKey, null)');
+    // public key is private
+    shouldReject('crypto.subtle.deriveBits({ name:"ECDH", public:privateKey }, privateKey, null)');
+    // faked public key
+    shouldReject('crypto.subtle.deriveBits({ name:"ECDH", public:fakeKey }, privateKey, null)');
+    // mismatched named curve
+    shouldReject('crypto.subtle.deriveBits({ name:"ECDH", public:publicKeyP384 }, privateKey, null)');
+    // Wrong length
+    return shouldReject('crypto.subtle.deriveBits({ name:"ECDH", public:publicKey }, privateKey, 384)');
+}).then(finishJSTest, finishJSTest);
+
+</script>
+
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/crypto/subtle/ecdh-generate-key-derive-bits-expected.txt b/LayoutTests/crypto/subtle/ecdh-generate-key-derive-bits-expected.txt
new file mode 100644 (file)
index 0000000..a4d33cb
--- /dev/null
@@ -0,0 +1,10 @@
+Test ECDH deriveBits operation with generated base key and null length
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS derivedKey.byteLength is 32
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/crypto/subtle/ecdh-generate-key-derive-bits.html b/LayoutTests/crypto/subtle/ecdh-generate-key-derive-bits.html
new file mode 100644 (file)
index 0000000..1e643a6
--- /dev/null
@@ -0,0 +1,42 @@
+<!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 ECDH deriveBits operation with generated base key and null length");
+
+jsTestIsAsync = true;
+
+var extractable = true;
+var jwkPublicKey = {
+    kty: "EC",
+    crv: "P-256",
+    x: "1FSVWieTvikFkG1NOyhkUCaMbdQhxwH6aCu4Ez-sRtA",
+    y: "9jmNTLqM4cjBhdAnHcNI9YQV3O8LFmo-EdZWk8ntAaI",
+};
+
+crypto.subtle.generateKey({ name: "ECDH", namedCurve: "P-256" }, extractable, ["deriveBits"]).then(function(result) {
+    privateKey = result.privateKey;
+    return crypto.subtle.importKey("jwk", jwkPublicKey, { name: "ECDH", namedCurve: "P-256" }, extractable, [ ]);
+}).then(function(result) {
+    publicKey = result;
+    return crypto.subtle.deriveBits({ name:"ECDH", public:publicKey }, privateKey, null);
+}).then(function(result) {
+    derivedKey = result;
+
+    shouldBe("derivedKey.byteLength", "32");
+
+    finishJSTest();
+}, failAndFinishJSTest);
+
+</script>
+
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/crypto/subtle/ecdh-import-key-derive-bits-custom-length-expected.txt b/LayoutTests/crypto/subtle/ecdh-import-key-derive-bits-custom-length-expected.txt
new file mode 100644 (file)
index 0000000..924d18e
--- /dev/null
@@ -0,0 +1,10 @@
+Test ECDH deriveBits operation with imported base key and custom length
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS bytesToHexString(derivedKey) is expectedDerivedKey
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/crypto/subtle/ecdh-import-key-derive-bits-custom-length.html b/LayoutTests/crypto/subtle/ecdh-import-key-derive-bits-custom-length.html
new file mode 100644 (file)
index 0000000..e869ff3
--- /dev/null
@@ -0,0 +1,50 @@
+<!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 ECDH deriveBits operation with imported base key and custom length");
+
+jsTestIsAsync = true;
+
+var extractable = true;
+var jwkPrivateKey = {
+    kty: "EC",
+    crv: "P-256",
+    x: "1FSVWieTvikFkG1NOyhkUCaMbdQhxwH6aCu4Ez-sRtA",
+    y: "9jmNTLqM4cjBhdAnHcNI9YQV3O8LFmo-EdZWk8ntAaI",
+    d: "ppxBSov3N8_AUcisAuvmLV4yE8e_L_BLE8bZb9Z1Xjg",
+};
+var jwkPublicKey = {
+    kty: "EC",
+    crv: "P-256",
+    x: "1FSVWieTvikFkG1NOyhkUCaMbdQhxwH6aCu4Ez-sRtA",
+    y: "9jmNTLqM4cjBhdAnHcNI9YQV3O8LFmo-EdZWk8ntAaI",
+};
+var expectedDerivedKey = "40bf0c0a56f75ca587ea4f6729d7bf9a";
+
+crypto.subtle.importKey("jwk", jwkPrivateKey, { name: "ECDH", namedCurve: "P-256" }, extractable, ["deriveBits"]).then(function(result) {
+    privateKey = result;
+    return crypto.subtle.importKey("jwk", jwkPublicKey, { name: "ECDH", namedCurve: "P-256" }, extractable, [ ]);
+}).then(function(result) {
+    publicKey = result;
+    return crypto.subtle.deriveBits({ name:"ECDH", public:publicKey }, privateKey, 128);
+}).then(function(result) {
+    derivedKey = result;
+
+    shouldBe("bytesToHexString(derivedKey)", "expectedDerivedKey");
+
+    finishJSTest();
+}, failAndFinishJSTest);
+
+</script>
+
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/crypto/subtle/ecdh-import-key-derive-bits-null-length-expected.txt b/LayoutTests/crypto/subtle/ecdh-import-key-derive-bits-null-length-expected.txt
new file mode 100644 (file)
index 0000000..b2886f8
--- /dev/null
@@ -0,0 +1,10 @@
+Test ECDH deriveBits operation with imported base key and null length
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS bytesToHexString(derivedKey) is expectedDerivedKey
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/crypto/subtle/ecdh-import-key-derive-bits-null-length.html b/LayoutTests/crypto/subtle/ecdh-import-key-derive-bits-null-length.html
new file mode 100644 (file)
index 0000000..f889716
--- /dev/null
@@ -0,0 +1,50 @@
+<!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 ECDH deriveBits operation with imported base key and null length");
+
+jsTestIsAsync = true;
+
+var extractable = true;
+var jwkPrivateKey = {
+    kty: "EC",
+    crv: "P-256",
+    x: "1FSVWieTvikFkG1NOyhkUCaMbdQhxwH6aCu4Ez-sRtA",
+    y: "9jmNTLqM4cjBhdAnHcNI9YQV3O8LFmo-EdZWk8ntAaI",
+    d: "ppxBSov3N8_AUcisAuvmLV4yE8e_L_BLE8bZb9Z1Xjg",
+};
+var jwkPublicKey = {
+    kty: "EC",
+    crv: "P-256",
+    x: "1FSVWieTvikFkG1NOyhkUCaMbdQhxwH6aCu4Ez-sRtA",
+    y: "9jmNTLqM4cjBhdAnHcNI9YQV3O8LFmo-EdZWk8ntAaI",
+};
+var expectedDerivedKey = "40bf0c0a56f75ca587ea4f6729d7bf9a30c5f4a0d47eea13fdf9da8f0b53b85e";
+
+crypto.subtle.importKey("jwk", jwkPrivateKey, { name: "ECDH", namedCurve: "P-256" }, extractable, ["deriveBits"]).then(function(result) {
+    privateKey = result;
+    return crypto.subtle.importKey("jwk", jwkPublicKey, { name: "ECDH", namedCurve: "P-256" }, extractable, [ ]);
+}).then(function(result) {
+    publicKey = result;
+    return crypto.subtle.deriveBits({ name:"ECDH", public:publicKey }, privateKey, null);
+}).then(function(result) {
+    derivedKey = result;
+
+    shouldBe("bytesToHexString(derivedKey)", "expectedDerivedKey");
+
+    finishJSTest();
+}, failAndFinishJSTest);
+
+</script>
+
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/crypto/workers/subtle/ecdh-import-key-derive-bits-expected.txt b/LayoutTests/crypto/workers/subtle/ecdh-import-key-derive-bits-expected.txt
new file mode 100644 (file)
index 0000000..824d37b
--- /dev/null
@@ -0,0 +1,11 @@
+[Worker] Test ECDH deriveBits operation with imported base key in workers
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Starting worker: resources/ecdh-import-key-derive-bits.js
+PASS [Worker] bytesToHexString(derivedKey) is expectedDerivedKey
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/crypto/workers/subtle/ecdh-import-key-derive-bits.html b/LayoutTests/crypto/workers/subtle/ecdh-import-key-derive-bits.html
new file mode 100644 (file)
index 0000000..037fa15
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="../../../resources/js-test-pre.js"></script>
+</head>
+<body>
+    <script>
+        worker = startWorker('resources/ecdh-import-key-derive-bits.js');
+    </script>
+    <script src="../../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/crypto/workers/subtle/resources/ecdh-import-key-derive-bits.js b/LayoutTests/crypto/workers/subtle/resources/ecdh-import-key-derive-bits.js
new file mode 100644 (file)
index 0000000..072697a
--- /dev/null
@@ -0,0 +1,36 @@
+importScripts('../../../../resources/js-test-pre.js');
+importScripts("../../../resources/common.js");
+
+description("Test ECDH deriveBits operation with imported base key in workers");
+
+jsTestIsAsync = true;
+
+var extractable = true;
+var jwkPrivateKey = {
+    kty: "EC",
+    crv: "P-256",
+    x: "1FSVWieTvikFkG1NOyhkUCaMbdQhxwH6aCu4Ez-sRtA",
+    y: "9jmNTLqM4cjBhdAnHcNI9YQV3O8LFmo-EdZWk8ntAaI",
+    d: "ppxBSov3N8_AUcisAuvmLV4yE8e_L_BLE8bZb9Z1Xjg",
+};
+var jwkPublicKey = {
+    kty: "EC",
+    crv: "P-256",
+    x: "1FSVWieTvikFkG1NOyhkUCaMbdQhxwH6aCu4Ez-sRtA",
+    y: "9jmNTLqM4cjBhdAnHcNI9YQV3O8LFmo-EdZWk8ntAaI",
+};
+var expectedDerivedKey = "40bf0c0a56f75ca587ea4f6729d7bf9a30c5f4a0d47eea13fdf9da8f0b53b85e";
+
+crypto.subtle.importKey("jwk", jwkPrivateKey, { name: "ECDH", namedCurve: "P-256" }, extractable, ["deriveBits"]).then(function(result) {
+    privateKey = result;
+    return crypto.subtle.importKey("jwk", jwkPublicKey, { name: "ECDH", namedCurve: "P-256" }, extractable, [ ]);
+}).then(function(result) {
+    publicKey = result;
+    return crypto.subtle.deriveBits({ name:"ECDH", public:publicKey }, privateKey, null);
+}).then(function(result) {
+    derivedKey = result;
+
+    shouldBe("bytesToHexString(derivedKey)", "expectedDerivedKey");
+
+    finishJSTest();
+}, failAndFinishJSTest);
index 1d89562..779ba19 100644 (file)
@@ -344,6 +344,7 @@ set(WebCore_NON_SVG_IDL_FILES
     crypto/parameters/AesGcmParams.idl
     crypto/parameters/AesKeyGenParams.idl
     crypto/parameters/EcKeyParams.idl
+    crypto/parameters/EcdhKeyDeriveParams.idl
     crypto/parameters/HmacKeyParams.idl
     crypto/parameters/RsaHashedImportParams.idl
     crypto/parameters/RsaHashedKeyGenParams.idl
index 6bc1f45..58d9265 100644 (file)
@@ -1,3 +1,48 @@
+2017-03-08  Jiewen Tan  <jiewen_tan@apple.com>
+
+        [WebCrypto] Implement ECDH DeriveBits operation
+        https://bugs.webkit.org/show_bug.cgi?id=169319
+        <rdar://problem/23789585>
+
+        Reviewed by Brent Fulgham.
+
+        This patch implements DeriveBits operation of ECDH according to the spec:
+        https://www.w3.org/TR/WebCryptoAPI/#ecdh-operations.
+
+        Tests: crypto/subtle/derive-bits-malformed-parameters.html
+               crypto/subtle/ecdh-derive-bits-malformed-parametrs.html
+               crypto/subtle/ecdh-generate-key-derive-bits.html
+               crypto/subtle/ecdh-import-key-derive-bits-custom-length.html
+               crypto/subtle/ecdh-import-key-derive-bits-null-length.html
+               crypto/workers/subtle/ecdh-import-key-derive-bits.html
+
+        * CMakeLists.txt:
+        * DerivedSources.make:
+        * PlatformGTK.cmake:
+        * PlatformMac.cmake:
+        * WebCore.xcodeproj/project.pbxproj:
+        * bindings/js/JSSubtleCryptoCustom.cpp:
+        (WebCore::normalizeCryptoAlgorithmParameters):
+        (WebCore::jsSubtleCryptoFunctionDeriveKeyPromise):
+        (WebCore::jsSubtleCryptoFunctionDeriveBitsPromise):
+        (WebCore::JSSubtleCrypto::generateKey):
+        Reorder a bit of the functions.
+        * crypto/CommonCryptoUtilities.h:
+        * crypto/CryptoAlgorithm.cpp:
+        (WebCore::CryptoAlgorithm::deriveBits):
+        * crypto/CryptoAlgorithm.h:
+        * crypto/CryptoAlgorithmParameters.h:
+        * crypto/algorithms/CryptoAlgorithmECDH.cpp:
+        (WebCore::CryptoAlgorithmECDH::deriveBits):
+        * crypto/algorithms/CryptoAlgorithmECDH.h:
+        * crypto/gnutls/CryptoAlgorithmECDHGnuTLS.cpp: Added.
+        (WebCore::CryptoAlgorithmECDH::platformDeriveBits):
+        * crypto/keys/CryptoKeyEC.h:
+        * crypto/mac/CryptoAlgorithmECDHMac.cpp: Added.
+        (WebCore::CryptoAlgorithmECDH::platformDeriveBits):
+        * crypto/parameters/CryptoAlgorithmEcdhKeyDeriveParams.h: Added.
+        * crypto/parameters/EcdhKeyDeriveParams.idl: Added.
+
 2017-03-08  John Wilander  <wilander@apple.com>
 
         Resource Load Statistics: Communicate to the network process which domains to partition
index 1f057f2..665e0c3 100644 (file)
@@ -276,6 +276,7 @@ JS_BINDING_IDLS = \
     $(WebCore)/crypto/parameters/AesGcmParams.idl \
     $(WebCore)/crypto/parameters/AesKeyGenParams.idl \
     $(WebCore)/crypto/parameters/EcKeyParams.idl \
+    $(WebCore)/crypto/parameters/EcdhKeyDeriveParams.idl \
     $(WebCore)/crypto/parameters/HmacKeyParams.idl \
     $(WebCore)/crypto/parameters/RsaHashedImportParams.idl \
     $(WebCore)/crypto/parameters/RsaHashedKeyGenParams.idl \
index 3cd0db9..2f9e911 100644 (file)
@@ -403,6 +403,7 @@ if (ENABLE_SUBTLE_CRYPTO)
         crypto/gnutls/CryptoAlgorithmAES_CFBGnuTLS.cpp
         crypto/gnutls/CryptoAlgorithmAES_GCMGnuTLS.cpp
         crypto/gnutls/CryptoAlgorithmAES_KWGnuTLS.cpp
+        crypto/gnutls/CryptoAlgorithmECDHGnuTLS.cpp
         crypto/gnutls/CryptoAlgorithmRSAES_PKCS1_v1_5GnuTLS.cpp
         crypto/gnutls/CryptoAlgorithmRSASSA_PKCS1_v1_5GnuTLS.cpp
         crypto/gnutls/CryptoAlgorithmRSA_OAEPGnuTLS.cpp
index 8058280..894c9bd 100644 (file)
@@ -206,6 +206,7 @@ list(APPEND WebCore_SOURCES
     crypto/mac/CryptoAlgorithmAES_CFBMac.cpp
     crypto/mac/CryptoAlgorithmAES_GCMMac.cpp
     crypto/mac/CryptoAlgorithmAES_KWMac.cpp
+    crypto/mac/CryptoAlgorithmECDHMac.cpp
     crypto/mac/CryptoAlgorithmHMACMac.cpp
     crypto/mac/CryptoAlgorithmRSAES_PKCS1_v1_5Mac.cpp
     crypto/mac/CryptoAlgorithmRSASSA_PKCS1_v1_5Mac.cpp
index 3108f84..c25992a 100644 (file)
                5750A9821E6A150800705C4A /* JSEcKeyParams.h in Headers */ = {isa = PBXBuildFile; fileRef = 5750A9801E6A150800705C4A /* JSEcKeyParams.h */; };
                5750A9861E6A216800705C4A /* CryptoAlgorithmECDH.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5750A9841E6A216800705C4A /* CryptoAlgorithmECDH.cpp */; };
                5750A9871E6A216800705C4A /* CryptoAlgorithmECDH.h in Headers */ = {isa = PBXBuildFile; fileRef = 5750A9851E6A216800705C4A /* CryptoAlgorithmECDH.h */; };
+               5768142A1E6F99C100E77754 /* CryptoAlgorithmEcdhKeyDeriveParams.h in Headers */ = {isa = PBXBuildFile; fileRef = 576814291E6F99C100E77754 /* CryptoAlgorithmEcdhKeyDeriveParams.h */; };
+               576814351E6FE3E800E77754 /* CryptoAlgorithmECDHMac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 576814341E6FE3E800E77754 /* CryptoAlgorithmECDHMac.cpp */; };
+               576814401E709FA100E77754 /* JSEcdhKeyDeriveParams.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5768143D1E709C3600E77754 /* JSEcdhKeyDeriveParams.cpp */; };
+               576814411E709FA400E77754 /* JSEcdhKeyDeriveParams.h in Headers */ = {isa = PBXBuildFile; fileRef = 5768143E1E709C3600E77754 /* JSEcdhKeyDeriveParams.h */; };
                5768E4341DB7524500D0A4F7 /* JSRsaHashedKeyGenParams.h in Headers */ = {isa = PBXBuildFile; fileRef = 5768E4331DB7524500D0A4F7 /* JSRsaHashedKeyGenParams.h */; };
                5768E4361DB7527400D0A4F7 /* JSRsaHashedKeyGenParams.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5768E4351DB7527300D0A4F7 /* JSRsaHashedKeyGenParams.cpp */; };
                577483121DADC55D00716EF9 /* CryptoAlgorithmAesKeyGenParams.h in Headers */ = {isa = PBXBuildFile; fileRef = 577483111DADC55D00716EF9 /* CryptoAlgorithmAesKeyGenParams.h */; };
                5750A9801E6A150800705C4A /* JSEcKeyParams.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSEcKeyParams.h; sourceTree = "<group>"; };
                5750A9841E6A216800705C4A /* CryptoAlgorithmECDH.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CryptoAlgorithmECDH.cpp; sourceTree = "<group>"; };
                5750A9851E6A216800705C4A /* CryptoAlgorithmECDH.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CryptoAlgorithmECDH.h; sourceTree = "<group>"; };
+               576814281E6F98AD00E77754 /* EcdhKeyDeriveParams.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = EcdhKeyDeriveParams.idl; sourceTree = "<group>"; };
+               576814291E6F99C100E77754 /* CryptoAlgorithmEcdhKeyDeriveParams.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CryptoAlgorithmEcdhKeyDeriveParams.h; sourceTree = "<group>"; };
+               576814341E6FE3E800E77754 /* CryptoAlgorithmECDHMac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CryptoAlgorithmECDHMac.cpp; sourceTree = "<group>"; };
+               5768143D1E709C3600E77754 /* JSEcdhKeyDeriveParams.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSEcdhKeyDeriveParams.cpp; sourceTree = "<group>"; };
+               5768143E1E709C3600E77754 /* JSEcdhKeyDeriveParams.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSEcdhKeyDeriveParams.h; sourceTree = "<group>"; };
                5768E4331DB7524500D0A4F7 /* JSRsaHashedKeyGenParams.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSRsaHashedKeyGenParams.h; sourceTree = "<group>"; };
                5768E4351DB7527300D0A4F7 /* JSRsaHashedKeyGenParams.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSRsaHashedKeyGenParams.cpp; sourceTree = "<group>"; };
                577483101DADC49900716EF9 /* AesKeyGenParams.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = AesKeyGenParams.idl; sourceTree = "<group>"; };
                                570440571E53851600356601 /* CryptoAlgorithmAES_CFBMac.cpp */,
                                57B5F80D1E5D2F2D00F34F90 /* CryptoAlgorithmAES_GCMMac.cpp */,
                                E1FE137C184D270200892F13 /* CryptoAlgorithmAES_KWMac.cpp */,
+                               576814341E6FE3E800E77754 /* CryptoAlgorithmECDHMac.cpp */,
                                E125F8371822F1EB00D84CD9 /* CryptoAlgorithmHMACMac.cpp */,
                                E1BB84AC1822CA7400525043 /* CryptoAlgorithmRegistryMac.cpp */,
                                E1FE136E183FECF000892F13 /* CryptoAlgorithmRSA_OAEPMac.cpp */,
                                577483111DADC55D00716EF9 /* CryptoAlgorithmAesKeyGenParams.h */,
                                E19AC3F61824E5D100349426 /* CryptoAlgorithmAesKeyGenParamsDeprecated.h */,
                                5750A97D1E6A13EF00705C4A /* CryptoAlgorithmEcKeyParams.h */,
+                               576814291E6F99C100E77754 /* CryptoAlgorithmEcdhKeyDeriveParams.h */,
                                577483181DB4491F00716EF9 /* CryptoAlgorithmHmacKeyParams.h */,
                                E19DA29B18189ADD00088BC8 /* CryptoAlgorithmHmacKeyParamsDeprecated.h */,
                                E1C6571E1816E50300256CDD /* CryptoAlgorithmHmacParamsDeprecated.h */,
                                E1FE1376184D1E3300892F13 /* CryptoAlgorithmRsaOaepParamsDeprecated.h */,
                                E1BD331B182D8EE900C05D9F /* CryptoAlgorithmRsaSsaParamsDeprecated.h */,
                                5750A97C1E6A12B400705C4A /* EcKeyParams.idl */,
+                               576814281E6F98AD00E77754 /* EcdhKeyDeriveParams.idl */,
                                577483171DB1FE8900716EF9 /* HmacKeyParams.idl */,
                                57E2336C1DCD437000F28D01 /* RsaHashedImportParams.idl */,
                                57F827391DB72C22009D2BF4 /* RsaHashedKeyGenParams.idl */,
                                57D0018C1DD5413200ED19D9 /* JSCryptoKeyUsage.h */,
                                5750A97F1E6A150800705C4A /* JSEcKeyParams.cpp */,
                                5750A9801E6A150800705C4A /* JSEcKeyParams.h */,
+                               5768143D1E709C3600E77754 /* JSEcdhKeyDeriveParams.cpp */,
+                               5768143E1E709C3600E77754 /* JSEcdhKeyDeriveParams.h */,
                                57E233681DCAB24300F28D01 /* JSHmacKeyParams.cpp */,
                                57E233661DCAB21C00F28D01 /* JSHmacKeyParams.h */,
                                57E2335E1DC7D67B00F28D01 /* JSJsonWebKey.cpp */,
                                1AE96A911D1A0DDD00B86768 /* JSApplePayShippingContactSelectedEvent.h in Headers */,
                                7C6579F41E00856600E3A27A /* JSApplePayShippingMethod.h in Headers */,
                                1AE96A931D1A0DDD00B86768 /* JSApplePayShippingMethodSelectedEvent.h in Headers */,
+                               576814411E709FA400E77754 /* JSEcdhKeyDeriveParams.h in Headers */,
                                65DF31DB09D1C123000BE325 /* JSAttr.h in Headers */,
                                FDA15E9E12B03EE1003A583A /* JSAudioBuffer.h in Headers */,
                                FDF7E9C413AC21DB00A51EAC /* JSAudioBufferCallback.h in Headers */,
                                A8EA800A0A19516E00A8EF5F /* StyleSheetList.h in Headers */,
                                BC5EB5E50E81BF6D00B25965 /* StyleSurroundData.h in Headers */,
                                BC5EB8100E81F2CE00B25965 /* StyleTransformData.h in Headers */,
+                               5768142A1E6F99C100E77754 /* CryptoAlgorithmEcdhKeyDeriveParams.h in Headers */,
                                E4DEAA1817A93DC3000E0430 /* StyleTreeResolver.h in Headers */,
                                E42E76DC1C7AF77600E3614D /* StyleUpdate.h in Headers */,
                                E48137B91DB3B526005C59BF /* StyleValidity.h in Headers */,
                                A871DB260A150BD600B12A68 /* HTMLTableSectionElement.cpp in Sources */,
                                D66817FA166FE6D700FA07B4 /* HTMLTemplateElement.cpp in Sources */,
                                A81369D7097374F600D74463 /* HTMLTextAreaElement.cpp in Sources */,
+                               576814401E709FA100E77754 /* JSEcdhKeyDeriveParams.cpp in Sources */,
                                9BC6C21C13CCC97B008E0337 /* HTMLTextFormControlElement.cpp in Sources */,
                                830519951BB0F11000F3772E /* HTMLTimeElement.cpp in Sources */,
                                A871DC290A15205700B12A68 /* HTMLTitleElement.cpp in Sources */,
                                76FB9FF819A73E3A00420562 /* JSAutocompleteErrorEvent.cpp in Sources */,
                                BC124EFF0C26447A009E2349 /* JSBarProp.cpp in Sources */,
                                BC946346107A934B00857193 /* JSBeforeLoadEvent.cpp in Sources */,
+                               576814351E6FE3E800E77754 /* CryptoAlgorithmECDHMac.cpp in Sources */,
                                70F546E8B8B5D7DC54EE144E /* JSBeforeUnloadEvent.cpp in Sources */,
                                FDF09DC81399B62200688E5B /* JSBiquadFilterNode.cpp in Sources */,
                                2E2D99CD10E2BBDA00496337 /* JSBlob.cpp in Sources */,
index 46ff351..8ac9728 100644 (file)
@@ -39,6 +39,7 @@
 #include "JSDOMPromise.h"
 #include "JSDOMWrapper.h"
 #include "JSEcKeyParams.h"
+#include "JSEcdhKeyDeriveParams.h"
 #include "JSHmacKeyParams.h"
 #include "JSJsonWebKey.h"
 #include "JSRsaHashedImportParams.h"
@@ -160,9 +161,28 @@ static std::unique_ptr<CryptoAlgorithmParameters> normalizeCryptoAlgorithmParame
             }
             break;
         case Operations::DeriveKey:
-        case Operations::DeriveBits:
             throwNotSupportedError(state, scope);
             return nullptr;
+        case Operations::DeriveBits:
+            switch (*identifier) {
+            case CryptoAlgorithmIdentifier::ECDH: {
+                // Remove this hack once https://bugs.webkit.org/show_bug.cgi?id=169333 is fixed.
+                JSValue nameValue = value.getObject()->get(&state, Identifier::fromString(&state, "name"));
+                JSValue publicValue = value.getObject()->get(&state, Identifier::fromString(&state, "public"));
+                JSObject* newValue = constructEmptyObject(&state);
+                newValue->putDirect(vm, Identifier::fromString(&vm, "name"), nameValue);
+                newValue->putDirect(vm, Identifier::fromString(&vm, "publicKey"), publicValue);
+
+                auto params = convertDictionary<CryptoAlgorithmEcdhKeyDeriveParams>(state, newValue);
+                RETURN_IF_EXCEPTION(scope, nullptr);
+                result = std::make_unique<CryptoAlgorithmEcdhKeyDeriveParams>(params);
+                break;
+            }
+            default:
+                throwNotSupportedError(state, scope);
+                return nullptr;
+            }
+            break;
         case Operations::GenerateKey:
             switch (*identifier) {
             case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5: {
@@ -660,40 +680,6 @@ static void jsSubtleCryptoFunctionDigestPromise(ExecState& state, Ref<DeferredPr
     algorithm->digest(WTFMove(data), WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContextFromExecState(&state), subtle->wrapped().workQueue());
 }
 
-static void jsSubtleCryptoFunctionDeriveKeyPromise(ExecState& state, Ref<DeferredPromise>&& promise)
-{
-    VM& vm = state.vm();
-    auto scope = DECLARE_THROW_SCOPE(vm);
-
-    if (UNLIKELY(state.argumentCount() < 5)) {
-        promise->reject<IDLAny>(createNotEnoughArgumentsError(&state));
-        return;
-    }
-
-    auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(0), Operations::DeriveKey);
-    RETURN_IF_EXCEPTION(scope, void());
-
-    // We should always return a NOT_SUPPORTED_ERR since we currently don't support any algorithms that has deriveKey operation.
-    ASSERT_NOT_REACHED();
-}
-
-static void jsSubtleCryptoFunctionDeriveBitsPromise(ExecState& state, Ref<DeferredPromise>&& promise)
-{
-    VM& vm = state.vm();
-    auto scope = DECLARE_THROW_SCOPE(vm);
-
-    if (UNLIKELY(state.argumentCount() < 3)) {
-        promise->reject<IDLAny>(createNotEnoughArgumentsError(&state));
-        return;
-    }
-
-    auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(0), Operations::DeriveBits);
-    RETURN_IF_EXCEPTION(scope, void());
-
-    // We should always return a NOT_SUPPORTED_ERR since we currently don't support any algorithms that has deriveBits operation.
-    ASSERT_NOT_REACHED();
-}
-
 static void jsSubtleCryptoFunctionGenerateKeyPromise(ExecState& state, Ref<DeferredPromise>&& promise)
 {
     VM& vm = state.vm();
@@ -747,6 +733,71 @@ static void jsSubtleCryptoFunctionGenerateKeyPromise(ExecState& state, Ref<Defer
     algorithm->generateKey(*params, extractable, keyUsages, WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContextFromExecState(&state));
 }
 
+static void jsSubtleCryptoFunctionDeriveKeyPromise(ExecState& state, Ref<DeferredPromise>&& promise)
+{
+    VM& vm = state.vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    if (UNLIKELY(state.argumentCount() < 5)) {
+        promise->reject<IDLAny>(createNotEnoughArgumentsError(&state));
+        return;
+    }
+
+    auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(0), Operations::DeriveKey);
+    RETURN_IF_EXCEPTION(scope, void());
+
+    // We should always return a NOT_SUPPORTED_ERR since we currently don't support any algorithms that has deriveKey operation.
+    ASSERT_NOT_REACHED();
+}
+
+static void jsSubtleCryptoFunctionDeriveBitsPromise(ExecState& state, Ref<DeferredPromise>&& promise)
+{
+    VM& vm = state.vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    if (UNLIKELY(state.argumentCount() < 3)) {
+        promise->reject<IDLAny>(createNotEnoughArgumentsError(&state));
+        return;
+    }
+
+    auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(0), Operations::DeriveBits);
+    RETURN_IF_EXCEPTION(scope, void());
+
+    auto baseKey = toCryptoKey(state, state.uncheckedArgument(1));
+    RETURN_IF_EXCEPTION(scope, void());
+
+    auto length = convert<IDLUnsignedLong>(state, state.uncheckedArgument(2), IntegerConversionConfiguration::Normal);
+    RETURN_IF_EXCEPTION(scope, void());
+
+    if (params->identifier != baseKey->algorithmIdentifier()) {
+        promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't match AlgorithmIdentifier"));
+        return;
+    }
+
+    if (!baseKey->allows(CryptoKeyUsageDeriveBits)) {
+        promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't support bits derivation"));
+        return;
+    }
+
+    auto algorithm = CryptoAlgorithmRegistry::singleton().create(params->identifier);
+    if (UNLIKELY(!algorithm)) {
+        throwNotSupportedError(state, scope);
+        return;
+    }
+
+    auto callback = [capturedPromise = promise.copyRef()](const Vector<uint8_t>& derivedKey) mutable {
+        fulfillPromiseWithArrayBuffer(WTFMove(capturedPromise), derivedKey.data(), derivedKey.size());
+        return;
+    };
+    auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable {
+        rejectWithException(WTFMove(capturedPromise), ec);
+    };
+
+    auto subtle = jsDynamicDowncast<JSSubtleCrypto*>(vm, state.thisValue());
+    ASSERT(subtle);
+    algorithm->deriveBits(WTFMove(params), baseKey.releaseNonNull(), length, WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContextFromExecState(&state), subtle->wrapped().workQueue());
+}
+
 static void jsSubtleCryptoFunctionImportKeyPromise(ExecState& state, Ref<DeferredPromise>&& promise)
 {
     VM& vm = state.vm();
@@ -1098,6 +1149,12 @@ JSValue JSSubtleCrypto::digest(ExecState& state)
     return callPromiseFunction<jsSubtleCryptoFunctionDigestPromise, PromiseExecutionScope::WindowOrWorker>(state);
 }
 
+
+JSValue JSSubtleCrypto::generateKey(ExecState& state)
+{
+    return callPromiseFunction<jsSubtleCryptoFunctionGenerateKeyPromise, PromiseExecutionScope::WindowOrWorker>(state);
+}
+
 JSValue JSSubtleCrypto::deriveKey(ExecState& state)
 {
     return callPromiseFunction<jsSubtleCryptoFunctionDeriveKeyPromise, PromiseExecutionScope::WindowOrWorker>(state);
@@ -1108,11 +1165,6 @@ JSValue JSSubtleCrypto::deriveBits(ExecState& state)
     return callPromiseFunction<jsSubtleCryptoFunctionDeriveBitsPromise, PromiseExecutionScope::WindowOrWorker>(state);
 }
 
-JSValue JSSubtleCrypto::generateKey(ExecState& state)
-{
-    return callPromiseFunction<jsSubtleCryptoFunctionGenerateKeyPromise, PromiseExecutionScope::WindowOrWorker>(state);
-}
-
 JSValue JSSubtleCrypto::importKey(ExecState& state)
 {
     return callPromiseFunction<jsSubtleCryptoFunctionImportKeyPromise, PromiseExecutionScope::WindowOrWorker>(state);
index 64cd592..f54ecc1 100644 (file)
@@ -107,7 +107,7 @@ extern "C" CCCryptorStatus CCECCryptorExportKey(CCECKeyExternalFormat format, vo
 extern "C" int CCECGetKeySize(CCECCryptorRef key);
 extern "C" CCCryptorStatus CCECCryptorCreateFromData(size_t keySize, uint8_t *qX, size_t qXLength, uint8_t *qY, size_t qYLength, CCECCryptorRef *ref);
 extern "C" CCCryptorStatus CCECCryptorGetKeyComponents(CCECCryptorRef ecKey, size_t *keySize, uint8_t *qX, size_t *qXLength, uint8_t *qY, size_t *qYLength, uint8_t *d, size_t *dLength);
-
+extern "C" CCCryptorStatus CCECCryptorComputeSharedSecret(CCECCryptorRef privateKey, CCECCryptorRef publicKey, void *out, size_t *outLen);
 
 #if !USE(APPLE_INTERNAL_SDK)
 extern "C" CCCryptorStatus CCCryptorGCM(CCOperation op, CCAlgorithm alg, const void* key, size_t keyLength, const void* iv, size_t ivLen, const void* aData, size_t aDataLen, const void* dataIn, size_t dataInLength, void* dataOut, void* tag, size_t* tagLength);
index fcca683..eff5ec7 100644 (file)
@@ -62,6 +62,11 @@ void CryptoAlgorithm::generateKey(const CryptoAlgorithmParameters&, bool, Crypto
     exceptionCallback(NOT_SUPPORTED_ERR);
 }
 
+void CryptoAlgorithm::deriveBits(std::unique_ptr<CryptoAlgorithmParameters>&&, Ref<CryptoKey>&&, unsigned long, VectorCallback&&, ExceptionCallback&& exceptionCallback, ScriptExecutionContext&, WorkQueue&)
+{
+    exceptionCallback(NOT_SUPPORTED_ERR);
+}
+
 void CryptoAlgorithm::importKey(SubtleCrypto::KeyFormat, KeyData&&, const std::unique_ptr<CryptoAlgorithmParameters>&&, bool, CryptoKeyUsageBitmap, KeyCallback&&, ExceptionCallback&& exceptionCallback)
 {
     exceptionCallback(NOT_SUPPORTED_ERR);
index c30ae32..6467bca 100644 (file)
@@ -72,6 +72,7 @@ public:
     virtual void verify(Ref<CryptoKey>&&, Vector<uint8_t>&& signature, Vector<uint8_t>&&, BoolCallback&&, ExceptionCallback&&, ScriptExecutionContext&, WorkQueue&);
     virtual void digest(Vector<uint8_t>&&, VectorCallback&&, ExceptionCallback&&, ScriptExecutionContext&, WorkQueue&);
     virtual void generateKey(const CryptoAlgorithmParameters&, bool extractable, CryptoKeyUsageBitmap, KeyOrKeyPairCallback&&, ExceptionCallback&&, ScriptExecutionContext&);
+    virtual void deriveBits(std::unique_ptr<CryptoAlgorithmParameters>&&, Ref<CryptoKey>&&, unsigned long length, VectorCallback&&, ExceptionCallback&&, ScriptExecutionContext&, WorkQueue&);
     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=169262
     virtual void importKey(SubtleCrypto::KeyFormat, KeyData&&, const std::unique_ptr<CryptoAlgorithmParameters>&&, bool extractable, CryptoKeyUsageBitmap, KeyCallback&&, ExceptionCallback&&);
     virtual void exportKey(SubtleCrypto::KeyFormat, Ref<CryptoKey>&&, KeyDataCallback&&, ExceptionCallback&&);
index 6aa633b..01ab965 100644 (file)
@@ -41,6 +41,7 @@ public:
         AesGcmParams,
         AesKeyGenParams,
         EcKeyParams,
+        EcdhKeyDeriveParams,
         HmacKeyParams,
         RsaHashedKeyGenParams,
         RsaHashedImportParams,
index fd6c105..9de41b8 100644 (file)
@@ -29,6 +29,7 @@
 #if ENABLE(SUBTLE_CRYPTO)
 
 #include "CryptoAlgorithmEcKeyParams.h"
+#include "CryptoAlgorithmEcdhKeyDeriveParams.h"
 #include "CryptoKeyEC.h"
 #include "ExceptionCode.h"
 
@@ -65,6 +66,56 @@ void CryptoAlgorithmECDH::generateKey(const CryptoAlgorithmParameters& parameter
     callback(WTFMove(pair));
 }
 
+void CryptoAlgorithmECDH::deriveBits(std::unique_ptr<CryptoAlgorithmParameters>&& parameters, Ref<CryptoKey>&& baseKey, unsigned long length, VectorCallback&& callback, ExceptionCallback&& exceptionCallback, ScriptExecutionContext& context, WorkQueue& workQueue)
+{
+    // We only accept length that is a multiple of 8.
+    if (length % 8) {
+        exceptionCallback(OperationError);
+        return;
+    }
+
+    ASSERT(parameters);
+    auto& ecParameters = downcast<CryptoAlgorithmEcdhKeyDeriveParams>(*parameters);
+
+    if (baseKey->type() != CryptoKey::Type::Private) {
+        exceptionCallback(INVALID_ACCESS_ERR);
+        return;
+    }
+    ASSERT(ecParameters.publicKey);
+    if (ecParameters.publicKey->type() != CryptoKey::Type::Public) {
+        exceptionCallback(INVALID_ACCESS_ERR);
+        return;
+    }
+    if (baseKey->algorithmIdentifier() != ecParameters.publicKey->algorithmIdentifier()) {
+        exceptionCallback(INVALID_ACCESS_ERR);
+        return;
+    }
+    auto& ecBaseKey = downcast<CryptoKeyEC>(baseKey.get());
+    auto& ecPublicKey = downcast<CryptoKeyEC>(*(ecParameters.publicKey.get()));
+    if (ecBaseKey.namedCurve() != ecPublicKey.namedCurve()) {
+        exceptionCallback(INVALID_ACCESS_ERR);
+        return;
+    }
+
+    auto unifiedCallback = [callback = WTFMove(callback), exceptionCallback = WTFMove(exceptionCallback)](std::optional<Vector<uint8_t>>&& derivedKey, unsigned long length) mutable {
+        if (!derivedKey) {
+            exceptionCallback(OperationError);
+            return;
+        }
+        if (!length) {
+            callback(WTFMove(*derivedKey));
+            return;
+        }
+        if (length / 8 > (*derivedKey).size()) {
+            exceptionCallback(OperationError);
+            return;
+        }
+        (*derivedKey).shrink(length / 8);
+        callback(WTFMove(*derivedKey));
+    };
+    platformDeriveBits(WTFMove(baseKey), ecParameters.publicKey.releaseNonNull(), length, WTFMove(unifiedCallback), context, workQueue);
+}
+
 void CryptoAlgorithmECDH::importKey(SubtleCrypto::KeyFormat format, KeyData&& data, const std::unique_ptr<CryptoAlgorithmParameters>&& parameters, bool extractable, CryptoKeyUsageBitmap usages, KeyCallback&& callback, ExceptionCallback&& exceptionCallback)
 {
     ASSERT(parameters);
index 51b462e..a395a3f 100644 (file)
@@ -42,8 +42,12 @@ private:
     CryptoAlgorithmIdentifier identifier() const final;
 
     void generateKey(const CryptoAlgorithmParameters&, bool extractable, CryptoKeyUsageBitmap, KeyOrKeyPairCallback&&, ExceptionCallback&&, ScriptExecutionContext&) final;
+    void deriveBits(std::unique_ptr<CryptoAlgorithmParameters>&&, Ref<CryptoKey>&&, unsigned long length, VectorCallback&&, ExceptionCallback&&, ScriptExecutionContext&, WorkQueue&) final;
     void importKey(SubtleCrypto::KeyFormat, KeyData&&, const std::unique_ptr<CryptoAlgorithmParameters>&&, bool extractable, CryptoKeyUsageBitmap, KeyCallback&&, ExceptionCallback&&) final;
     void exportKey(SubtleCrypto::KeyFormat, Ref<CryptoKey>&&, KeyDataCallback&&, ExceptionCallback&&) final;
+
+    using Callback = Function<void(std::optional<Vector<uint8_t>>&&, unsigned long)>;
+    void platformDeriveBits(Ref<CryptoKey>&& baseKey, Ref<CryptoKey>&& publicKey, unsigned long length, Callback&&, ScriptExecutionContext&, WorkQueue&);
 };
 
 } // namespace WebCore
diff --git a/Source/WebCore/crypto/gnutls/CryptoAlgorithmECDHGnuTLS.cpp b/Source/WebCore/crypto/gnutls/CryptoAlgorithmECDHGnuTLS.cpp
new file mode 100644 (file)
index 0000000..a7cc604
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "CryptoAlgorithmECDH.h"
+
+#if ENABLE(SUBTLE_CRYPTO)
+
+#include "NotImplemented.h"
+
+namespace WebCore {
+
+void CryptoAlgorithmECDH::platformDeriveBits(Ref<CryptoKey>&&, Ref<CryptoKey>&&, unsigned long, Callback&&, ScriptExecutionContext&, WorkQueue&)
+{
+    notImplemented();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(SUBTLE_CRYPTO)
index 5039b4e..94a6d94 100644 (file)
@@ -84,6 +84,8 @@ public:
     JsonWebKey exportJwk() const;
 
     size_t keySizeInBits() const;
+    NamedCurve namedCurve() const { return m_curve; }
+    PlatformECKey platformKey() { return m_platformKey; }
 
 private:
     CryptoKeyEC(CryptoAlgorithmIdentifier, NamedCurve, CryptoKeyType, PlatformECKey, bool extractable, CryptoKeyUsageBitmap);
diff --git a/Source/WebCore/crypto/mac/CryptoAlgorithmECDHMac.cpp b/Source/WebCore/crypto/mac/CryptoAlgorithmECDHMac.cpp
new file mode 100644 (file)
index 0000000..b38c50e
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "CryptoAlgorithmECDH.h"
+
+#if ENABLE(SUBTLE_CRYPTO)
+
+#include "CommonCryptoUtilities.h"
+#include "CryptoKeyEC.h"
+#include "ScriptExecutionContext.h"
+
+namespace WebCore {
+
+void CryptoAlgorithmECDH::platformDeriveBits(Ref<CryptoKey>&& baseKey, Ref<CryptoKey>&& publicKey, unsigned long length, Callback&& callback, ScriptExecutionContext& context, WorkQueue& workQueue)
+{
+    context.ref();
+    workQueue.dispatch([baseKey = WTFMove(baseKey), publicKey = WTFMove(publicKey), length, callback = WTFMove(callback), &context]() mutable {
+        auto& ecBaseKey = downcast<CryptoKeyEC>(baseKey.get());
+        auto& ecPublicKey = downcast<CryptoKeyEC>(publicKey.get());
+
+        std::optional<Vector<uint8_t>> result = std::nullopt;
+        Vector<uint8_t> derivedKey(ecBaseKey.keySizeInBits() / 8); // Per https://tools.ietf.org/html/rfc6090#section-4.
+        size_t size = derivedKey.size();
+        if (!CCECCryptorComputeSharedSecret(ecBaseKey.platformKey(), ecPublicKey.platformKey(), derivedKey.data(), &size))
+            result = WTFMove(derivedKey);
+
+        context.postTask([result = WTFMove(result), length, callback = WTFMove(callback)](ScriptExecutionContext& context) mutable {
+            callback(WTFMove(result), length);
+            context.deref();
+        });
+    });
+}
+
+}
+
+#endif // ENABLE(SUBTLE_CRYPTO)
diff --git a/Source/WebCore/crypto/parameters/CryptoAlgorithmEcdhKeyDeriveParams.h b/Source/WebCore/crypto/parameters/CryptoAlgorithmEcdhKeyDeriveParams.h
new file mode 100644 (file)
index 0000000..a700947
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "CryptoAlgorithmParameters.h"
+#include <wtf/RefCounted.h>
+
+#if ENABLE(SUBTLE_CRYPTO)
+
+namespace WebCore {
+
+class CryptoKey;
+
+class CryptoAlgorithmEcdhKeyDeriveParams final : public CryptoAlgorithmParameters {
+public:
+    RefPtr<CryptoKey> publicKey;
+
+    Class parametersClass() const final { return Class::EcdhKeyDeriveParams; }
+};
+
+} // namespace WebCore
+
+SPECIALIZE_TYPE_TRAITS_CRYPTO_ALGORITHM_PARAMETERS(EcdhKeyDeriveParams)
+
+#endif // ENABLE(SUBTLE_CRYPTO)
diff --git a/Source/WebCore/crypto/parameters/EcdhKeyDeriveParams.idl b/Source/WebCore/crypto/parameters/EcdhKeyDeriveParams.idl
new file mode 100644 (file)
index 0000000..b9edb72
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+[
+    Conditional=SUBTLE_CRYPTO,
+    ImplementedAs=CryptoAlgorithmEcdhKeyDeriveParams,
+] dictionary EcdhKeyDeriveParams : CryptoAlgorithmParameters {
+    // We should rename this to public once https://bugs.webkit.org/show_bug.cgi?id=169333 is fixed.
+    // The peer's EC public key.
+    required CryptoKey publicKey;
+};