[WebCrypto] Support SPKI/PKCS8 for Elliptic Curve
https://bugs.webkit.org/show_bug.cgi?id=169318
<rdar://problem/31081956>

Reviewed by Brent Fulgham.

LayoutTests/imported/w3c:

* web-platform-tests/WebCryptoAPI/import_export/ec_importKey.worker-expected.txt:
* web-platform-tests/WebCryptoAPI/import_export/test_ec_importKey-expected.txt:

Source/WebCore:

This patch adds SPKI/PKCS8 support for Elliptic Curve cryptos. We can now import/export
SPKI/PKCS8 Elliptic Curve keys after this change. Few things to note: 1) This patch
implements a loose DER encoder/decoder for hacking the underlying CommonCrypto library.
2) It only permits id-ecPublicKey as the AlgorithmIdentifier following OpenSSL/Chrome(BoringSSL).
3) It follows OpenSSL/Chrome(BoringSSL) to replace ECParameters in ECPrivateKey with custom
tags. Hence, we should fully comply with OpenSSL/Chrome(BoringSSL).

Tests: crypto/subtle/ec-import-jwk-key-export-pkcs8-key.html
       crypto/subtle/ec-import-jwk-key-export-spki-key.html
       crypto/subtle/ec-import-pkcs8-key-export-jwk-key.html
       crypto/subtle/ec-import-pkcs8-key-export-pkcs8-key-p256.html
       crypto/subtle/ec-import-pkcs8-key-export-pkcs8-key-p384.html
       crypto/subtle/ec-import-raw-key-export-spki-key.html
       crypto/subtle/ec-import-spki-key-export-jwk-key.html
       crypto/subtle/ec-import-spki-key-export-raw-key.html
       crypto/subtle/ec-import-spki-key-export-spki-key-p256.html
       crypto/subtle/ec-import-spki-key-export-spki-key-p384.html
       crypto/subtle/ecdh-generate-export-key-spki-p256.html
       crypto/subtle/ecdh-generate-export-key-spki-p384.html
       crypto/subtle/ecdh-generate-export-pkcs8-p256.html
       crypto/subtle/ecdh-generate-export-pkcs8-p384.html
       crypto/subtle/ecdh-import-pkcs8-key-p256.html
       crypto/subtle/ecdh-import-pkcs8-key-p384.html
       crypto/subtle/ecdh-import-spki-key-p256.html
       crypto/subtle/ecdh-import-spki-key-p384.html
       crypto/workers/subtle/ec-generate-export-pkcs8-key.html
       crypto/workers/subtle/ec-generate-export-spki-key.html
       crypto/workers/subtle/ec-import-pkcs8-key.html
       crypto/workers/subtle/ec-import-spki-key.html

* WebCore.xcodeproj/project.pbxproj:
* crypto/algorithms/CryptoAlgorithmECDH.cpp:
(WebCore::CryptoAlgorithmECDH::importKey):
(WebCore::CryptoAlgorithmECDH::exportKey):
* crypto/gnutls/CryptoKeyECGnuTLS.cpp:
(WebCore::CryptoKeyEC::platformExportRaw):
(WebCore::CryptoKeyEC::platformImportSpki):
(WebCore::CryptoKeyEC::platformExportSpki):
(WebCore::CryptoKeyEC::platformImportPkcs8):
(WebCore::CryptoKeyEC::platformExportPkcs8):
(WebCore::CryptoKeyEC::exportRaw): Deleted.
* crypto/keys/CryptoKeyEC.cpp:
(WebCore::CryptoKeyEC::importSpki):
(WebCore::CryptoKeyEC::importPkcs8):
(WebCore::CryptoKeyEC::exportRaw):
(WebCore::CryptoKeyEC::exportSpki):
(WebCore::CryptoKeyEC::exportPkcs8):
* crypto/keys/CryptoKeyEC.h:
* crypto/mac/CommonCryptoDERUtilities.h: Added.
(WebCore::bytesUsedToEncodedLength):
(WebCore::extraBytesNeededForEncodedLength):
(WebCore::addEncodedASN1Length):
(WebCore::bytesNeededForEncodedLength):
* crypto/mac/CryptoKeyECMac.cpp:
(WebCore::compareBytes):
(WebCore::CryptoKeyEC::platformExportRaw):
(WebCore::CryptoKeyEC::platformImportJWKPrivate):
(WebCore::getOID):
(WebCore::CryptoKeyEC::platformImportSpki):
(WebCore::CryptoKeyEC::platformExportSpki):
(WebCore::CryptoKeyEC::platformImportPkcs8):
(WebCore::CryptoKeyEC::platformExportPkcs8):
(WebCore::CryptoKeyEC::exportRaw): Deleted.
Enlarge the robust of exportRaw.
* crypto/mac/CryptoKeyRSAMac.cpp:
(WebCore::CryptoKeyRSA::exportSpki):
(WebCore::CryptoKeyRSA::exportPkcs8):
Enhance the implementation.
(WebCore::bytesUsedToEncodedLength): Deleted.
(WebCore::bytesNeededForEncodedLength): Deleted.
(WebCore::addEncodedASN1Length): Deleted.
Moved to CommonCryptoDERUtilities.h.

LayoutTests:

* crypto/subtle/ec-export-key-malformed-parameters-expected.txt:
* crypto/subtle/ec-export-key-malformed-parameters.html:
* crypto/subtle/ec-import-jwk-key-export-jwk-key-private-expected.txt:
* crypto/subtle/ec-import-jwk-key-export-jwk-key-private.html:
* crypto/subtle/ec-import-jwk-key-export-pkcs8-key-expected.txt: Added.
* crypto/subtle/ec-import-jwk-key-export-pkcs8-key.html: Added.
* crypto/subtle/ec-import-jwk-key-export-spki-key-expected.txt: Added.
* crypto/subtle/ec-import-jwk-key-export-spki-key.html: Added.
* crypto/subtle/ec-import-key-malformed-parameters-expected.txt:
* crypto/subtle/ec-import-key-malformed-parameters.html:
* crypto/subtle/ec-import-pkcs8-key-export-jwk-key-expected.txt: Added.
* crypto/subtle/ec-import-pkcs8-key-export-jwk-key.html: Added.
* crypto/subtle/ec-import-pkcs8-key-export-pkcs8-key-p256-expected.txt: Added.
* crypto/subtle/ec-import-pkcs8-key-export-pkcs8-key-p256.html: Added.
* crypto/subtle/ec-import-pkcs8-key-export-pkcs8-key-p384-expected.txt: Added.
* crypto/subtle/ec-import-pkcs8-key-export-pkcs8-key-p384.html: Added.
* crypto/subtle/ec-import-raw-key-export-spki-key-expected.txt: Added.
* crypto/subtle/ec-import-raw-key-export-spki-key.html: Added.
* crypto/subtle/ec-import-spki-key-export-jwk-key-expected.txt: Added.
* crypto/subtle/ec-import-spki-key-export-jwk-key.html: Added.
* crypto/subtle/ec-import-spki-key-export-raw-key-expected.txt: Added.
* crypto/subtle/ec-import-spki-key-export-raw-key.html: Added.
* crypto/subtle/ec-import-spki-key-export-spki-key-p256-expected.txt: Added.
* crypto/subtle/ec-import-spki-key-export-spki-key-p256.html: Added.
* crypto/subtle/ec-import-spki-key-export-spki-key-p384-expected.txt: Added.
* crypto/subtle/ec-import-spki-key-export-spki-key-p384.html: Added.
* crypto/subtle/ecdh-generate-export-key-spki-p256-expected.txt: Added.
* crypto/subtle/ecdh-generate-export-key-spki-p256.html: Added.
* crypto/subtle/ecdh-generate-export-key-spki-p384-expected.txt: Added.
* crypto/subtle/ecdh-generate-export-key-spki-p384.html: Added.
* crypto/subtle/ecdh-generate-export-pkcs8-p256-expected.txt: Added.
* crypto/subtle/ecdh-generate-export-pkcs8-p256.html: Added.
* crypto/subtle/ecdh-generate-export-pkcs8-p384-expected.txt: Added.
* crypto/subtle/ecdh-generate-export-pkcs8-p384.html: Added.
* crypto/subtle/ecdh-import-pkcs8-key-p256-expected.txt: Added.
* crypto/subtle/ecdh-import-pkcs8-key-p256.html: Added.
* crypto/subtle/ecdh-import-pkcs8-key-p384-expected.txt: Added.
* crypto/subtle/ecdh-import-pkcs8-key-p384.html: Added.
* crypto/subtle/ecdh-import-spki-key-p256-expected.txt: Added.
* crypto/subtle/ecdh-import-spki-key-p256.html: Added.
* crypto/subtle/ecdh-import-spki-key-p384-expected.txt: Added.
* crypto/subtle/ecdh-import-spki-key-p384.html: Added.
* crypto/workers/subtle/ec-generate-export-pkcs8-key-expected.txt: Added.
* crypto/workers/subtle/ec-generate-export-pkcs8-key.html: Added.
* crypto/workers/subtle/ec-generate-export-spki-key-expected.txt: Added.
* crypto/workers/subtle/ec-generate-export-spki-key.html: Added.
* crypto/workers/subtle/ec-import-pkcs8-key-expected.txt: Added.
* crypto/workers/subtle/ec-import-pkcs8-key.html: Added.
* crypto/workers/subtle/ec-import-spki-key-expected.txt: Added.
* crypto/workers/subtle/ec-import-spki-key.html: Added.
* crypto/workers/subtle/resources/ec-generate-export-pkcs8-key.js: Added.
* crypto/workers/subtle/resources/ec-generate-export-spki-key.js: Added.
* crypto/workers/subtle/resources/ec-import-pkcs8-key.js: Added.
* crypto/workers/subtle/resources/ec-import-spki-key.js: Added.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@214074 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 0b6dffe..afccaa8 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,66 @@
+2017-03-16  Jiewen Tan  <jiewen_tan@apple.com>
+
+        [WebCrypto] Support SPKI/PKCS8 for Elliptic Curve
+        https://bugs.webkit.org/show_bug.cgi?id=169318
+        <rdar://problem/31081956>
+
+        Reviewed by Brent Fulgham.
+
+        * crypto/subtle/ec-export-key-malformed-parameters-expected.txt:
+        * crypto/subtle/ec-export-key-malformed-parameters.html:
+        * crypto/subtle/ec-import-jwk-key-export-jwk-key-private-expected.txt:
+        * crypto/subtle/ec-import-jwk-key-export-jwk-key-private.html:
+        * crypto/subtle/ec-import-jwk-key-export-pkcs8-key-expected.txt: Added.
+        * crypto/subtle/ec-import-jwk-key-export-pkcs8-key.html: Added.
+        * crypto/subtle/ec-import-jwk-key-export-spki-key-expected.txt: Added.
+        * crypto/subtle/ec-import-jwk-key-export-spki-key.html: Added.
+        * crypto/subtle/ec-import-key-malformed-parameters-expected.txt:
+        * crypto/subtle/ec-import-key-malformed-parameters.html:
+        * crypto/subtle/ec-import-pkcs8-key-export-jwk-key-expected.txt: Added.
+        * crypto/subtle/ec-import-pkcs8-key-export-jwk-key.html: Added.
+        * crypto/subtle/ec-import-pkcs8-key-export-pkcs8-key-p256-expected.txt: Added.
+        * crypto/subtle/ec-import-pkcs8-key-export-pkcs8-key-p256.html: Added.
+        * crypto/subtle/ec-import-pkcs8-key-export-pkcs8-key-p384-expected.txt: Added.
+        * crypto/subtle/ec-import-pkcs8-key-export-pkcs8-key-p384.html: Added.
+        * crypto/subtle/ec-import-raw-key-export-spki-key-expected.txt: Added.
+        * crypto/subtle/ec-import-raw-key-export-spki-key.html: Added.
+        * crypto/subtle/ec-import-spki-key-export-jwk-key-expected.txt: Added.
+        * crypto/subtle/ec-import-spki-key-export-jwk-key.html: Added.
+        * crypto/subtle/ec-import-spki-key-export-raw-key-expected.txt: Added.
+        * crypto/subtle/ec-import-spki-key-export-raw-key.html: Added.
+        * crypto/subtle/ec-import-spki-key-export-spki-key-p256-expected.txt: Added.
+        * crypto/subtle/ec-import-spki-key-export-spki-key-p256.html: Added.
+        * crypto/subtle/ec-import-spki-key-export-spki-key-p384-expected.txt: Added.
+        * crypto/subtle/ec-import-spki-key-export-spki-key-p384.html: Added.
+        * crypto/subtle/ecdh-generate-export-key-spki-p256-expected.txt: Added.
+        * crypto/subtle/ecdh-generate-export-key-spki-p256.html: Added.
+        * crypto/subtle/ecdh-generate-export-key-spki-p384-expected.txt: Added.
+        * crypto/subtle/ecdh-generate-export-key-spki-p384.html: Added.
+        * crypto/subtle/ecdh-generate-export-pkcs8-p256-expected.txt: Added.
+        * crypto/subtle/ecdh-generate-export-pkcs8-p256.html: Added.
+        * crypto/subtle/ecdh-generate-export-pkcs8-p384-expected.txt: Added.
+        * crypto/subtle/ecdh-generate-export-pkcs8-p384.html: Added.
+        * crypto/subtle/ecdh-import-pkcs8-key-p256-expected.txt: Added.
+        * crypto/subtle/ecdh-import-pkcs8-key-p256.html: Added.
+        * crypto/subtle/ecdh-import-pkcs8-key-p384-expected.txt: Added.
+        * crypto/subtle/ecdh-import-pkcs8-key-p384.html: Added.
+        * crypto/subtle/ecdh-import-spki-key-p256-expected.txt: Added.
+        * crypto/subtle/ecdh-import-spki-key-p256.html: Added.
+        * crypto/subtle/ecdh-import-spki-key-p384-expected.txt: Added.
+        * crypto/subtle/ecdh-import-spki-key-p384.html: Added.
+        * crypto/workers/subtle/ec-generate-export-pkcs8-key-expected.txt: Added.
+        * crypto/workers/subtle/ec-generate-export-pkcs8-key.html: Added.
+        * crypto/workers/subtle/ec-generate-export-spki-key-expected.txt: Added.
+        * crypto/workers/subtle/ec-generate-export-spki-key.html: Added.
+        * crypto/workers/subtle/ec-import-pkcs8-key-expected.txt: Added.
+        * crypto/workers/subtle/ec-import-pkcs8-key.html: Added.
+        * crypto/workers/subtle/ec-import-spki-key-expected.txt: Added.
+        * crypto/workers/subtle/ec-import-spki-key.html: Added.
+        * crypto/workers/subtle/resources/ec-generate-export-pkcs8-key.js: Added.
+        * crypto/workers/subtle/resources/ec-generate-export-spki-key.js: Added.
+        * crypto/workers/subtle/resources/ec-import-pkcs8-key.js: Added.
+        * crypto/workers/subtle/resources/ec-import-spki-key.js: Added.
+
 2017-03-16  Zalan Bujtas  <zalan@apple.com>
 
         Simple line layout: Extend webkit-hyphenate-limit-lines to cover subsequent words.
diff --git a/LayoutTests/crypto/subtle/ec-export-key-malformed-parameters-expected.txt b/LayoutTests/crypto/subtle/ec-export-key-malformed-parameters-expected.txt
index ec743c5..bf2fb04 100644
--- a/LayoutTests/crypto/subtle/ec-export-key-malformed-parameters-expected.txt
+++ b/LayoutTests/crypto/subtle/ec-export-key-malformed-parameters-expected.txt
@@ -4,6 +4,8 @@
 
 
 PASS crypto.subtle.exportKey("raw", privateKey) rejected promise  with InvalidAccessError (DOM Exception 15): The requested operation is not valid for the provided key.
+PASS crypto.subtle.exportKey("spki", privateKey) rejected promise  with InvalidAccessError (DOM Exception 15): The requested operation is not valid for the provided key.
+PASS crypto.subtle.exportKey("pkcs8", publicKey) rejected promise  with InvalidAccessError (DOM Exception 15): The requested operation is not valid for the provided key.
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/LayoutTests/crypto/subtle/ec-export-key-malformed-parameters.html b/LayoutTests/crypto/subtle/ec-export-key-malformed-parameters.html
index ee9a2a7..8fecf52 100644
--- a/LayoutTests/crypto/subtle/ec-export-key-malformed-parameters.html
+++ b/LayoutTests/crypto/subtle/ec-export-key-malformed-parameters.html
@@ -21,9 +21,16 @@
 
 crypto.subtle.generateKey(algorithmKeyGen, extractable, ["deriveKey", "deriveBits"]).then(function(result) {
     privateKey = result.privateKey;
+    publicKey = result.publicKey;
 
     // Wrong key and format.
     return shouldReject('crypto.subtle.exportKey("raw", privateKey)');
+}).then(function() {
+    // Wrong key and format.
+    return shouldReject('crypto.subtle.exportKey("spki", privateKey)');
+}).then(function() {
+    // Wrong key and format.
+    return shouldReject('crypto.subtle.exportKey("pkcs8", publicKey)');
 }).then(finishJSTest, finishJSTest);
 
 </script>
diff --git a/LayoutTests/crypto/subtle/ec-import-jwk-key-export-jwk-key-private-expected.txt b/LayoutTests/crypto/subtle/ec-import-jwk-key-export-jwk-key-private-expected.txt
index c5a821f..cab8048 100644
--- a/LayoutTests/crypto/subtle/ec-import-jwk-key-export-jwk-key-private-expected.txt
+++ b/LayoutTests/crypto/subtle/ec-import-jwk-key-export-jwk-key-private-expected.txt
@@ -4,13 +4,13 @@
 
 
 Importing a key...
-PASS publicKey.kty is jwkKey.kty
-PASS publicKey.crv is jwkKey.crv
-PASS publicKey.x is jwkKey.x
-PASS publicKey.y is jwkKey.y
-PASS publicKey.d is jwkKey.d
-PASS publicKey.key_ops is jwkKey.key_ops
-PASS publicKey.ext is jwkKey.ext
+PASS privateKey.kty is jwkKey.kty
+PASS privateKey.crv is jwkKey.crv
+PASS privateKey.x is jwkKey.x
+PASS privateKey.y is jwkKey.y
+PASS privateKey.d is jwkKey.d
+PASS privateKey.key_ops is jwkKey.key_ops
+PASS privateKey.ext is jwkKey.ext
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/LayoutTests/crypto/subtle/ec-import-jwk-key-export-jwk-key-private.html b/LayoutTests/crypto/subtle/ec-import-jwk-key-export-jwk-key-private.html
index a9ae997..602033f 100644
--- a/LayoutTests/crypto/subtle/ec-import-jwk-key-export-jwk-key-private.html
+++ b/LayoutTests/crypto/subtle/ec-import-jwk-key-export-jwk-key-private.html
@@ -28,15 +28,15 @@
 crypto.subtle.importKey("jwk", jwkKey, { name: "ECDH", namedCurve: "P-256" }, extractable, ["deriveKey", "deriveBits"]).then(function(result) {
     return crypto.subtle.exportKey("jwk", result);
 }).then(function(result) {
-    publicKey = result;
+    privateKey = result;
 
-    shouldBe("publicKey.kty", "jwkKey.kty");
-    shouldBe("publicKey.crv", "jwkKey.crv");
-    shouldBe("publicKey.x", "jwkKey.x");
-    shouldBe("publicKey.y", "jwkKey.y");
-    shouldBe("publicKey.d", "jwkKey.d");
-    shouldBe("publicKey.key_ops", "jwkKey.key_ops");
-    shouldBe("publicKey.ext", "jwkKey.ext");
+    shouldBe("privateKey.kty", "jwkKey.kty");
+    shouldBe("privateKey.crv", "jwkKey.crv");
+    shouldBe("privateKey.x", "jwkKey.x");
+    shouldBe("privateKey.y", "jwkKey.y");
+    shouldBe("privateKey.d", "jwkKey.d");
+    shouldBe("privateKey.key_ops", "jwkKey.key_ops");
+    shouldBe("privateKey.ext", "jwkKey.ext");
 
     finishJSTest();
 });
diff --git a/LayoutTests/crypto/subtle/ec-import-jwk-key-export-pkcs8-key-expected.txt b/LayoutTests/crypto/subtle/ec-import-jwk-key-export-pkcs8-key-expected.txt
new file mode 100644
index 0000000..e554e79
--- /dev/null
+++ b/LayoutTests/crypto/subtle/ec-import-jwk-key-export-pkcs8-key-expected.txt
@@ -0,0 +1,11 @@
+Test importing a jwk private ECDH key and then export it in PKCS8 format
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Importing a key...
+PASS bytesToHexString(privateKey) is expectedPkcs8KeyHex
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/crypto/subtle/ec-import-jwk-key-export-pkcs8-key.html b/LayoutTests/crypto/subtle/ec-import-jwk-key-export-pkcs8-key.html
new file mode 100644
index 0000000..9ffdd39
--- /dev/null
+++ b/LayoutTests/crypto/subtle/ec-import-jwk-key-export-pkcs8-key.html
@@ -0,0 +1,43 @@
+<!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 importing a jwk private ECDH key and then export it in PKCS8 format");
+
+jsTestIsAsync = true;
+
+var jwkKey = {
+    kty: "EC",
+    ext: true,
+    key_ops: ["deriveBits", "deriveKey"],
+    crv: "P-256",
+    x: "1FSVWieTvikFkG1NOyhkUCaMbdQhxwH6aCu4Ez-sRtA",
+    y: "9jmNTLqM4cjBhdAnHcNI9YQV3O8LFmo-EdZWk8ntAaI",
+    d: "ppxBSov3N8_AUcisAuvmLV4yE8e_L_BLE8bZb9Z1Xjg",
+};
+var expectedPkcs8KeyHex = "308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b0201010420a69c414a8bf737cfc051c8ac02ebe62d5e3213c7bf2ff04b13c6d96fd6755e38a14403420004d454955a2793be2905906d4d3b286450268c6dd421c701fa682bb8133fac46d0f6398d4cba8ce1c8c185d0271dc348f58415dcef0b166a3e11d65693c9ed01a2";
+var extractable = true;
+
+debug("Importing a key...");
+crypto.subtle.importKey("jwk", jwkKey, { name: "ECDH", namedCurve: "P-256" }, extractable, ["deriveKey", "deriveBits"]).then(function(result) {
+    return crypto.subtle.exportKey("pkcs8", result);
+}).then(function(result) {
+    privateKey = result;
+
+    shouldBe("bytesToHexString(privateKey)", "expectedPkcs8KeyHex");
+
+    finishJSTest();
+});
+
+</script>
+
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/crypto/subtle/ec-import-jwk-key-export-spki-key-expected.txt b/LayoutTests/crypto/subtle/ec-import-jwk-key-export-spki-key-expected.txt
new file mode 100644
index 0000000..cc84218
--- /dev/null
+++ b/LayoutTests/crypto/subtle/ec-import-jwk-key-export-spki-key-expected.txt
@@ -0,0 +1,11 @@
+Test importing a JWK ECDH public key and export it in SPKI format
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Importing a key...
+PASS bytesToHexString(publicKey) is expectedSpkiKey
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/crypto/subtle/ec-import-jwk-key-export-spki-key.html b/LayoutTests/crypto/subtle/ec-import-jwk-key-export-spki-key.html
new file mode 100644
index 0000000..c35ca2e
--- /dev/null
+++ b/LayoutTests/crypto/subtle/ec-import-jwk-key-export-spki-key.html
@@ -0,0 +1,40 @@
+<!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 importing a JWK ECDH public key and export it in SPKI format");
+
+jsTestIsAsync = true;
+
+var jwkKey = {
+    kty: "EC",
+    crv: "P-256",
+    x: "1FSVWieTvikFkG1NOyhkUCaMbdQhxwH6aCu4Ez-sRtA",
+    y: "9jmNTLqM4cjBhdAnHcNI9YQV3O8LFmo-EdZWk8ntAaI",
+};
+var expectedSpkiKey = "3059301306072a8648ce3d020106082a8648ce3d03010703420004d454955a2793be2905906d4d3b286450268c6dd421c701fa682bb8133fac46d0f6398d4cba8ce1c8c185d0271dc348f58415dcef0b166a3e11d65693c9ed01a2";
+var extractable = true;
+
+debug("Importing a key...");
+crypto.subtle.importKey("jwk", jwkKey, { name: "ECDH", namedCurve: "P-256" }, extractable, [ ]).then(function(key) {
+    return crypto.subtle.exportKey("spki", key);
+}).then(function(result) {
+    publicKey = result;
+
+    shouldBe("bytesToHexString(publicKey)", "expectedSpkiKey");
+
+    finishJSTest();
+});
+
+</script>
+
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/crypto/subtle/ec-import-key-malformed-parameters-expected.txt b/LayoutTests/crypto/subtle/ec-import-key-malformed-parameters-expected.txt
index 23bffa4..c74c929 100644
--- a/LayoutTests/crypto/subtle/ec-import-key-malformed-parameters-expected.txt
+++ b/LayoutTests/crypto/subtle/ec-import-key-malformed-parameters-expected.txt
@@ -27,6 +27,42 @@
 PASS crypto.subtle.importKey("jwk", {kty: "EC", crv: "P-384", x:x384, y:y}, { name: "ECDH", namedCurve: "P-384" }, extractable, [ ]) rejected promise  with DataError (DOM Exception 30): Data provided to an operation does not meet requirements.
 PASS crypto.subtle.importKey("jwk", {kty: "EC", crv: "P-384", x:x, y:y384}, { name: "ECDH", namedCurve: "P-384" }, extractable, [ ]) rejected promise  with DataError (DOM Exception 30): Data provided to an operation does not meet requirements.
 PASS crypto.subtle.importKey("jwk", {kty: "EC", crv: "P-384", x:x384, y:y384, d:d}, { name: "ECDH", namedCurve: "P-384" }, extractable, [ ]) rejected promise  with DataError (DOM Exception 30): Data provided to an operation does not meet requirements.
+PASS crypto.subtle.importKey("spki", spkiP256Key, { name: "ECDH", namedCurve: "P-256" }, extractable, ["deriveBits"]) rejected promise  with SyntaxError (DOM Exception 12): A required parameter was missing or out-of-range.
+PASS crypto.subtle.importKey("spki", truncatedSpkiP256Key1, { name: "ECDH", namedCurve: "P-256" }, extractable, [ ]) rejected promise  with DataError (DOM Exception 30): Data provided to an operation does not meet requirements.
+PASS crypto.subtle.importKey("spki", truncatedSpkiP256Key2, { name: "ECDH", namedCurve: "P-256" }, extractable, [ ]) rejected promise  with DataError (DOM Exception 30): Data provided to an operation does not meet requirements.
+PASS crypto.subtle.importKey("spki", truncatedSpkiP256Key3, { name: "ECDH", namedCurve: "P-256" }, extractable, [ ]) rejected promise  with DataError (DOM Exception 30): Data provided to an operation does not meet requirements.
+PASS crypto.subtle.importKey("spki", truncatedSpkiP256Key4, { name: "ECDH", namedCurve: "P-256" }, extractable, [ ]) rejected promise  with DataError (DOM Exception 30): Data provided to an operation does not meet requirements.
+PASS crypto.subtle.importKey("spki", truncatedSpkiP256Key5, { name: "ECDH", namedCurve: "P-256" }, extractable, [ ]) rejected promise  with DataError (DOM Exception 30): Data provided to an operation does not meet requirements.
+PASS crypto.subtle.importKey("spki", truncatedSpkiP256Key6, { name: "ECDH", namedCurve: "P-256" }, extractable, [ ]) rejected promise  with DataError (DOM Exception 30): Data provided to an operation does not meet requirements.
+PASS crypto.subtle.importKey("spki", truncatedSpkiP256Key7, { name: "ECDH", namedCurve: "P-256" }, extractable, [ ]) rejected promise  with DataError (DOM Exception 30): Data provided to an operation does not meet requirements.
+PASS crypto.subtle.importKey("spki", truncatedSpkiP256Key8, { name: "ECDH", namedCurve: "P-256" }, extractable, [ ]) rejected promise  with DataError (DOM Exception 30): Data provided to an operation does not meet requirements.
+PASS crypto.subtle.importKey("spki", truncatedSpkiP384Key1, { name: "ECDH", namedCurve: "P-384" }, extractable, [ ]) rejected promise  with DataError (DOM Exception 30): Data provided to an operation does not meet requirements.
+PASS crypto.subtle.importKey("spki", truncatedSpkiP384Key2, { name: "ECDH", namedCurve: "P-384" }, extractable, [ ]) rejected promise  with DataError (DOM Exception 30): Data provided to an operation does not meet requirements.
+PASS crypto.subtle.importKey("spki", truncatedSpkiP384Key3, { name: "ECDH", namedCurve: "P-384" }, extractable, [ ]) rejected promise  with DataError (DOM Exception 30): Data provided to an operation does not meet requirements.
+PASS crypto.subtle.importKey("spki", spkiP256Key, { name: "ECDH", namedCurve: "P-384" }, extractable, [ ]) rejected promise  with DataError (DOM Exception 30): Data provided to an operation does not meet requirements.
+PASS crypto.subtle.importKey("spki", spkiP384Key, { name: "ECDH", namedCurve: "P-256" }, extractable, [ ]) rejected promise  with DataError (DOM Exception 30): Data provided to an operation does not meet requirements.
+PASS crypto.subtle.importKey("spki", corruptedSpkiP256Key, { name: "ECDH", namedCurve: "P-256" }, extractable, [ ]) rejected promise  with DataError (DOM Exception 30): Data provided to an operation does not meet requirements.
+PASS crypto.subtle.importKey("pkcs8", pkcs8P256Key, { name: "ECDH", namedCurve: "P-256" }, extractable, ["encrypt"]) rejected promise  with SyntaxError (DOM Exception 12): A required parameter was missing or out-of-range.
+PASS crypto.subtle.importKey("pkcs8", pkcs8P256Key, { name: "ECDH", namedCurve: "P-256" }, extractable, ["decrypt"]) rejected promise  with SyntaxError (DOM Exception 12): A required parameter was missing or out-of-range.
+PASS crypto.subtle.importKey("pkcs8", pkcs8P256Key, { name: "ECDH", namedCurve: "P-256" }, extractable, ["sign"]) rejected promise  with SyntaxError (DOM Exception 12): A required parameter was missing or out-of-range.
+PASS crypto.subtle.importKey("pkcs8", pkcs8P256Key, { name: "ECDH", namedCurve: "P-256" }, extractable, ["verify"]) rejected promise  with SyntaxError (DOM Exception 12): A required parameter was missing or out-of-range.
+PASS crypto.subtle.importKey("pkcs8", pkcs8P256Key, { name: "ECDH", namedCurve: "P-256" }, extractable, ["wrapKey"]) rejected promise  with SyntaxError (DOM Exception 12): A required parameter was missing or out-of-range.
+PASS crypto.subtle.importKey("pkcs8", pkcs8P256Key, { name: "ECDH", namedCurve: "P-256" }, extractable, ["unwrapKey"]) rejected promise  with SyntaxError (DOM Exception 12): A required parameter was missing or out-of-range.
+PASS crypto.subtle.importKey("pkcs8", truncatedPkcs8P256Key1, { name: "ECDH", namedCurve: "P-256" }, extractable, ["deriveKey"]) rejected promise  with DataError (DOM Exception 30): Data provided to an operation does not meet requirements.
+PASS crypto.subtle.importKey("pkcs8", truncatedPkcs8P256Key2, { name: "ECDH", namedCurve: "P-256" }, extractable, ["deriveKey"]) rejected promise  with DataError (DOM Exception 30): Data provided to an operation does not meet requirements.
+PASS crypto.subtle.importKey("pkcs8", truncatedPkcs8P256Key3, { name: "ECDH", namedCurve: "P-256" }, extractable, ["deriveKey"]) rejected promise  with DataError (DOM Exception 30): Data provided to an operation does not meet requirements.
+PASS crypto.subtle.importKey("pkcs8", truncatedPkcs8P256Key4, { name: "ECDH", namedCurve: "P-256" }, extractable, ["deriveKey"]) rejected promise  with DataError (DOM Exception 30): Data provided to an operation does not meet requirements.
+PASS crypto.subtle.importKey("pkcs8", truncatedPkcs8P256Key5, { name: "ECDH", namedCurve: "P-256" }, extractable, ["deriveKey"]) rejected promise  with DataError (DOM Exception 30): Data provided to an operation does not meet requirements.
+PASS crypto.subtle.importKey("pkcs8", truncatedPkcs8P256Key6, { name: "ECDH", namedCurve: "P-256" }, extractable, ["deriveKey"]) rejected promise  with DataError (DOM Exception 30): Data provided to an operation does not meet requirements.
+PASS crypto.subtle.importKey("pkcs8", truncatedPkcs8P256Key7, { name: "ECDH", namedCurve: "P-256" }, extractable, ["deriveKey"]) rejected promise  with DataError (DOM Exception 30): Data provided to an operation does not meet requirements.
+PASS crypto.subtle.importKey("pkcs8", truncatedPkcs8P256Key8, { name: "ECDH", namedCurve: "P-256" }, extractable, ["deriveKey"]) rejected promise  with DataError (DOM Exception 30): Data provided to an operation does not meet requirements.
+PASS crypto.subtle.importKey("pkcs8", truncatedPkcs8P256Key9, { name: "ECDH", namedCurve: "P-256" }, extractable, ["deriveKey"]) rejected promise  with DataError (DOM Exception 30): Data provided to an operation does not meet requirements.
+PASS crypto.subtle.importKey("pkcs8", truncatedPkcs8P256Key10, { name: "ECDH", namedCurve: "P-256" }, extractable, ["deriveKey"]) rejected promise  with DataError (DOM Exception 30): Data provided to an operation does not meet requirements.
+PASS crypto.subtle.importKey("pkcs8", truncatedPkcs8P256Key11, { name: "ECDH", namedCurve: "P-256" }, extractable, ["deriveKey"]) rejected promise  with DataError (DOM Exception 30): Data provided to an operation does not meet requirements.
+PASS crypto.subtle.importKey("pkcs8", truncatedPkcs8P384Key1, { name: "ECDH", namedCurve: "P-384" }, extractable, ["deriveKey"]) rejected promise  with DataError (DOM Exception 30): Data provided to an operation does not meet requirements.
+PASS crypto.subtle.importKey("pkcs8", truncatedPkcs8P384Key2, { name: "ECDH", namedCurve: "P-384" }, extractable, ["deriveKey"]) rejected promise  with DataError (DOM Exception 30): Data provided to an operation does not meet requirements.
+PASS crypto.subtle.importKey("pkcs8", longPkcs8P256Key, { name: "ECDH", namedCurve: "P-256" }, extractable, ["deriveKey"]) rejected promise  with DataError (DOM Exception 30): Data provided to an operation does not meet requirements.
+PASS crypto.subtle.importKey("pkcs8", corruptedPkcs8P256Key, { name: "ECDH", namedCurve: "P-256" }, extractable, ["deriveKey"]) rejected promise  with DataError (DOM Exception 30): Data provided to an operation does not meet requirements.
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/LayoutTests/crypto/subtle/ec-import-key-malformed-parameters.html b/LayoutTests/crypto/subtle/ec-import-key-malformed-parameters.html
index 87dedbc..11dc96f 100644
--- a/LayoutTests/crypto/subtle/ec-import-key-malformed-parameters.html
+++ b/LayoutTests/crypto/subtle/ec-import-key-malformed-parameters.html
@@ -19,6 +19,37 @@
 var d = "ppxBSov3N8_AUcisAuvmLV4yE8e_L_BLE8bZb9Z1Xjg"; // P-256
 var x384 = "1bHwFrsaPRjYq-zFOyLXK8Ugv3EqbVF075ct7ouTl_pwyhjeBu03JHjKTsyVbNWK";
 var y384 = "1bHwFrsaPRjYq-zFOyLXK8Ugv3EqbVF075ct7ouTl_pwyhjeBu03JHjKTsyVbNWK";
+var spkiP256Key = hexStringToUint8Array("3059301306072a8648ce3d020106082a8648ce3d03010703420004c3ee3a2c3380072b9b2a59fed2cada65121806e22c4f4f8a25e740fc3e54d75d86c200298e6dfc1611d185eedbdb3c2661b0eb0441f7fd57c90d08112e9ae71c");
+var spkiP384Key = hexStringToUint8Array("3076301006072a8648ce3d020106052b8104002203620004478f6119747475f94b742654be32ab6ebbdc371afa34fbee6d12c32fe2d586231262b17d13a1f271f19c8008c034d8716b7df0ce1d987990c5b175ecae1aa40f2fb89e4778528e1234e56d69638db135d103fa68448fee2b4f58ecc86d7f4b7a");
+var truncatedSpkiP256Key1 = hexStringToUint8Array("30");
+var truncatedSpkiP256Key2 = hexStringToUint8Array("305930");
+var truncatedSpkiP256Key3 = hexStringToUint8Array("305930130607");
+var truncatedSpkiP256Key4 = hexStringToUint8Array("3059301306072b8648ce3d0201");
+var truncatedSpkiP256Key5 = hexStringToUint8Array("3059301306072a8648ce3d02010608");
+var truncatedSpkiP256Key6 = hexStringToUint8Array("3059301306072a8648ce3d020106082a8648ce3d030108");
+var truncatedSpkiP256Key7 = hexStringToUint8Array("3059301306072a8648ce3d020106082a8648ce3d030107034200");
+var truncatedSpkiP256Key8 = hexStringToUint8Array("3059301306072a8648ce3d020106082a8648ce3d03010703420004c3ee3a2c3380072b9b2a59fed2cada65121806e22c4f4f8a25e740fc3e54d75d86c200298e6dfc1611d185eedbdb3c2661b0eb0441f7fd57c90d08112e9ae7");
+var truncatedSpkiP384Key1 = hexStringToUint8Array("3076301006072a8648ce3d02010605");
+var truncatedSpkiP384Key2 = hexStringToUint8Array("3076301006072a8648ce3d020106052b81040022");
+var truncatedSpkiP384Key3 = hexStringToUint8Array("3076301006072a8648ce3d020106052b8104002203620004478f6119747475f94b742654be32ab6ebbdc371afa34fbee6d12c32fe2d586231262b17d13a1f271f19c8008c034d8716b7df0ce1d987990c5b175ecae1aa40f2fb89e4778528e1234e56d69638db135d103fa68448fee2b4f58ecc86d7f4b");
+var corruptedSpkiP256Key = hexStringToUint8Array("3059301306072a8648ce3d020106082a8648ce3d03010703420000c3ee3a2c3380072b9b2a59fed2cada65121806e22c4f4f8a25e740fc3e54d75d86c200298e6dfc1611d185eedbdb3c2661b0eb0441f7fd57c90d08112e9ae71c");
+var pkcs8P256Key = hexStringToUint8Array("308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b02010104200a21f3f048b893b0f2b5a8459bd6d2bc112614aa86437f8fa2496a0e27f5b0a8a14403420004d726bd565878f24ee3616890d3668503334b84da3434b2774a44d6e4b9c536dd60e9181e1d1469ba3e6aba8987225f6e797d01a0dc400a4a298c902bae66abe2");
+var pkcs8P384Key = hexStringToUint8Array("3081b6020100301006072a8648ce3d020106052b8104002204819e30819b0201010430c38e34a7cd58961c8deda9c9118548724945d3f3b3bd71f03c93247304c1f7d86b8507501e4e05a0fbae76e44bbe8cc2a16403620004cb75013d8ba42edd022e9de8dfe856a2ee3f48ec28a666c4a73cf3d16e09c7d5747e6c5b5795a656e175c71feed01ec5e282b19e6650f6ea31970114f3e1e6e2275dd6811f87e7f7128c48806a9763785ac31bd345436e57eae23a1151355ef2");
+var truncatedPkcs8P256Key1 = hexStringToUint8Array("30");
+var truncatedPkcs8P256Key2 = hexStringToUint8Array("30818702010030");
+var truncatedPkcs8P256Key3 = hexStringToUint8Array("3081870201003013");
+var truncatedPkcs8P256Key4 = hexStringToUint8Array("308187020100301306072b8648ce3d0201");
+var truncatedPkcs8P256Key5 = hexStringToUint8Array("308187020100301306072a8648ce3d0201");
+var truncatedPkcs8P256Key6 = hexStringToUint8Array("308187020100301306072a8648ce3d020106082b8648ce3d030107");
+var truncatedPkcs8P256Key7 = hexStringToUint8Array("308187020100301306072a8648ce3d020106082a8648ce3d03010704");
+var truncatedPkcs8P256Key8 = hexStringToUint8Array("308187020100301306072a8648ce3d020106082a8648ce3d030107046d30");
+var truncatedPkcs8P256Key9 = hexStringToUint8Array("308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b02010104");
+var truncatedPkcs8P256Key10 = hexStringToUint8Array("308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b0201010420");
+var truncatedPkcs8P256Key11 = hexStringToUint8Array("308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b02010104200a21f3f048b893b0f2b5a8459bd6d2bc112614aa86437f8fa2496a0e27f5b0a8a14403");
+var longPkcs8P256Key = hexStringToUint8Array("308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b02010104200a21f3f048b893b0f2b5a8459bd6d2bc112614aa86437f8fa2496a0e27f5b0a8a14403420004d726bd565878f24ee3616890d3668503334b84da3434b2774a44d6e4b9c536dd60e9181e1d1469ba3e6aba8987225f6e797d01a0dc400a4a298c902bae66abe2badbad");
+var corruptedPkcs8P256Key = hexStringToUint8Array("308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b02010104200a21f3f048b893b0f2b5a8459bd6d2bc112614aa86437f8fa2496a0e27f5b0a8a14403420005d726bd565878f24ee3616890d3668503334b84da3434b2774a44d6e4b9c536dd60e9181e1d1469ba3e6aba8987225f6e797d01a0dc400a4a298c902bae66abe2");
+var truncatedPkcs8P384Key1 = hexStringToUint8Array("3081b6020100301006072a8648ce3d0201");
+var truncatedPkcs8P384Key2 = hexStringToUint8Array("3081b6020100301006072a8648ce3d020106052b81040023");
 
 // Named curves mismatch raw keys
 shouldReject('crypto.subtle.importKey("raw", rawP256Key, { name: "ECDH", namedCurve: "P-384" }, extractable, [ ])');
@@ -57,6 +88,50 @@
 shouldReject('crypto.subtle.importKey("jwk", {kty: "EC", crv: "P-384", x:x384, y:y}, { name: "ECDH", namedCurve: "P-384" }, extractable, [ ])');
 shouldReject('crypto.subtle.importKey("jwk", {kty: "EC", crv: "P-384", x:x, y:y384}, { name: "ECDH", namedCurve: "P-384" }, extractable, [ ])');
 shouldReject('crypto.subtle.importKey("jwk", {kty: "EC", crv: "P-384", x:x384, y:y384, d:d}, { name: "ECDH", namedCurve: "P-384" }, extractable, [ ])');
+// Spki: Non-empty usages
+shouldReject('crypto.subtle.importKey("spki", spkiP256Key, { name: "ECDH", namedCurve: "P-256" }, extractable, ["deriveBits"])');
+// Spki: Truncated keys
+shouldReject('crypto.subtle.importKey("spki", truncatedSpkiP256Key1, { name: "ECDH", namedCurve: "P-256" }, extractable, [ ])');
+shouldReject('crypto.subtle.importKey("spki", truncatedSpkiP256Key2, { name: "ECDH", namedCurve: "P-256" }, extractable, [ ])');
+shouldReject('crypto.subtle.importKey("spki", truncatedSpkiP256Key3, { name: "ECDH", namedCurve: "P-256" }, extractable, [ ])');
+shouldReject('crypto.subtle.importKey("spki", truncatedSpkiP256Key4, { name: "ECDH", namedCurve: "P-256" }, extractable, [ ])');
+shouldReject('crypto.subtle.importKey("spki", truncatedSpkiP256Key5, { name: "ECDH", namedCurve: "P-256" }, extractable, [ ])');
+shouldReject('crypto.subtle.importKey("spki", truncatedSpkiP256Key6, { name: "ECDH", namedCurve: "P-256" }, extractable, [ ])');
+shouldReject('crypto.subtle.importKey("spki", truncatedSpkiP256Key7, { name: "ECDH", namedCurve: "P-256" }, extractable, [ ])');
+shouldReject('crypto.subtle.importKey("spki", truncatedSpkiP256Key8, { name: "ECDH", namedCurve: "P-256" }, extractable, [ ])');
+shouldReject('crypto.subtle.importKey("spki", truncatedSpkiP384Key1, { name: "ECDH", namedCurve: "P-384" }, extractable, [ ])');
+shouldReject('crypto.subtle.importKey("spki", truncatedSpkiP384Key2, { name: "ECDH", namedCurve: "P-384" }, extractable, [ ])');
+shouldReject('crypto.subtle.importKey("spki", truncatedSpkiP384Key3, { name: "ECDH", namedCurve: "P-384" }, extractable, [ ])');
+// Spki: Missmatched Curves
+shouldReject('crypto.subtle.importKey("spki", spkiP256Key, { name: "ECDH", namedCurve: "P-384" }, extractable, [ ])');
+shouldReject('crypto.subtle.importKey("spki", spkiP384Key, { name: "ECDH", namedCurve: "P-256" }, extractable, [ ])');
+// Spki: Corrupted Key Data
+shouldReject('crypto.subtle.importKey("spki", corruptedSpkiP256Key, { name: "ECDH", namedCurve: "P-256" }, extractable, [ ])');
+// Pkcs8: Wrong usages
+shouldReject('crypto.subtle.importKey("pkcs8", pkcs8P256Key, { name: "ECDH", namedCurve: "P-256" }, extractable, ["encrypt"])');
+shouldReject('crypto.subtle.importKey("pkcs8", pkcs8P256Key, { name: "ECDH", namedCurve: "P-256" }, extractable, ["decrypt"])');
+shouldReject('crypto.subtle.importKey("pkcs8", pkcs8P256Key, { name: "ECDH", namedCurve: "P-256" }, extractable, ["sign"])');
+shouldReject('crypto.subtle.importKey("pkcs8", pkcs8P256Key, { name: "ECDH", namedCurve: "P-256" }, extractable, ["verify"])');
+shouldReject('crypto.subtle.importKey("pkcs8", pkcs8P256Key, { name: "ECDH", namedCurve: "P-256" }, extractable, ["wrapKey"])');
+shouldReject('crypto.subtle.importKey("pkcs8", pkcs8P256Key, { name: "ECDH", namedCurve: "P-256" }, extractable, ["unwrapKey"])');
+// Pkcs8: Truncated keys
+shouldReject('crypto.subtle.importKey("pkcs8", truncatedPkcs8P256Key1, { name: "ECDH", namedCurve: "P-256" }, extractable, ["deriveKey"])');
+shouldReject('crypto.subtle.importKey("pkcs8", truncatedPkcs8P256Key2, { name: "ECDH", namedCurve: "P-256" }, extractable, ["deriveKey"])');
+shouldReject('crypto.subtle.importKey("pkcs8", truncatedPkcs8P256Key3, { name: "ECDH", namedCurve: "P-256" }, extractable, ["deriveKey"])');
+shouldReject('crypto.subtle.importKey("pkcs8", truncatedPkcs8P256Key4, { name: "ECDH", namedCurve: "P-256" }, extractable, ["deriveKey"])');
+shouldReject('crypto.subtle.importKey("pkcs8", truncatedPkcs8P256Key5, { name: "ECDH", namedCurve: "P-256" }, extractable, ["deriveKey"])');
+shouldReject('crypto.subtle.importKey("pkcs8", truncatedPkcs8P256Key6, { name: "ECDH", namedCurve: "P-256" }, extractable, ["deriveKey"])');
+shouldReject('crypto.subtle.importKey("pkcs8", truncatedPkcs8P256Key7, { name: "ECDH", namedCurve: "P-256" }, extractable, ["deriveKey"])');
+shouldReject('crypto.subtle.importKey("pkcs8", truncatedPkcs8P256Key8, { name: "ECDH", namedCurve: "P-256" }, extractable, ["deriveKey"])');
+shouldReject('crypto.subtle.importKey("pkcs8", truncatedPkcs8P256Key9, { name: "ECDH", namedCurve: "P-256" }, extractable, ["deriveKey"])');
+shouldReject('crypto.subtle.importKey("pkcs8", truncatedPkcs8P256Key10, { name: "ECDH", namedCurve: "P-256" }, extractable, ["deriveKey"])');
+shouldReject('crypto.subtle.importKey("pkcs8", truncatedPkcs8P256Key11, { name: "ECDH", namedCurve: "P-256" }, extractable, ["deriveKey"])');
+shouldReject('crypto.subtle.importKey("pkcs8", truncatedPkcs8P384Key1, { name: "ECDH", namedCurve: "P-384" }, extractable, ["deriveKey"])');
+shouldReject('crypto.subtle.importKey("pkcs8", truncatedPkcs8P384Key2, { name: "ECDH", namedCurve: "P-384" }, extractable, ["deriveKey"])');
+// Pkcs8: Long key
+shouldReject('crypto.subtle.importKey("pkcs8", longPkcs8P256Key, { name: "ECDH", namedCurve: "P-256" }, extractable, ["deriveKey"])');
+// Pkcs8: Corrupted Key Data
+shouldReject('crypto.subtle.importKey("pkcs8", corruptedPkcs8P256Key, { name: "ECDH", namedCurve: "P-256" }, extractable, ["deriveKey"])');
 </script>
 
 <script src="../../resources/js-test-post.js"></script>
diff --git a/LayoutTests/crypto/subtle/ec-import-pkcs8-key-export-jwk-key-expected.txt b/LayoutTests/crypto/subtle/ec-import-pkcs8-key-export-jwk-key-expected.txt
new file mode 100644
index 0000000..b6cc75b
--- /dev/null
+++ b/LayoutTests/crypto/subtle/ec-import-pkcs8-key-export-jwk-key-expected.txt
@@ -0,0 +1,17 @@
+Test importing a P-384 PKCS8 ECDH key and exporting it in JWK format
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Importing a key...
+PASS privateKey.kty is expectedJwkKey.kty
+PASS privateKey.crv is expectedJwkKey.crv
+PASS privateKey.x is expectedJwkKey.x
+PASS privateKey.y is expectedJwkKey.y
+PASS privateKey.d is expectedJwkKey.d
+PASS privateKey.key_ops is expectedJwkKey.key_ops
+PASS privateKey.ext is expectedJwkKey.ext
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/crypto/subtle/ec-import-pkcs8-key-export-jwk-key.html b/LayoutTests/crypto/subtle/ec-import-pkcs8-key-export-jwk-key.html
new file mode 100644
index 0000000..011b8b0
--- /dev/null
+++ b/LayoutTests/crypto/subtle/ec-import-pkcs8-key-export-jwk-key.html
@@ -0,0 +1,49 @@
+<!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 importing a P-384 PKCS8 ECDH key and exporting it in JWK format");
+
+jsTestIsAsync = true;
+
+var pkcs8Key = hexStringToUint8Array("3081b6020100301006072a8648ce3d020106052b8104002204819e30819b02010104307fdf264b53c1a5e0c6be32f6736a73591f6a2d536c5ac6906b19ebe371ab71ec84c2b102def67aa0db451382604fb21aa1640362000413dcd0e8352158ca1ee5807c3f91d3b7331942baf7a48b0e3ad28fb6b665b1d8188dc01415058dbdb141f81e7cbf595861b1617b3deb5360b7e3dd0e48b92cdf957117cdefa77bc8f797b5b73a614028a83fc123a48c74eec9ca3c3e89322d57");
+var expectedJwkKey = {
+    kty: "EC",
+    ext: true,
+    key_ops: ["deriveBits", "deriveKey"],
+    crv: "P-384",
+    x: "E9zQ6DUhWMoe5YB8P5HTtzMZQrr3pIsOOtKPtrZlsdgYjcAUFQWNvbFB-B58v1lY",
+    y: "YbFhez3rU2C3490OSLks35VxF83vp3vI95e1tzphQCioP8EjpIx07snKPD6JMi1X",
+    d: "f98mS1PBpeDGvjL2c2pzWR9qLVNsWsaQaxnr43GrceyEwrEC3vZ6oNtFE4JgT7Ia",
+};
+var extractable = true;
+
+debug("Importing a key...");
+crypto.subtle.importKey("pkcs8", pkcs8Key, {name: "ECDH", namedCurve: "P-384"}, extractable, ["deriveKey", "deriveBits"]).then(function(key) {
+    return crypto.subtle.exportKey("jwk", key);
+}).then(function(result) {
+    privateKey = result;
+
+    shouldBe("privateKey.kty", "expectedJwkKey.kty");
+    shouldBe("privateKey.crv", "expectedJwkKey.crv");
+    shouldBe("privateKey.x", "expectedJwkKey.x");
+    shouldBe("privateKey.y", "expectedJwkKey.y");
+    shouldBe("privateKey.d", "expectedJwkKey.d");
+    shouldBe("privateKey.key_ops", "expectedJwkKey.key_ops");
+    shouldBe("privateKey.ext", "expectedJwkKey.ext");
+
+    finishJSTest();
+});
+
+</script>
+
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/crypto/subtle/ec-import-pkcs8-key-export-pkcs8-key-p256-expected.txt b/LayoutTests/crypto/subtle/ec-import-pkcs8-key-export-pkcs8-key-p256-expected.txt
new file mode 100644
index 0000000..8cbb125
--- /dev/null
+++ b/LayoutTests/crypto/subtle/ec-import-pkcs8-key-export-pkcs8-key-p256-expected.txt
@@ -0,0 +1,11 @@
+Test importing a P-256 PKCS8 ECDH key and exporting it in PKCS8 format
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Importing a key...
+PASS bytesToHexString(privateKey) is pkcs8KeyHex
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/crypto/subtle/ec-import-pkcs8-key-export-pkcs8-key-p256.html b/LayoutTests/crypto/subtle/ec-import-pkcs8-key-export-pkcs8-key-p256.html
new file mode 100644
index 0000000..f2f855f
--- /dev/null
+++ b/LayoutTests/crypto/subtle/ec-import-pkcs8-key-export-pkcs8-key-p256.html
@@ -0,0 +1,35 @@
+<!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 importing a P-256 PKCS8 ECDH key and exporting it in PKCS8 format");
+
+jsTestIsAsync = true;
+
+var pkcs8KeyHex = "308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b02010104200a21f3f048b893b0f2b5a8459bd6d2bc112614aa86437f8fa2496a0e27f5b0a8a14403420004d726bd565878f24ee3616890d3668503334b84da3434b2774a44d6e4b9c536dd60e9181e1d1469ba3e6aba8987225f6e797d01a0dc400a4a298c902bae66abe2";
+var pkcs8Key = hexStringToUint8Array(pkcs8KeyHex);
+var extractable = true;
+
+debug("Importing a key...");
+crypto.subtle.importKey("pkcs8", pkcs8Key, {name: "ECDH", namedCurve: "P-256"}, extractable, ["deriveKey", "deriveBits"]).then(function(key) {
+    return crypto.subtle.exportKey("pkcs8", key);
+}).then(function(result) {
+    privateKey = result;
+
+    shouldBe("bytesToHexString(privateKey)", "pkcs8KeyHex");
+
+    finishJSTest();
+});
+
+</script>
+
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/crypto/subtle/ec-import-pkcs8-key-export-pkcs8-key-p384-expected.txt b/LayoutTests/crypto/subtle/ec-import-pkcs8-key-export-pkcs8-key-p384-expected.txt
new file mode 100644
index 0000000..42acdde
--- /dev/null
+++ b/LayoutTests/crypto/subtle/ec-import-pkcs8-key-export-pkcs8-key-p384-expected.txt
@@ -0,0 +1,11 @@
+Test importing a P-384 PKCS8 ECDH key and exporting it in PKCS8 format
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Importing a key...
+PASS bytesToHexString(privateKey) is pkcs8KeyHex
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/crypto/subtle/ec-import-pkcs8-key-export-pkcs8-key-p384.html b/LayoutTests/crypto/subtle/ec-import-pkcs8-key-export-pkcs8-key-p384.html
new file mode 100644
index 0000000..1661330
--- /dev/null
+++ b/LayoutTests/crypto/subtle/ec-import-pkcs8-key-export-pkcs8-key-p384.html
@@ -0,0 +1,35 @@
+<!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 importing a P-384 PKCS8 ECDH key and exporting it in PKCS8 format");
+
+jsTestIsAsync = true;
+
+var pkcs8KeyHex = "3081b6020100301006072a8648ce3d020106052b8104002204819e30819b02010104307fdf264b53c1a5e0c6be32f6736a73591f6a2d536c5ac6906b19ebe371ab71ec84c2b102def67aa0db451382604fb21aa1640362000413dcd0e8352158ca1ee5807c3f91d3b7331942baf7a48b0e3ad28fb6b665b1d8188dc01415058dbdb141f81e7cbf595861b1617b3deb5360b7e3dd0e48b92cdf957117cdefa77bc8f797b5b73a614028a83fc123a48c74eec9ca3c3e89322d57";
+var pkcs8Key = hexStringToUint8Array(pkcs8KeyHex);
+var extractable = true;
+
+debug("Importing a key...");
+crypto.subtle.importKey("pkcs8", pkcs8Key, {name: "ECDH", namedCurve: "P-384"}, extractable, ["deriveKey", "deriveBits"]).then(function(key) {
+    return crypto.subtle.exportKey("pkcs8", key);
+}).then(function(result) {
+    privateKey = result;
+
+    shouldBe("bytesToHexString(privateKey)", "pkcs8KeyHex");
+
+    finishJSTest();
+});
+
+</script>
+
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/crypto/subtle/ec-import-raw-key-export-spki-key-expected.txt b/LayoutTests/crypto/subtle/ec-import-raw-key-export-spki-key-expected.txt
new file mode 100644
index 0000000..542e6aa
--- /dev/null
+++ b/LayoutTests/crypto/subtle/ec-import-raw-key-export-spki-key-expected.txt
@@ -0,0 +1,11 @@
+Test importing an ECDH raw key and then export it in SPKI format
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Importing a key...
+PASS bytesToHexString(publicKey) is expectedSpkiKey
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/crypto/subtle/ec-import-raw-key-export-spki-key.html b/LayoutTests/crypto/subtle/ec-import-raw-key-export-spki-key.html
new file mode 100644
index 0000000..56b0b00
--- /dev/null
+++ b/LayoutTests/crypto/subtle/ec-import-raw-key-export-spki-key.html
@@ -0,0 +1,35 @@
+<!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 importing an ECDH raw key and then export it in SPKI format");
+
+jsTestIsAsync = true;
+
+var rawKey = hexStringToUint8Array("04dc08d9bf603333eab1ad29cef41a6203ab6ecce03c5a4a9bf5771a3fb9f971d89a09664bfb87c61199b3453220eadec714c49ad1e24bf5d7ec5bddeca6420893");
+var expectedSpkiKey = "3059301306072a8648ce3d020106082a8648ce3d03010703420004dc08d9bf603333eab1ad29cef41a6203ab6ecce03c5a4a9bf5771a3fb9f971d89a09664bfb87c61199b3453220eadec714c49ad1e24bf5d7ec5bddeca6420893";
+var extractable = true;
+
+debug("Importing a key...");
+crypto.subtle.importKey("raw", rawKey, { name: "ECDH", namedCurve: "P-256" }, extractable, [ ]).then(function(key) {
+    return crypto.subtle.exportKey("spki", key);
+}).then(function(result) {
+    publicKey = result;
+
+    shouldBe("bytesToHexString(publicKey)", "expectedSpkiKey");
+
+    finishJSTest();
+});
+
+</script>
+
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/crypto/subtle/ec-import-spki-key-export-jwk-key-expected.txt b/LayoutTests/crypto/subtle/ec-import-spki-key-export-jwk-key-expected.txt
new file mode 100644
index 0000000..da5b7d2
--- /dev/null
+++ b/LayoutTests/crypto/subtle/ec-import-spki-key-export-jwk-key-expected.txt
@@ -0,0 +1,16 @@
+Test importing a SPKI ECDH key and exporting it in JWK format
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Importing a key...
+PASS publicKey.kty is expectedJwkKey.kty
+PASS publicKey.crv is expectedJwkKey.crv
+PASS publicKey.x is expectedJwkKey.x
+PASS publicKey.y is expectedJwkKey.y
+PASS publicKey.key_ops is [ ]
+PASS publicKey.ext is expectedJwkKey.ext
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/crypto/subtle/ec-import-spki-key-export-jwk-key.html b/LayoutTests/crypto/subtle/ec-import-spki-key-export-jwk-key.html
new file mode 100644
index 0000000..03588d1
--- /dev/null
+++ b/LayoutTests/crypto/subtle/ec-import-spki-key-export-jwk-key.html
@@ -0,0 +1,49 @@
+<!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 importing a SPKI ECDH key and exporting it in JWK format");
+
+jsTestIsAsync = true;
+
+var spkiKey = hexStringToUint8Array("3059301306072a8648ce3d020106082a8648ce3d03010703420004c3ee3a2c3380072b9b2a59fed2cada65121806e22c4f4f8a25e740fc3e54d75d86c200298e6dfc1611d185eedbdb3c2661b0eb0441f7fd57c90d08112e9ae71c");
+var expectedJwkKey = {
+    kty: "EC",
+    use: "enc",
+    ext: true,
+    crv: "P-256",
+    x: "w-46LDOAByubKln-0sraZRIYBuIsT0-KJedA_D5U110",
+    y: "hsIAKY5t_BYR0YXu29s8JmGw6wRB9_1XyQ0IES6a5xw",
+};
+
+var extractable = true;
+
+debug("Importing a key...");
+crypto.subtle.importKey("spki", spkiKey, {name: "ECDH", namedCurve: "P-256"}, extractable, [ ]).then(function(key) {
+    return crypto.subtle.exportKey("jwk", key);
+}).then(function(result) {
+    publicKey = result;
+
+
+    shouldBe("publicKey.kty", "expectedJwkKey.kty");
+    shouldBe("publicKey.crv", "expectedJwkKey.crv");
+    shouldBe("publicKey.x", "expectedJwkKey.x");
+    shouldBe("publicKey.y", "expectedJwkKey.y");
+    shouldBe("publicKey.key_ops", "[ ]");
+    shouldBe("publicKey.ext", "expectedJwkKey.ext");
+
+    finishJSTest();
+});
+
+</script>
+
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/crypto/subtle/ec-import-spki-key-export-raw-key-expected.txt b/LayoutTests/crypto/subtle/ec-import-spki-key-export-raw-key-expected.txt
new file mode 100644
index 0000000..2583974
--- /dev/null
+++ b/LayoutTests/crypto/subtle/ec-import-spki-key-export-raw-key-expected.txt
@@ -0,0 +1,11 @@
+Test importing a SPKI ECDH key and exporting it in raw format
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Importing a key...
+PASS bytesToHexString(publicKey) is expectedRawKey
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/crypto/subtle/ec-import-spki-key-export-raw-key.html b/LayoutTests/crypto/subtle/ec-import-spki-key-export-raw-key.html
new file mode 100644
index 0000000..cf192c2
--- /dev/null
+++ b/LayoutTests/crypto/subtle/ec-import-spki-key-export-raw-key.html
@@ -0,0 +1,35 @@
+<!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 importing a SPKI ECDH key and exporting it in raw format");
+
+jsTestIsAsync = true;
+
+var spkiKey = hexStringToUint8Array("3059301306072a8648ce3d020106082a8648ce3d03010703420004c3ee3a2c3380072b9b2a59fed2cada65121806e22c4f4f8a25e740fc3e54d75d86c200298e6dfc1611d185eedbdb3c2661b0eb0441f7fd57c90d08112e9ae71c");
+var expectedRawKey = "04c3ee3a2c3380072b9b2a59fed2cada65121806e22c4f4f8a25e740fc3e54d75d86c200298e6dfc1611d185eedbdb3c2661b0eb0441f7fd57c90d08112e9ae71c";
+var extractable = true;
+
+debug("Importing a key...");
+crypto.subtle.importKey("spki", spkiKey, {name: "ECDH", namedCurve: "P-256"}, extractable, [ ]).then(function(key) {
+    return crypto.subtle.exportKey("raw", key);
+}).then(function(result) {
+    publicKey = result;
+
+    shouldBe("bytesToHexString(publicKey)", "expectedRawKey");
+
+    finishJSTest();
+});
+
+</script>
+
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/crypto/subtle/ec-import-spki-key-export-spki-key-p256-expected.txt b/LayoutTests/crypto/subtle/ec-import-spki-key-export-spki-key-p256-expected.txt
new file mode 100644
index 0000000..779bc63
--- /dev/null
+++ b/LayoutTests/crypto/subtle/ec-import-spki-key-export-spki-key-p256-expected.txt
@@ -0,0 +1,11 @@
+Test importing a P-256 SPKI ECDH key and exporting it in SPKI format
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Importing a key...
+PASS bytesToHexString(publicKey) is spkiKeyHex
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/crypto/subtle/ec-import-spki-key-export-spki-key-p256.html b/LayoutTests/crypto/subtle/ec-import-spki-key-export-spki-key-p256.html
new file mode 100644
index 0000000..63fd2d07
--- /dev/null
+++ b/LayoutTests/crypto/subtle/ec-import-spki-key-export-spki-key-p256.html
@@ -0,0 +1,35 @@
+<!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 importing a P-256 SPKI ECDH key and exporting it in SPKI format");
+
+jsTestIsAsync = true;
+
+var spkiKeyHex = "3059301306072a8648ce3d020106082a8648ce3d03010703420004c3ee3a2c3380072b9b2a59fed2cada65121806e22c4f4f8a25e740fc3e54d75d86c200298e6dfc1611d185eedbdb3c2661b0eb0441f7fd57c90d08112e9ae71c";
+var spkiKey = hexStringToUint8Array(spkiKeyHex);
+var extractable = true;
+
+debug("Importing a key...");
+crypto.subtle.importKey("spki", spkiKey, {name: "ECDH", namedCurve: "P-256"}, extractable, [ ]).then(function(key) {
+    return crypto.subtle.exportKey("spki", key);
+}).then(function(result) {
+    publicKey = result;
+
+    shouldBe("bytesToHexString(publicKey)", "spkiKeyHex");
+
+    finishJSTest();
+});
+
+</script>
+
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/crypto/subtle/ec-import-spki-key-export-spki-key-p384-expected.txt b/LayoutTests/crypto/subtle/ec-import-spki-key-export-spki-key-p384-expected.txt
new file mode 100644
index 0000000..27fa3f1
--- /dev/null
+++ b/LayoutTests/crypto/subtle/ec-import-spki-key-export-spki-key-p384-expected.txt
@@ -0,0 +1,11 @@
+Test importing a P-384 SPKI ECDH key and exporting it in SPKI format
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Importing a key...
+PASS bytesToHexString(publicKey) is spkiKeyHex
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/crypto/subtle/ec-import-spki-key-export-spki-key-p384.html b/LayoutTests/crypto/subtle/ec-import-spki-key-export-spki-key-p384.html
new file mode 100644
index 0000000..dabb9f8
--- /dev/null
+++ b/LayoutTests/crypto/subtle/ec-import-spki-key-export-spki-key-p384.html
@@ -0,0 +1,35 @@
+<!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 importing a P-384 SPKI ECDH key and exporting it in SPKI format");
+
+jsTestIsAsync = true;
+
+var spkiKeyHex = "3076301006072a8648ce3d020106052b8104002203620004478f6119747475f94b742654be32ab6ebbdc371afa34fbee6d12c32fe2d586231262b17d13a1f271f19c8008c034d8716b7df0ce1d987990c5b175ecae1aa40f2fb89e4778528e1234e56d69638db135d103fa68448fee2b4f58ecc86d7f4b7a";
+var spkiKey = hexStringToUint8Array(spkiKeyHex);
+var extractable = true;
+
+debug("Importing a key...");
+crypto.subtle.importKey("spki", spkiKey, {name: "ECDH", namedCurve: "P-384"}, extractable, [ ]).then(function(key) {
+    return crypto.subtle.exportKey("spki", key);
+}).then(function(result) {
+    publicKey = result;
+
+    shouldBe("bytesToHexString(publicKey)", "spkiKeyHex");
+
+    finishJSTest();
+});
+
+</script>
+
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/crypto/subtle/ecdh-generate-export-key-spki-p256-expected.txt b/LayoutTests/crypto/subtle/ecdh-generate-export-key-spki-p256-expected.txt
new file mode 100644
index 0000000..f510c8d
--- /dev/null
+++ b/LayoutTests/crypto/subtle/ecdh-generate-export-key-spki-p256-expected.txt
@@ -0,0 +1,12 @@
+Test exporting a P-256 ECDH public key with SPKI format.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Generating a key pair...
+Exporting the public key...
+PASS publicKey.byteLength is 91
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/crypto/subtle/ecdh-generate-export-key-spki-p256.html b/LayoutTests/crypto/subtle/ecdh-generate-export-key-spki-p256.html
new file mode 100644
index 0000000..47f3ad7
--- /dev/null
+++ b/LayoutTests/crypto/subtle/ecdh-generate-export-key-spki-p256.html
@@ -0,0 +1,39 @@
+<!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 exporting a P-256 ECDH public key with SPKI format.");
+
+jsTestIsAsync = true;
+
+var algorithmKeyGen = {
+    name: "ECDH",
+    namedCurve: "P-256"
+};
+var extractable = true;
+
+var keyPair;
+debug("Generating a key pair...");
+crypto.subtle.generateKey(algorithmKeyGen, extractable, ["deriveKey", "deriveBits"]).then(function(result) {
+    keyPair = result;
+    debug("Exporting the public key...");
+    return crypto.subtle.exportKey("spki", keyPair.publicKey);
+}).then(function(result) {
+    publicKey = result;
+
+    shouldBe("publicKey.byteLength", "91");
+
+    finishJSTest();
+});
+</script>
+
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/crypto/subtle/ecdh-generate-export-key-spki-p384-expected.txt b/LayoutTests/crypto/subtle/ecdh-generate-export-key-spki-p384-expected.txt
new file mode 100644
index 0000000..2487ea0
--- /dev/null
+++ b/LayoutTests/crypto/subtle/ecdh-generate-export-key-spki-p384-expected.txt
@@ -0,0 +1,12 @@
+Test exporting a P-384 ECDH public key with SPKI format.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Generating a key pair...
+Exporting the public key...
+PASS publicKey.byteLength is 120
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/crypto/subtle/ecdh-generate-export-key-spki-p384.html b/LayoutTests/crypto/subtle/ecdh-generate-export-key-spki-p384.html
new file mode 100644
index 0000000..6486cb7
--- /dev/null
+++ b/LayoutTests/crypto/subtle/ecdh-generate-export-key-spki-p384.html
@@ -0,0 +1,39 @@
+<!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 exporting a P-384 ECDH public key with SPKI format.");
+
+jsTestIsAsync = true;
+
+var algorithmKeyGen = {
+    name: "ECDH",
+    namedCurve: "P-384"
+};
+var extractable = true;
+
+var keyPair;
+debug("Generating a key pair...");
+crypto.subtle.generateKey(algorithmKeyGen, extractable, ["deriveKey", "deriveBits"]).then(function(result) {
+    keyPair = result;
+    debug("Exporting the public key...");
+    return crypto.subtle.exportKey("spki", keyPair.publicKey);
+}).then(function(result) {
+    publicKey = result;
+
+    shouldBe("publicKey.byteLength", "120");
+
+    finishJSTest();
+});
+</script>
+
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/crypto/subtle/ecdh-generate-export-pkcs8-p256-expected.txt b/LayoutTests/crypto/subtle/ecdh-generate-export-pkcs8-p256-expected.txt
new file mode 100644
index 0000000..5f308e6
--- /dev/null
+++ b/LayoutTests/crypto/subtle/ecdh-generate-export-pkcs8-p256-expected.txt
@@ -0,0 +1,12 @@
+Test exporting a P-256 ECDH private key with PKCS8 format.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Generating a key pair...
+Exporting the public key...
+PASS privateKey.byteLength is 138
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/crypto/subtle/ecdh-generate-export-pkcs8-p256.html b/LayoutTests/crypto/subtle/ecdh-generate-export-pkcs8-p256.html
new file mode 100644
index 0000000..9b4bc37
--- /dev/null
+++ b/LayoutTests/crypto/subtle/ecdh-generate-export-pkcs8-p256.html
@@ -0,0 +1,39 @@
+<!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 exporting a P-256 ECDH private key with PKCS8 format.");
+
+jsTestIsAsync = true;
+
+var algorithmKeyGen = {
+    name: "ECDH",
+    namedCurve: "P-256"
+};
+var extractable = true;
+
+var keyPair;
+debug("Generating a key pair...");
+crypto.subtle.generateKey(algorithmKeyGen, extractable, ["deriveKey", "deriveBits"]).then(function(result) {
+    keyPair = result;
+    debug("Exporting the public key...");
+    return crypto.subtle.exportKey("pkcs8", keyPair.privateKey);
+}).then(function(result) {
+    privateKey = result;
+
+    shouldBe("privateKey.byteLength", "138");
+
+    finishJSTest();
+});
+</script>
+
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/crypto/subtle/ecdh-generate-export-pkcs8-p384-expected.txt b/LayoutTests/crypto/subtle/ecdh-generate-export-pkcs8-p384-expected.txt
new file mode 100644
index 0000000..6f25bd1
--- /dev/null
+++ b/LayoutTests/crypto/subtle/ecdh-generate-export-pkcs8-p384-expected.txt
@@ -0,0 +1,12 @@
+Test exporting a P-384 ECDH private key with PKCS8 format.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Generating a key pair...
+Exporting the public key...
+PASS privateKey.byteLength is 185
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/crypto/subtle/ecdh-generate-export-pkcs8-p384.html b/LayoutTests/crypto/subtle/ecdh-generate-export-pkcs8-p384.html
new file mode 100644
index 0000000..34b9457
--- /dev/null
+++ b/LayoutTests/crypto/subtle/ecdh-generate-export-pkcs8-p384.html
@@ -0,0 +1,39 @@
+<!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 exporting a P-384 ECDH private key with PKCS8 format.");
+
+jsTestIsAsync = true;
+
+var algorithmKeyGen = {
+    name: "ECDH",
+    namedCurve: "P-384"
+};
+var extractable = true;
+
+var keyPair;
+debug("Generating a key pair...");
+crypto.subtle.generateKey(algorithmKeyGen, extractable, ["deriveKey", "deriveBits"]).then(function(result) {
+    keyPair = result;
+    debug("Exporting the public key...");
+    return crypto.subtle.exportKey("pkcs8", keyPair.privateKey);
+}).then(function(result) {
+    privateKey = result;
+
+    shouldBe("privateKey.byteLength", "185");
+
+    finishJSTest();
+});
+</script>
+
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/crypto/subtle/ecdh-import-pkcs8-key-p256-expected.txt b/LayoutTests/crypto/subtle/ecdh-import-pkcs8-key-p256-expected.txt
new file mode 100644
index 0000000..c0d2bf0
--- /dev/null
+++ b/LayoutTests/crypto/subtle/ecdh-import-pkcs8-key-p256-expected.txt
@@ -0,0 +1,16 @@
+Test importing a P-256 PKCS8 ECDH key
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Importing a key...
+PASS publicKey.toString() is '[object CryptoKey]'
+PASS publicKey.type is 'private'
+PASS publicKey.extractable is true
+PASS publicKey.algorithm.name is 'ECDH'
+PASS publicKey.algorithm.namedCurve is 'P-256'
+PASS publicKey.usages is [ 'deriveBits', 'deriveKey' ]
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/crypto/subtle/ecdh-import-pkcs8-key-p256.html b/LayoutTests/crypto/subtle/ecdh-import-pkcs8-key-p256.html
new file mode 100644
index 0000000..dc1b3bd
--- /dev/null
+++ b/LayoutTests/crypto/subtle/ecdh-import-pkcs8-key-p256.html
@@ -0,0 +1,37 @@
+<!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 importing a P-256 PKCS8 ECDH key");
+
+jsTestIsAsync = true;
+
+var pkcs8Key = hexStringToUint8Array("308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b02010104200a21f3f048b893b0f2b5a8459bd6d2bc112614aa86437f8fa2496a0e27f5b0a8a14403420004d726bd565878f24ee3616890d3668503334b84da3434b2774a44d6e4b9c536dd60e9181e1d1469ba3e6aba8987225f6e797d01a0dc400a4a298c902bae66abe2");
+var extractable = true;
+
+debug("Importing a key...");
+crypto.subtle.importKey("pkcs8", pkcs8Key, {name: "ECDH", namedCurve: "P-256"}, extractable, ["deriveKey", "deriveBits"]).then(function(result) {
+    publicKey = result;
+
+    shouldBe("publicKey.toString()", "'[object CryptoKey]'");
+    shouldBe("publicKey.type", "'private'");
+    shouldBe("publicKey.extractable", "true");
+    shouldBe("publicKey.algorithm.name", "'ECDH'");
+    shouldBe("publicKey.algorithm.namedCurve", "'P-256'");
+    shouldBe("publicKey.usages", "[ 'deriveBits', 'deriveKey' ]");
+
+    finishJSTest();
+});
+
+</script>
+
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/crypto/subtle/ecdh-import-pkcs8-key-p384-expected.txt b/LayoutTests/crypto/subtle/ecdh-import-pkcs8-key-p384-expected.txt
new file mode 100644
index 0000000..3fb47e3
--- /dev/null
+++ b/LayoutTests/crypto/subtle/ecdh-import-pkcs8-key-p384-expected.txt
@@ -0,0 +1,16 @@
+Test importing a P-384 PKCS8 ECDH key
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Importing a key...
+PASS publicKey.toString() is '[object CryptoKey]'
+PASS publicKey.type is 'private'
+PASS publicKey.extractable is true
+PASS publicKey.algorithm.name is 'ECDH'
+PASS publicKey.algorithm.namedCurve is 'P-384'
+PASS publicKey.usages is [ 'deriveBits', 'deriveKey' ]
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/crypto/subtle/ecdh-import-pkcs8-key-p384.html b/LayoutTests/crypto/subtle/ecdh-import-pkcs8-key-p384.html
new file mode 100644
index 0000000..bf73687
--- /dev/null
+++ b/LayoutTests/crypto/subtle/ecdh-import-pkcs8-key-p384.html
@@ -0,0 +1,38 @@
+<!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 importing a P-384 PKCS8 ECDH key");
+
+jsTestIsAsync = true;
+
+// From OpenSSL
+var pkcs8Key = Base64URL.parse("MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDCmchQf8pIqW87DnVZ/hRK5k4ueQK58pYL9KZ5pRl0HIl/Y9NOOy9SQydZKjZclxRihZANiAARP6PR5oBstUk0PY3rdA5G3MzRKnspHAjWdQq1CrP0GMud8hVU06JaCj+x2MYs6p/l0XtlKGaVRUqRBjP3yd9PXBt3z1EPuBxCscXzoW6YOj+KefYs9/geXx+tH0sGahso");
+var extractable = true;
+
+debug("Importing a key...");
+crypto.subtle.importKey("pkcs8", pkcs8Key, {name: "ECDH", namedCurve: "P-384"}, extractable, ["deriveKey", "deriveBits"]).then(function(result) {
+    publicKey = result;
+
+    shouldBe("publicKey.toString()", "'[object CryptoKey]'");
+    shouldBe("publicKey.type", "'private'");
+    shouldBe("publicKey.extractable", "true");
+    shouldBe("publicKey.algorithm.name", "'ECDH'");
+    shouldBe("publicKey.algorithm.namedCurve", "'P-384'");
+    shouldBe("publicKey.usages", "[ 'deriveBits', 'deriveKey' ]");
+
+    finishJSTest();
+});
+
+</script>
+
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/crypto/subtle/ecdh-import-spki-key-p256-expected.txt b/LayoutTests/crypto/subtle/ecdh-import-spki-key-p256-expected.txt
new file mode 100644
index 0000000..55385f1
--- /dev/null
+++ b/LayoutTests/crypto/subtle/ecdh-import-spki-key-p256-expected.txt
@@ -0,0 +1,16 @@
+Test importing a P-256 SPKI ECDH key
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Importing a key...
+PASS publicKey.toString() is '[object CryptoKey]'
+PASS publicKey.type is 'public'
+PASS publicKey.extractable is true
+PASS publicKey.algorithm.name is 'ECDH'
+PASS publicKey.algorithm.namedCurve is 'P-256'
+PASS publicKey.usages is [ ]
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/crypto/subtle/ecdh-import-spki-key-p256.html b/LayoutTests/crypto/subtle/ecdh-import-spki-key-p256.html
new file mode 100644
index 0000000..2ce6fa1
--- /dev/null
+++ b/LayoutTests/crypto/subtle/ecdh-import-spki-key-p256.html
@@ -0,0 +1,37 @@
+<!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 importing a P-256 SPKI ECDH key");
+
+jsTestIsAsync = true;
+
+var spkiKey = hexStringToUint8Array("3059301306072a8648ce3d020106082a8648ce3d03010703420004c3ee3a2c3380072b9b2a59fed2cada65121806e22c4f4f8a25e740fc3e54d75d86c200298e6dfc1611d185eedbdb3c2661b0eb0441f7fd57c90d08112e9ae71c");
+var extractable = true;
+
+debug("Importing a key...");
+crypto.subtle.importKey("spki", spkiKey, {name: "ECDH", namedCurve: "P-256"}, extractable, [ ]).then(function(result) {
+    publicKey = result;
+
+    shouldBe("publicKey.toString()", "'[object CryptoKey]'");
+    shouldBe("publicKey.type", "'public'");
+    shouldBe("publicKey.extractable", "true");
+    shouldBe("publicKey.algorithm.name", "'ECDH'");
+    shouldBe("publicKey.algorithm.namedCurve", "'P-256'");
+    shouldBe("publicKey.usages", "[ ]");
+
+    finishJSTest();
+});
+
+</script>
+
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/crypto/subtle/ecdh-import-spki-key-p384-expected.txt b/LayoutTests/crypto/subtle/ecdh-import-spki-key-p384-expected.txt
new file mode 100644
index 0000000..f25fef4
--- /dev/null
+++ b/LayoutTests/crypto/subtle/ecdh-import-spki-key-p384-expected.txt
@@ -0,0 +1,16 @@
+Test importing a P-384 SPKI ECDH key
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Importing a key...
+PASS publicKey.toString() is '[object CryptoKey]'
+PASS publicKey.type is 'public'
+PASS publicKey.extractable is true
+PASS publicKey.algorithm.name is 'ECDH'
+PASS publicKey.algorithm.namedCurve is 'P-384'
+PASS publicKey.usages is [ ]
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/crypto/subtle/ecdh-import-spki-key-p384.html b/LayoutTests/crypto/subtle/ecdh-import-spki-key-p384.html
new file mode 100644
index 0000000..d50323b
--- /dev/null
+++ b/LayoutTests/crypto/subtle/ecdh-import-spki-key-p384.html
@@ -0,0 +1,38 @@
+<!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 importing a P-384 SPKI ECDH key");
+
+jsTestIsAsync = true;
+
+// From OpenSSL
+var spkiKey = Base64URL.parse("MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAET+j0eaAbLVJND2N63QORtzM0Sp7KRwI1nUKtQqz9BjLnfIVVNOiWgo/sdjGLOqf5dF7ZShmlUVKkQYz98nfT1wbd89RD7gcQrHF86FumDo/inn2LPf4Hl8frR9LBmobK");
+var extractable = true;
+
+debug("Importing a key...");
+crypto.subtle.importKey("spki", spkiKey, {name: "ECDH", namedCurve: "P-384"}, extractable, [ ]).then(function(result) {
+    publicKey = result;
+
+    shouldBe("publicKey.toString()", "'[object CryptoKey]'");
+    shouldBe("publicKey.type", "'public'");
+    shouldBe("publicKey.extractable", "true");
+    shouldBe("publicKey.algorithm.name", "'ECDH'");
+    shouldBe("publicKey.algorithm.namedCurve", "'P-384'");
+    shouldBe("publicKey.usages", "[ ]");
+
+    finishJSTest();
+});
+
+</script>
+
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/crypto/workers/subtle/ec-generate-export-pkcs8-key-expected.txt b/LayoutTests/crypto/workers/subtle/ec-generate-export-pkcs8-key-expected.txt
new file mode 100644
index 0000000..941dabf
--- /dev/null
+++ b/LayoutTests/crypto/workers/subtle/ec-generate-export-pkcs8-key-expected.txt
@@ -0,0 +1,13 @@
+[Worker] Test exporting a ECDH private key with PKCS8 format.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Starting worker: resources/ec-generate-export-pkcs8-key.js
+[Worker] Generating a key pair...
+[Worker] Exporting the public key...
+PASS [Worker] privateKey.byteLength is 185
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/crypto/workers/subtle/ec-generate-export-pkcs8-key.html b/LayoutTests/crypto/workers/subtle/ec-generate-export-pkcs8-key.html
new file mode 100644
index 0000000..acee33c
--- /dev/null
+++ b/LayoutTests/crypto/workers/subtle/ec-generate-export-pkcs8-key.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="../../../resources/js-test-pre.js"></script>
+</head>
+<body>
+    <script>
+        worker = startWorker('resources/ec-generate-export-pkcs8-key.js');
+    </script>
+    <script src="../../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/crypto/workers/subtle/ec-generate-export-spki-key-expected.txt b/LayoutTests/crypto/workers/subtle/ec-generate-export-spki-key-expected.txt
new file mode 100644
index 0000000..87bb20e
--- /dev/null
+++ b/LayoutTests/crypto/workers/subtle/ec-generate-export-spki-key-expected.txt
@@ -0,0 +1,13 @@
+[Worker] Test exporting an ECDH public key with SPKI format in workers.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Starting worker: resources/ec-generate-export-spki-key.js
+[Worker] Generating a key pair...
+[Worker] Exporting the public key...
+PASS [Worker] publicKey.byteLength is 91
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/crypto/workers/subtle/ec-generate-export-spki-key.html b/LayoutTests/crypto/workers/subtle/ec-generate-export-spki-key.html
new file mode 100644
index 0000000..4cb3328
--- /dev/null
+++ b/LayoutTests/crypto/workers/subtle/ec-generate-export-spki-key.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="../../../resources/js-test-pre.js"></script>
+</head>
+<body>
+    <script>
+        worker = startWorker('resources/ec-generate-export-spki-key.js');
+    </script>
+    <script src="../../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/crypto/workers/subtle/ec-import-pkcs8-key-expected.txt b/LayoutTests/crypto/workers/subtle/ec-import-pkcs8-key-expected.txt
new file mode 100644
index 0000000..76886e2
--- /dev/null
+++ b/LayoutTests/crypto/workers/subtle/ec-import-pkcs8-key-expected.txt
@@ -0,0 +1,17 @@
+[Worker] Test importing a PKCS8 ECDH key in workers
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Starting worker: resources/ec-import-pkcs8-key.js
+[Worker] Importing a key...
+PASS [Worker] publicKey.toString() is '[object CryptoKey]'
+PASS [Worker] publicKey.type is 'private'
+PASS [Worker] publicKey.extractable is true
+PASS [Worker] publicKey.algorithm.name is 'ECDH'
+PASS [Worker] publicKey.algorithm.namedCurve is 'P-384'
+PASS [Worker] publicKey.usages is [ 'deriveBits', 'deriveKey' ]
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/crypto/workers/subtle/ec-import-pkcs8-key.html b/LayoutTests/crypto/workers/subtle/ec-import-pkcs8-key.html
new file mode 100644
index 0000000..701fc4e
--- /dev/null
+++ b/LayoutTests/crypto/workers/subtle/ec-import-pkcs8-key.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="../../../resources/js-test-pre.js"></script>
+</head>
+<body>
+    <script>
+        worker = startWorker('resources/ec-import-pkcs8-key.js');
+    </script>
+    <script src="../../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/crypto/workers/subtle/ec-import-spki-key-expected.txt b/LayoutTests/crypto/workers/subtle/ec-import-spki-key-expected.txt
new file mode 100644
index 0000000..a1af92a
--- /dev/null
+++ b/LayoutTests/crypto/workers/subtle/ec-import-spki-key-expected.txt
@@ -0,0 +1,17 @@
+[Worker] Test importing a SPKI ECDH key in workers
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Starting worker: resources/ec-import-spki-key.js
+[Worker] Importing a key...
+PASS [Worker] publicKey.toString() is '[object CryptoKey]'
+PASS [Worker] publicKey.type is 'public'
+PASS [Worker] publicKey.extractable is true
+PASS [Worker] publicKey.algorithm.name is 'ECDH'
+PASS [Worker] publicKey.algorithm.namedCurve is 'P-256'
+PASS [Worker] publicKey.usages is [ ]
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/crypto/workers/subtle/ec-import-spki-key.html b/LayoutTests/crypto/workers/subtle/ec-import-spki-key.html
new file mode 100644
index 0000000..d0367ef
--- /dev/null
+++ b/LayoutTests/crypto/workers/subtle/ec-import-spki-key.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="../../../resources/js-test-pre.js"></script>
+</head>
+<body>
+    <script>
+        worker = startWorker('resources/ec-import-spki-key.js');
+    </script>
+    <script src="../../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/crypto/workers/subtle/resources/ec-generate-export-pkcs8-key.js b/LayoutTests/crypto/workers/subtle/resources/ec-generate-export-pkcs8-key.js
new file mode 100644
index 0000000..9ebd49b
--- /dev/null
+++ b/LayoutTests/crypto/workers/subtle/resources/ec-generate-export-pkcs8-key.js
@@ -0,0 +1,26 @@
+importScripts('../../../../resources/js-test-pre.js');
+importScripts("../../../resources/common.js");
+
+description("Test exporting a ECDH private key with PKCS8 format.");
+
+jsTestIsAsync = true;
+
+var algorithmKeyGen = {
+    name: "ECDH",
+    namedCurve: "P-384"
+};
+var extractable = true;
+
+var keyPair;
+debug("Generating a key pair...");
+crypto.subtle.generateKey(algorithmKeyGen, extractable, ["deriveKey", "deriveBits"]).then(function(result) {
+    keyPair = result;
+    debug("Exporting the public key...");
+    return crypto.subtle.exportKey("pkcs8", keyPair.privateKey);
+}).then(function(result) {
+    privateKey = result;
+
+    shouldBe("privateKey.byteLength", "185");
+
+    finishJSTest();
+});
diff --git a/LayoutTests/crypto/workers/subtle/resources/ec-generate-export-spki-key.js b/LayoutTests/crypto/workers/subtle/resources/ec-generate-export-spki-key.js
new file mode 100644
index 0000000..9a39bd7
--- /dev/null
+++ b/LayoutTests/crypto/workers/subtle/resources/ec-generate-export-spki-key.js
@@ -0,0 +1,26 @@
+importScripts('../../../../resources/js-test-pre.js');
+importScripts("../../../resources/common.js");
+
+description("Test exporting an ECDH public key with SPKI format in workers.");
+
+jsTestIsAsync = true;
+
+var algorithmKeyGen = {
+    name: "ECDH",
+    namedCurve: "P-256"
+};
+var extractable = true;
+
+var keyPair;
+debug("Generating a key pair...");
+crypto.subtle.generateKey(algorithmKeyGen, extractable, ["deriveKey", "deriveBits"]).then(function(result) {
+    keyPair = result;
+    debug("Exporting the public key...");
+    return crypto.subtle.exportKey("spki", keyPair.publicKey);
+}).then(function(result) {
+    publicKey = result;
+
+    shouldBe("publicKey.byteLength", "91");
+
+    finishJSTest();
+});
diff --git a/LayoutTests/crypto/workers/subtle/resources/ec-import-pkcs8-key.js b/LayoutTests/crypto/workers/subtle/resources/ec-import-pkcs8-key.js
new file mode 100644
index 0000000..564a965
--- /dev/null
+++ b/LayoutTests/crypto/workers/subtle/resources/ec-import-pkcs8-key.js
@@ -0,0 +1,24 @@
+importScripts('../../../../resources/js-test-pre.js');
+importScripts("../../../resources/common.js");
+
+description("Test importing a PKCS8 ECDH key in workers");
+
+jsTestIsAsync = true;
+
+// From OpenSSL
+var pkcs8Key = Base64URL.parse("MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDCmchQf8pIqW87DnVZ/hRK5k4ueQK58pYL9KZ5pRl0HIl/Y9NOOy9SQydZKjZclxRihZANiAARP6PR5oBstUk0PY3rdA5G3MzRKnspHAjWdQq1CrP0GMud8hVU06JaCj+x2MYs6p/l0XtlKGaVRUqRBjP3yd9PXBt3z1EPuBxCscXzoW6YOj+KefYs9/geXx+tH0sGahso");
+var extractable = true;
+
+debug("Importing a key...");
+crypto.subtle.importKey("pkcs8", pkcs8Key, {name: "ECDH", namedCurve: "P-384"}, extractable, ["deriveKey", "deriveBits"]).then(function(result) {
+    publicKey = result;
+
+    shouldBe("publicKey.toString()", "'[object CryptoKey]'");
+    shouldBe("publicKey.type", "'private'");
+    shouldBe("publicKey.extractable", "true");
+    shouldBe("publicKey.algorithm.name", "'ECDH'");
+    shouldBe("publicKey.algorithm.namedCurve", "'P-384'");
+    shouldBe("publicKey.usages", "[ 'deriveBits', 'deriveKey' ]");
+
+    finishJSTest();
+});
diff --git a/LayoutTests/crypto/workers/subtle/resources/ec-import-spki-key.js b/LayoutTests/crypto/workers/subtle/resources/ec-import-spki-key.js
new file mode 100644
index 0000000..c03dfa1
--- /dev/null
+++ b/LayoutTests/crypto/workers/subtle/resources/ec-import-spki-key.js
@@ -0,0 +1,23 @@
+importScripts('../../../../resources/js-test-pre.js');
+importScripts("../../../resources/common.js");
+
+description("Test importing a SPKI ECDH key in workers");
+
+jsTestIsAsync = true;
+
+var spkiKey = hexStringToUint8Array("3059301306072a8648ce3d020106082a8648ce3d03010703420004c3ee3a2c3380072b9b2a59fed2cada65121806e22c4f4f8a25e740fc3e54d75d86c200298e6dfc1611d185eedbdb3c2661b0eb0441f7fd57c90d08112e9ae71c");
+var extractable = true;
+
+debug("Importing a key...");
+crypto.subtle.importKey("spki", spkiKey, {name: "ECDH", namedCurve: "P-256"}, extractable, [ ]).then(function(result) {
+    publicKey = result;
+
+    shouldBe("publicKey.toString()", "'[object CryptoKey]'");
+    shouldBe("publicKey.type", "'public'");
+    shouldBe("publicKey.extractable", "true");
+    shouldBe("publicKey.algorithm.name", "'ECDH'");
+    shouldBe("publicKey.algorithm.namedCurve", "'P-256'");
+    shouldBe("publicKey.usages", "[ ]");
+
+    finishJSTest();
+});
diff --git a/LayoutTests/imported/w3c/ChangeLog b/LayoutTests/imported/w3c/ChangeLog
index 2fba8fa..1bbbe76 100644
--- a/LayoutTests/imported/w3c/ChangeLog
+++ b/LayoutTests/imported/w3c/ChangeLog
@@ -1,3 +1,14 @@
+2017-03-16  Jiewen Tan  <jiewen_tan@apple.com>
+
+        [WebCrypto] Support SPKI/PKCS8 for Elliptic Curve
+        https://bugs.webkit.org/show_bug.cgi?id=169318
+        <rdar://problem/31081956>
+
+        Reviewed by Brent Fulgham.
+
+        * web-platform-tests/WebCryptoAPI/import_export/ec_importKey.worker-expected.txt:
+        * web-platform-tests/WebCryptoAPI/import_export/test_ec_importKey-expected.txt:
+
 2017-03-14  Youenn Fablet  <youenn@apple.com>
 
         Import web-platform-tests/cors
diff --git a/LayoutTests/imported/w3c/web-platform-tests/WebCryptoAPI/import_export/ec_importKey.worker-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/WebCryptoAPI/import_export/ec_importKey.worker-expected.txt
index bdb31ab..d7d8e25 100644
--- a/LayoutTests/imported/w3c/web-platform-tests/WebCryptoAPI/import_export/ec_importKey.worker-expected.txt
+++ b/LayoutTests/imported/w3c/web-platform-tests/WebCryptoAPI/import_export/ec_importKey.worker-expected.txt
@@ -23,52 +23,52 @@
 FAIL Good parameters: P-521 bits (jwk, object(kty, crv, x, y), {name: ECDSA, namedCurve: P-521}, false, []) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The operation is not supported. Reached unreachable code
 FAIL Good parameters: P-521 bits (pkcs8, buffer(241), {name: ECDSA, namedCurve: P-521}, false, [sign]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The operation is not supported. Reached unreachable code
 FAIL Good parameters: P-521 bits (jwk, object(kty, crv, x, y, d), {name: ECDSA, namedCurve: P-521}, false, [sign]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The operation is not supported. Reached unreachable code
-FAIL Good parameters: P-256 bits (spki, buffer(91), {name: ECDH, namedCurve: P-256}, true, []) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+PASS Good parameters: P-256 bits (spki, buffer(91), {name: ECDH, namedCurve: P-256}, true, []) 
 PASS Good parameters: P-256 bits (jwk, object(kty, crv, x, y), {name: ECDH, namedCurve: P-256}, true, []) 
-FAIL Good parameters: P-256 bits (pkcs8, buffer(138), {name: ECDH, namedCurve: P-256}, true, [deriveKey]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+PASS Good parameters: P-256 bits (pkcs8, buffer(138), {name: ECDH, namedCurve: P-256}, true, [deriveKey]) 
 PASS Good parameters: P-256 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-256}, true, [deriveKey]) 
-FAIL Good parameters: P-256 bits (pkcs8, buffer(138), {name: ECDH, namedCurve: P-256}, true, [deriveBits, deriveKey]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+PASS Good parameters: P-256 bits (pkcs8, buffer(138), {name: ECDH, namedCurve: P-256}, true, [deriveBits, deriveKey]) 
 PASS Good parameters: P-256 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-256}, true, [deriveBits, deriveKey]) 
-FAIL Good parameters: P-256 bits (pkcs8, buffer(138), {name: ECDH, namedCurve: P-256}, true, [deriveBits]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+PASS Good parameters: P-256 bits (pkcs8, buffer(138), {name: ECDH, namedCurve: P-256}, true, [deriveBits]) 
 PASS Good parameters: P-256 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-256}, true, [deriveBits]) 
-FAIL Good parameters: P-256 bits (spki, buffer(91), {name: ECDH, namedCurve: P-256}, false, []) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+PASS Good parameters: P-256 bits (spki, buffer(91), {name: ECDH, namedCurve: P-256}, false, []) 
 PASS Good parameters: P-256 bits (jwk, object(kty, crv, x, y), {name: ECDH, namedCurve: P-256}, false, []) 
-FAIL Good parameters: P-256 bits (pkcs8, buffer(138), {name: ECDH, namedCurve: P-256}, false, [deriveKey]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+PASS Good parameters: P-256 bits (pkcs8, buffer(138), {name: ECDH, namedCurve: P-256}, false, [deriveKey]) 
 PASS Good parameters: P-256 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-256}, false, [deriveKey]) 
-FAIL Good parameters: P-256 bits (pkcs8, buffer(138), {name: ECDH, namedCurve: P-256}, false, [deriveBits, deriveKey]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+PASS Good parameters: P-256 bits (pkcs8, buffer(138), {name: ECDH, namedCurve: P-256}, false, [deriveBits, deriveKey]) 
 PASS Good parameters: P-256 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-256}, false, [deriveBits, deriveKey]) 
-FAIL Good parameters: P-256 bits (pkcs8, buffer(138), {name: ECDH, namedCurve: P-256}, false, [deriveBits]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+PASS Good parameters: P-256 bits (pkcs8, buffer(138), {name: ECDH, namedCurve: P-256}, false, [deriveBits]) 
 PASS Good parameters: P-256 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-256}, false, [deriveBits]) 
-FAIL Good parameters: P-384 bits (spki, buffer(120), {name: ECDH, namedCurve: P-384}, true, []) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+PASS Good parameters: P-384 bits (spki, buffer(120), {name: ECDH, namedCurve: P-384}, true, []) 
 PASS Good parameters: P-384 bits (jwk, object(kty, crv, x, y), {name: ECDH, namedCurve: P-384}, true, []) 
-FAIL Good parameters: P-384 bits (pkcs8, buffer(185), {name: ECDH, namedCurve: P-384}, true, [deriveKey]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+PASS Good parameters: P-384 bits (pkcs8, buffer(185), {name: ECDH, namedCurve: P-384}, true, [deriveKey]) 
 PASS Good parameters: P-384 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-384}, true, [deriveKey]) 
-FAIL Good parameters: P-384 bits (pkcs8, buffer(185), {name: ECDH, namedCurve: P-384}, true, [deriveBits, deriveKey]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+PASS Good parameters: P-384 bits (pkcs8, buffer(185), {name: ECDH, namedCurve: P-384}, true, [deriveBits, deriveKey]) 
 PASS Good parameters: P-384 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-384}, true, [deriveBits, deriveKey]) 
-FAIL Good parameters: P-384 bits (pkcs8, buffer(185), {name: ECDH, namedCurve: P-384}, true, [deriveBits]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+PASS Good parameters: P-384 bits (pkcs8, buffer(185), {name: ECDH, namedCurve: P-384}, true, [deriveBits]) 
 PASS Good parameters: P-384 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-384}, true, [deriveBits]) 
-FAIL Good parameters: P-384 bits (spki, buffer(120), {name: ECDH, namedCurve: P-384}, false, []) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+PASS Good parameters: P-384 bits (spki, buffer(120), {name: ECDH, namedCurve: P-384}, false, []) 
 PASS Good parameters: P-384 bits (jwk, object(kty, crv, x, y), {name: ECDH, namedCurve: P-384}, false, []) 
-FAIL Good parameters: P-384 bits (pkcs8, buffer(185), {name: ECDH, namedCurve: P-384}, false, [deriveKey]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+PASS Good parameters: P-384 bits (pkcs8, buffer(185), {name: ECDH, namedCurve: P-384}, false, [deriveKey]) 
 PASS Good parameters: P-384 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-384}, false, [deriveKey]) 
-FAIL Good parameters: P-384 bits (pkcs8, buffer(185), {name: ECDH, namedCurve: P-384}, false, [deriveBits, deriveKey]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+PASS Good parameters: P-384 bits (pkcs8, buffer(185), {name: ECDH, namedCurve: P-384}, false, [deriveBits, deriveKey]) 
 PASS Good parameters: P-384 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-384}, false, [deriveBits, deriveKey]) 
-FAIL Good parameters: P-384 bits (pkcs8, buffer(185), {name: ECDH, namedCurve: P-384}, false, [deriveBits]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+PASS Good parameters: P-384 bits (pkcs8, buffer(185), {name: ECDH, namedCurve: P-384}, false, [deriveBits]) 
 PASS Good parameters: P-384 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-384}, false, [deriveBits]) 
-FAIL Good parameters: P-521 bits (spki, buffer(158), {name: ECDH, namedCurve: P-521}, true, []) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+FAIL Good parameters: P-521 bits (spki, buffer(158), {name: ECDH, namedCurve: P-521}, true, []) assert_unreached: Threw an unexpected error: DataError (DOM Exception 30): Data provided to an operation does not meet requirements Reached unreachable code
 FAIL Good parameters: P-521 bits (jwk, object(kty, crv, x, y), {name: ECDH, namedCurve: P-521}, true, []) assert_unreached: Threw an unexpected error: DataError (DOM Exception 30): Data provided to an operation does not meet requirements Reached unreachable code
-FAIL Good parameters: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, true, [deriveKey]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+FAIL Good parameters: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, true, [deriveKey]) assert_unreached: Threw an unexpected error: DataError (DOM Exception 30): Data provided to an operation does not meet requirements Reached unreachable code
 FAIL Good parameters: P-521 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-521}, true, [deriveKey]) assert_unreached: Threw an unexpected error: DataError (DOM Exception 30): Data provided to an operation does not meet requirements Reached unreachable code
-FAIL Good parameters: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, true, [deriveBits, deriveKey]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+FAIL Good parameters: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, true, [deriveBits, deriveKey]) assert_unreached: Threw an unexpected error: DataError (DOM Exception 30): Data provided to an operation does not meet requirements Reached unreachable code
 FAIL Good parameters: P-521 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-521}, true, [deriveBits, deriveKey]) assert_unreached: Threw an unexpected error: DataError (DOM Exception 30): Data provided to an operation does not meet requirements Reached unreachable code
-FAIL Good parameters: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, true, [deriveBits]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+FAIL Good parameters: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, true, [deriveBits]) assert_unreached: Threw an unexpected error: DataError (DOM Exception 30): Data provided to an operation does not meet requirements Reached unreachable code
 FAIL Good parameters: P-521 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-521}, true, [deriveBits]) assert_unreached: Threw an unexpected error: DataError (DOM Exception 30): Data provided to an operation does not meet requirements Reached unreachable code
-FAIL Good parameters: P-521 bits (spki, buffer(158), {name: ECDH, namedCurve: P-521}, false, []) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+FAIL Good parameters: P-521 bits (spki, buffer(158), {name: ECDH, namedCurve: P-521}, false, []) assert_unreached: Threw an unexpected error: DataError (DOM Exception 30): Data provided to an operation does not meet requirements Reached unreachable code
 FAIL Good parameters: P-521 bits (jwk, object(kty, crv, x, y), {name: ECDH, namedCurve: P-521}, false, []) assert_unreached: Threw an unexpected error: DataError (DOM Exception 30): Data provided to an operation does not meet requirements Reached unreachable code
-FAIL Good parameters: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, false, [deriveKey]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+FAIL Good parameters: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, false, [deriveKey]) assert_unreached: Threw an unexpected error: DataError (DOM Exception 30): Data provided to an operation does not meet requirements Reached unreachable code
 FAIL Good parameters: P-521 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-521}, false, [deriveKey]) assert_unreached: Threw an unexpected error: DataError (DOM Exception 30): Data provided to an operation does not meet requirements Reached unreachable code
-FAIL Good parameters: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, false, [deriveBits, deriveKey]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+FAIL Good parameters: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, false, [deriveBits, deriveKey]) assert_unreached: Threw an unexpected error: DataError (DOM Exception 30): Data provided to an operation does not meet requirements Reached unreachable code
 FAIL Good parameters: P-521 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-521}, false, [deriveBits, deriveKey]) assert_unreached: Threw an unexpected error: DataError (DOM Exception 30): Data provided to an operation does not meet requirements Reached unreachable code
-FAIL Good parameters: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, false, [deriveBits]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+FAIL Good parameters: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, false, [deriveBits]) assert_unreached: Threw an unexpected error: DataError (DOM Exception 30): Data provided to an operation does not meet requirements Reached unreachable code
 FAIL Good parameters: P-521 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-521}, false, [deriveBits]) assert_unreached: Threw an unexpected error: DataError (DOM Exception 30): Data provided to an operation does not meet requirements Reached unreachable code
 
diff --git a/LayoutTests/imported/w3c/web-platform-tests/WebCryptoAPI/import_export/test_ec_importKey-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/WebCryptoAPI/import_export/test_ec_importKey-expected.txt
index bdb31ab..d7d8e25 100644
--- a/LayoutTests/imported/w3c/web-platform-tests/WebCryptoAPI/import_export/test_ec_importKey-expected.txt
+++ b/LayoutTests/imported/w3c/web-platform-tests/WebCryptoAPI/import_export/test_ec_importKey-expected.txt
@@ -23,52 +23,52 @@
 FAIL Good parameters: P-521 bits (jwk, object(kty, crv, x, y), {name: ECDSA, namedCurve: P-521}, false, []) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The operation is not supported. Reached unreachable code
 FAIL Good parameters: P-521 bits (pkcs8, buffer(241), {name: ECDSA, namedCurve: P-521}, false, [sign]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The operation is not supported. Reached unreachable code
 FAIL Good parameters: P-521 bits (jwk, object(kty, crv, x, y, d), {name: ECDSA, namedCurve: P-521}, false, [sign]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The operation is not supported. Reached unreachable code
-FAIL Good parameters: P-256 bits (spki, buffer(91), {name: ECDH, namedCurve: P-256}, true, []) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+PASS Good parameters: P-256 bits (spki, buffer(91), {name: ECDH, namedCurve: P-256}, true, []) 
 PASS Good parameters: P-256 bits (jwk, object(kty, crv, x, y), {name: ECDH, namedCurve: P-256}, true, []) 
-FAIL Good parameters: P-256 bits (pkcs8, buffer(138), {name: ECDH, namedCurve: P-256}, true, [deriveKey]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+PASS Good parameters: P-256 bits (pkcs8, buffer(138), {name: ECDH, namedCurve: P-256}, true, [deriveKey]) 
 PASS Good parameters: P-256 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-256}, true, [deriveKey]) 
-FAIL Good parameters: P-256 bits (pkcs8, buffer(138), {name: ECDH, namedCurve: P-256}, true, [deriveBits, deriveKey]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+PASS Good parameters: P-256 bits (pkcs8, buffer(138), {name: ECDH, namedCurve: P-256}, true, [deriveBits, deriveKey]) 
 PASS Good parameters: P-256 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-256}, true, [deriveBits, deriveKey]) 
-FAIL Good parameters: P-256 bits (pkcs8, buffer(138), {name: ECDH, namedCurve: P-256}, true, [deriveBits]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+PASS Good parameters: P-256 bits (pkcs8, buffer(138), {name: ECDH, namedCurve: P-256}, true, [deriveBits]) 
 PASS Good parameters: P-256 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-256}, true, [deriveBits]) 
-FAIL Good parameters: P-256 bits (spki, buffer(91), {name: ECDH, namedCurve: P-256}, false, []) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+PASS Good parameters: P-256 bits (spki, buffer(91), {name: ECDH, namedCurve: P-256}, false, []) 
 PASS Good parameters: P-256 bits (jwk, object(kty, crv, x, y), {name: ECDH, namedCurve: P-256}, false, []) 
-FAIL Good parameters: P-256 bits (pkcs8, buffer(138), {name: ECDH, namedCurve: P-256}, false, [deriveKey]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+PASS Good parameters: P-256 bits (pkcs8, buffer(138), {name: ECDH, namedCurve: P-256}, false, [deriveKey]) 
 PASS Good parameters: P-256 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-256}, false, [deriveKey]) 
-FAIL Good parameters: P-256 bits (pkcs8, buffer(138), {name: ECDH, namedCurve: P-256}, false, [deriveBits, deriveKey]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+PASS Good parameters: P-256 bits (pkcs8, buffer(138), {name: ECDH, namedCurve: P-256}, false, [deriveBits, deriveKey]) 
 PASS Good parameters: P-256 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-256}, false, [deriveBits, deriveKey]) 
-FAIL Good parameters: P-256 bits (pkcs8, buffer(138), {name: ECDH, namedCurve: P-256}, false, [deriveBits]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+PASS Good parameters: P-256 bits (pkcs8, buffer(138), {name: ECDH, namedCurve: P-256}, false, [deriveBits]) 
 PASS Good parameters: P-256 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-256}, false, [deriveBits]) 
-FAIL Good parameters: P-384 bits (spki, buffer(120), {name: ECDH, namedCurve: P-384}, true, []) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+PASS Good parameters: P-384 bits (spki, buffer(120), {name: ECDH, namedCurve: P-384}, true, []) 
 PASS Good parameters: P-384 bits (jwk, object(kty, crv, x, y), {name: ECDH, namedCurve: P-384}, true, []) 
-FAIL Good parameters: P-384 bits (pkcs8, buffer(185), {name: ECDH, namedCurve: P-384}, true, [deriveKey]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+PASS Good parameters: P-384 bits (pkcs8, buffer(185), {name: ECDH, namedCurve: P-384}, true, [deriveKey]) 
 PASS Good parameters: P-384 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-384}, true, [deriveKey]) 
-FAIL Good parameters: P-384 bits (pkcs8, buffer(185), {name: ECDH, namedCurve: P-384}, true, [deriveBits, deriveKey]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+PASS Good parameters: P-384 bits (pkcs8, buffer(185), {name: ECDH, namedCurve: P-384}, true, [deriveBits, deriveKey]) 
 PASS Good parameters: P-384 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-384}, true, [deriveBits, deriveKey]) 
-FAIL Good parameters: P-384 bits (pkcs8, buffer(185), {name: ECDH, namedCurve: P-384}, true, [deriveBits]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+PASS Good parameters: P-384 bits (pkcs8, buffer(185), {name: ECDH, namedCurve: P-384}, true, [deriveBits]) 
 PASS Good parameters: P-384 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-384}, true, [deriveBits]) 
-FAIL Good parameters: P-384 bits (spki, buffer(120), {name: ECDH, namedCurve: P-384}, false, []) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+PASS Good parameters: P-384 bits (spki, buffer(120), {name: ECDH, namedCurve: P-384}, false, []) 
 PASS Good parameters: P-384 bits (jwk, object(kty, crv, x, y), {name: ECDH, namedCurve: P-384}, false, []) 
-FAIL Good parameters: P-384 bits (pkcs8, buffer(185), {name: ECDH, namedCurve: P-384}, false, [deriveKey]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+PASS Good parameters: P-384 bits (pkcs8, buffer(185), {name: ECDH, namedCurve: P-384}, false, [deriveKey]) 
 PASS Good parameters: P-384 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-384}, false, [deriveKey]) 
-FAIL Good parameters: P-384 bits (pkcs8, buffer(185), {name: ECDH, namedCurve: P-384}, false, [deriveBits, deriveKey]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+PASS Good parameters: P-384 bits (pkcs8, buffer(185), {name: ECDH, namedCurve: P-384}, false, [deriveBits, deriveKey]) 
 PASS Good parameters: P-384 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-384}, false, [deriveBits, deriveKey]) 
-FAIL Good parameters: P-384 bits (pkcs8, buffer(185), {name: ECDH, namedCurve: P-384}, false, [deriveBits]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+PASS Good parameters: P-384 bits (pkcs8, buffer(185), {name: ECDH, namedCurve: P-384}, false, [deriveBits]) 
 PASS Good parameters: P-384 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-384}, false, [deriveBits]) 
-FAIL Good parameters: P-521 bits (spki, buffer(158), {name: ECDH, namedCurve: P-521}, true, []) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+FAIL Good parameters: P-521 bits (spki, buffer(158), {name: ECDH, namedCurve: P-521}, true, []) assert_unreached: Threw an unexpected error: DataError (DOM Exception 30): Data provided to an operation does not meet requirements Reached unreachable code
 FAIL Good parameters: P-521 bits (jwk, object(kty, crv, x, y), {name: ECDH, namedCurve: P-521}, true, []) assert_unreached: Threw an unexpected error: DataError (DOM Exception 30): Data provided to an operation does not meet requirements Reached unreachable code
-FAIL Good parameters: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, true, [deriveKey]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+FAIL Good parameters: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, true, [deriveKey]) assert_unreached: Threw an unexpected error: DataError (DOM Exception 30): Data provided to an operation does not meet requirements Reached unreachable code
 FAIL Good parameters: P-521 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-521}, true, [deriveKey]) assert_unreached: Threw an unexpected error: DataError (DOM Exception 30): Data provided to an operation does not meet requirements Reached unreachable code
-FAIL Good parameters: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, true, [deriveBits, deriveKey]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+FAIL Good parameters: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, true, [deriveBits, deriveKey]) assert_unreached: Threw an unexpected error: DataError (DOM Exception 30): Data provided to an operation does not meet requirements Reached unreachable code
 FAIL Good parameters: P-521 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-521}, true, [deriveBits, deriveKey]) assert_unreached: Threw an unexpected error: DataError (DOM Exception 30): Data provided to an operation does not meet requirements Reached unreachable code
-FAIL Good parameters: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, true, [deriveBits]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+FAIL Good parameters: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, true, [deriveBits]) assert_unreached: Threw an unexpected error: DataError (DOM Exception 30): Data provided to an operation does not meet requirements Reached unreachable code
 FAIL Good parameters: P-521 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-521}, true, [deriveBits]) assert_unreached: Threw an unexpected error: DataError (DOM Exception 30): Data provided to an operation does not meet requirements Reached unreachable code
-FAIL Good parameters: P-521 bits (spki, buffer(158), {name: ECDH, namedCurve: P-521}, false, []) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+FAIL Good parameters: P-521 bits (spki, buffer(158), {name: ECDH, namedCurve: P-521}, false, []) assert_unreached: Threw an unexpected error: DataError (DOM Exception 30): Data provided to an operation does not meet requirements Reached unreachable code
 FAIL Good parameters: P-521 bits (jwk, object(kty, crv, x, y), {name: ECDH, namedCurve: P-521}, false, []) assert_unreached: Threw an unexpected error: DataError (DOM Exception 30): Data provided to an operation does not meet requirements Reached unreachable code
-FAIL Good parameters: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, false, [deriveKey]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+FAIL Good parameters: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, false, [deriveKey]) assert_unreached: Threw an unexpected error: DataError (DOM Exception 30): Data provided to an operation does not meet requirements Reached unreachable code
 FAIL Good parameters: P-521 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-521}, false, [deriveKey]) assert_unreached: Threw an unexpected error: DataError (DOM Exception 30): Data provided to an operation does not meet requirements Reached unreachable code
-FAIL Good parameters: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, false, [deriveBits, deriveKey]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+FAIL Good parameters: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, false, [deriveBits, deriveKey]) assert_unreached: Threw an unexpected error: DataError (DOM Exception 30): Data provided to an operation does not meet requirements Reached unreachable code
 FAIL Good parameters: P-521 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-521}, false, [deriveBits, deriveKey]) assert_unreached: Threw an unexpected error: DataError (DOM Exception 30): Data provided to an operation does not meet requirements Reached unreachable code
-FAIL Good parameters: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, false, [deriveBits]) assert_unreached: Threw an unexpected error: NotSupportedError (DOM Exception 9): The algorithm is not supported Reached unreachable code
+FAIL Good parameters: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, false, [deriveBits]) assert_unreached: Threw an unexpected error: DataError (DOM Exception 30): Data provided to an operation does not meet requirements Reached unreachable code
 FAIL Good parameters: P-521 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-521}, false, [deriveBits]) assert_unreached: Threw an unexpected error: DataError (DOM Exception 30): Data provided to an operation does not meet requirements Reached unreachable code