Quellcode durchsuchen

LibWeb: Implement ECDH.generateKey

devgianlu vor 7 Monaten
Ursprung
Commit
009f328308

+ 100 - 0
Libraries/LibWeb/Crypto/CryptoAlgorithms.cpp

@@ -2526,6 +2526,106 @@ WebIDL::ExceptionOr<JS::Value> ECDSA::verify(AlgorithmParams const& params, GC::
     return JS::Value(result);
 }
 
+// https://w3c.github.io/webcrypto/#ecdh-operations
+WebIDL::ExceptionOr<Variant<GC::Ref<CryptoKey>, GC::Ref<CryptoKeyPair>>> ECDH::generate_key(AlgorithmParams const& params, bool extractable, Vector<Bindings::KeyUsage> const& key_usages)
+{
+    // 1. If usages contains an entry which is not "deriveKey" or "deriveBits" then throw a SyntaxError.
+    for (auto const& usage : key_usages) {
+        if (usage != Bindings::KeyUsage::Derivekey && usage != Bindings::KeyUsage::Derivebits) {
+            return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", idl_enum_to_string(usage))));
+        }
+    }
+
+    auto const& normalized_algorithm = static_cast<EcKeyGenParams const&>(params);
+
+    // 2. If the namedCurve member of normalizedAlgorithm is "P-256", "P-384" or "P-521":
+    // Generate an Elliptic Curve key pair, as defined in [RFC6090]
+    // with domain parameters for the curve identified by the namedCurve member of normalizedAlgorithm.
+    Variant<Empty, ::Crypto::Curves::SECP256r1, ::Crypto::Curves::SECP384r1> curve;
+    if (normalized_algorithm.named_curve.is_one_of("P-256"sv, "P-384"sv, "P-521"sv)) {
+        if (normalized_algorithm.named_curve.equals_ignoring_ascii_case("P-256"sv))
+            curve = ::Crypto::Curves::SECP256r1 {};
+
+        if (normalized_algorithm.named_curve.equals_ignoring_ascii_case("P-384"sv))
+            curve = ::Crypto::Curves::SECP384r1 {};
+
+        // FIXME: Support P-521
+        if (normalized_algorithm.named_curve.equals_ignoring_ascii_case("P-521"sv))
+            return WebIDL::NotSupportedError::create(m_realm, "'P-521' is not supported yet"_string);
+    } else {
+        // If the namedCurve member of normalizedAlgorithm is a value specified in an applicable specification
+        // that specifies the use of that value with ECDH:
+        // Perform the ECDH generation steps specified in that specification,
+        // passing in normalizedAlgorithm and resulting in an elliptic curve key pair.
+
+        // Otherwise: throw a NotSupportedError
+        return WebIDL::NotSupportedError::create(m_realm, "Only 'P-256', 'P-384' and 'P-521' is supported"_string);
+    }
+
+    // 3. If performing the operation results in an error, then throw a OperationError.
+    auto maybe_private_key_data = curve.visit(
+        [](Empty const&) -> ErrorOr<ByteBuffer> { return Error::from_string_literal("noop error"); },
+        [](auto instance) { return instance.generate_private_key(); });
+
+    if (maybe_private_key_data.is_error())
+        return WebIDL::OperationError::create(m_realm, "Failed to create valid crypto instance"_string);
+
+    auto private_key_data = maybe_private_key_data.release_value();
+
+    auto maybe_public_key_data = curve.visit(
+        [](Empty const&) -> ErrorOr<ByteBuffer> { return Error::from_string_literal("noop error"); },
+        [&](auto instance) { return instance.generate_public_key(private_key_data); });
+
+    if (maybe_public_key_data.is_error())
+        return WebIDL::OperationError::create(m_realm, "Failed to create valid crypto instance"_string);
+
+    auto public_key_data = maybe_public_key_data.release_value();
+
+    // 4. Let algorithm be a new EcKeyAlgorithm object.
+    auto algorithm = EcKeyAlgorithm::create(m_realm);
+
+    // 5. Set the name attribute of algorithm to "ECDH".
+    algorithm->set_name("ECDH"_string);
+
+    // 6. Set the namedCurve attribute of algorithm to equal the namedCurve member of normalizedAlgorithm.
+    algorithm->set_named_curve(normalized_algorithm.named_curve);
+
+    // 7. Let publicKey be a new CryptoKey representing the public key of the generated key pair.
+    auto public_key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { public_key_data });
+
+    // 8. Set the [[type]] internal slot of publicKey to "public"
+    public_key->set_type(Bindings::KeyType::Public);
+
+    // 9. Set the [[algorithm]] internal slot of publicKey to algorithm.
+    public_key->set_algorithm(algorithm);
+
+    // 10. Set the [[extractable]] internal slot of publicKey to true.
+    public_key->set_extractable(true);
+
+    // 11. Set the [[usages]] internal slot of publicKey to be the empty list.
+    public_key->set_usages({});
+
+    // 12. Let privateKey be a new CryptoKey representing the private key of the generated key pair.
+    auto private_key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { private_key_data });
+
+    // 13. Set the [[type]] internal slot of privateKey to "private"
+    private_key->set_type(Bindings::KeyType::Private);
+
+    // 14. Set the [[algorithm]] internal slot of privateKey to algorithm.
+    private_key->set_algorithm(algorithm);
+
+    // 15. Set the [[extractable]] internal slot of privateKey to extractable.
+    private_key->set_extractable(extractable);
+
+    // 16. Set the [[usages]] internal slot of privateKey to be the usage intersection of usages and [ "deriveKey", "deriveBits" ].
+    private_key->set_usages(usage_intersection(key_usages, { { Bindings::KeyUsage::Derivekey, Bindings::KeyUsage::Derivebits } }));
+
+    // 17. Let result be a new CryptoKeyPair dictionary.
+    // 18. Set the publicKey attribute of result to be publicKey.
+    // 19. Set the privateKey attribute of result to be privateKey.
+    // 20. Return the result of converting result to an ECMAScript Object, as defined by [WebIDL].
+    return Variant<GC::Ref<CryptoKey>, GC::Ref<CryptoKeyPair>> { CryptoKeyPair::create(m_realm, public_key, private_key) };
+}
 // https://wicg.github.io/webcrypto-secure-curves/#ed25519-operations
 WebIDL::ExceptionOr<Variant<GC::Ref<CryptoKey>, GC::Ref<CryptoKeyPair>>> ED25519::generate_key([[maybe_unused]] AlgorithmParams const& params, bool extractable, Vector<Bindings::KeyUsage> const& key_usages)
 {

+ 16 - 0
Libraries/LibWeb/Crypto/CryptoAlgorithms.h

@@ -493,6 +493,22 @@ private:
     }
 };
 
+class ECDH : public AlgorithmMethods {
+public:
+    virtual WebIDL::ExceptionOr<Variant<GC::Ref<CryptoKey>, GC::Ref<CryptoKeyPair>>> generate_key(AlgorithmParams const&, bool, Vector<Bindings::KeyUsage> const&) override;
+    // TODO: virtual WebIDL::ExceptionOr<GC::Ref<JS::ArrayBuffer>> derive_bits(AlgorithmParams const&, GC::Ref<CryptoKey>, Optional<u32>) override;
+    // TODO: virtual WebIDL::ExceptionOr<GC::Ref<CryptoKey>> import_key(AlgorithmParams const&, Bindings::KeyFormat, CryptoKey::InternalKeyData, bool, Vector<Bindings::KeyUsage> const&) override;
+    // TODO: virtual WebIDL::ExceptionOr<GC::Ref<JS::Object>> export_key(Bindings::KeyFormat, GC::Ref<CryptoKey>) override;
+
+    static NonnullOwnPtr<AlgorithmMethods> create(JS::Realm& realm) { return adopt_own(*new ECDH(realm)); }
+
+private:
+    explicit ECDH(JS::Realm& realm)
+        : AlgorithmMethods(realm)
+    {
+    }
+};
+
 class ED25519 : public AlgorithmMethods {
 public:
     virtual WebIDL::ExceptionOr<GC::Ref<JS::ArrayBuffer>> sign(AlgorithmParams const&, GC::Ref<CryptoKey>, ByteBuffer const&) override;

+ 1 - 1
Libraries/LibWeb/Crypto/SubtleCrypto.cpp

@@ -801,10 +801,10 @@ SupportedAlgorithmsMap supported_algorithms()
     // FIXME: define_an_algorithm<ECDSA>("exportKey"_string, "ECDSA"_string);
 
     // https://w3c.github.io/webcrypto/#ecdh-registration
-    // FIXME: define_an_algorithm<ECDH, EcKeyGenParams>("generateKey"_string, "ECDH"_string);
     // FIXME: define_an_algorithm<ECDH, EcdhKeyDerivePrams>("deriveBits"_string, "ECDH"_string);
     // FIXME: define_an_algorithm<ECDH, EcKeyImportParams>("importKey"_string, "ECDH"_string);
     // FIXME: define_an_algorithm<ECDH>("exportKey"_string, "ECDH"_string);
+    define_an_algorithm<ECDH, EcKeyGenParams>("generateKey"_string, "ECDH"_string);
 
     // https://w3c.github.io/webcrypto/#aes-ctr-registration
     define_an_algorithm<AesCtr, AesCtrParams>("encrypt"_string, "AES-CTR"_string);

+ 487 - 0
Tests/LibWeb/Text/expected/wpt-import/WebCryptoAPI/generateKey/failures_ECDH.https.any.txt

@@ -0,0 +1,487 @@
+Summary
+
+Harness status: OK
+
+Rerun
+
+Found 476 tests
+
+410 Pass
+66 Fail
+Details
+Result	Test Name	MessagePass	Bad algorithm: generateKey(AES, false, [decrypt])	
+Pass	Bad algorithm: generateKey(AES, true, [decrypt])	
+Pass	Bad algorithm: generateKey(AES, RED, [decrypt])	
+Pass	Bad algorithm: generateKey(AES, 7, [decrypt])	
+Pass	Bad algorithm: generateKey(AES, false, [sign, decrypt])	
+Pass	Bad algorithm: generateKey(AES, true, [sign, decrypt])	
+Pass	Bad algorithm: generateKey(AES, RED, [sign, decrypt])	
+Pass	Bad algorithm: generateKey(AES, 7, [sign, decrypt])	
+Pass	Bad algorithm: generateKey(AES, false, [deriveBits, sign, decrypt])	
+Pass	Bad algorithm: generateKey(AES, true, [deriveBits, sign, decrypt])	
+Pass	Bad algorithm: generateKey(AES, RED, [deriveBits, sign, decrypt])	
+Pass	Bad algorithm: generateKey(AES, 7, [deriveBits, sign, decrypt])	
+Pass	Bad algorithm: generateKey(AES, false, [deriveBits, decrypt])	
+Pass	Bad algorithm: generateKey(AES, true, [deriveBits, decrypt])	
+Pass	Bad algorithm: generateKey(AES, RED, [deriveBits, decrypt])	
+Pass	Bad algorithm: generateKey(AES, 7, [deriveBits, decrypt])	
+Pass	Bad algorithm: generateKey(AES, false, [sign])	
+Pass	Bad algorithm: generateKey(AES, true, [sign])	
+Pass	Bad algorithm: generateKey(AES, RED, [sign])	
+Pass	Bad algorithm: generateKey(AES, 7, [sign])	
+Pass	Bad algorithm: generateKey(AES, false, [deriveBits, sign])	
+Pass	Bad algorithm: generateKey(AES, true, [deriveBits, sign])	
+Pass	Bad algorithm: generateKey(AES, RED, [deriveBits, sign])	
+Pass	Bad algorithm: generateKey(AES, 7, [deriveBits, sign])	
+Pass	Bad algorithm: generateKey(AES, false, [deriveBits])	
+Pass	Bad algorithm: generateKey(AES, true, [deriveBits])	
+Pass	Bad algorithm: generateKey(AES, RED, [deriveBits])	
+Pass	Bad algorithm: generateKey(AES, 7, [deriveBits])	
+Pass	Bad algorithm: generateKey(AES, false, [])	
+Pass	Bad algorithm: generateKey(AES, true, [])	
+Pass	Bad algorithm: generateKey(AES, RED, [])	
+Pass	Bad algorithm: generateKey(AES, 7, [])	
+Pass	Bad algorithm: generateKey(AES, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Pass	Bad algorithm: generateKey(AES, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Pass	Bad algorithm: generateKey(AES, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Pass	Bad algorithm: generateKey(AES, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Pass	Bad algorithm: generateKey({name: AES}, false, [decrypt])	
+Pass	Bad algorithm: generateKey({name: AES}, true, [decrypt])	
+Pass	Bad algorithm: generateKey({name: AES}, RED, [decrypt])	
+Pass	Bad algorithm: generateKey({name: AES}, 7, [decrypt])	
+Pass	Bad algorithm: generateKey({name: AES}, false, [sign, decrypt])	
+Pass	Bad algorithm: generateKey({name: AES}, true, [sign, decrypt])	
+Pass	Bad algorithm: generateKey({name: AES}, RED, [sign, decrypt])	
+Pass	Bad algorithm: generateKey({name: AES}, 7, [sign, decrypt])	
+Pass	Bad algorithm: generateKey({name: AES}, false, [deriveBits, sign, decrypt])	
+Pass	Bad algorithm: generateKey({name: AES}, true, [deriveBits, sign, decrypt])	
+Pass	Bad algorithm: generateKey({name: AES}, RED, [deriveBits, sign, decrypt])	
+Pass	Bad algorithm: generateKey({name: AES}, 7, [deriveBits, sign, decrypt])	
+Pass	Bad algorithm: generateKey({name: AES}, false, [deriveBits, decrypt])	
+Pass	Bad algorithm: generateKey({name: AES}, true, [deriveBits, decrypt])	
+Pass	Bad algorithm: generateKey({name: AES}, RED, [deriveBits, decrypt])	
+Pass	Bad algorithm: generateKey({name: AES}, 7, [deriveBits, decrypt])	
+Pass	Bad algorithm: generateKey({name: AES}, false, [sign])	
+Pass	Bad algorithm: generateKey({name: AES}, true, [sign])	
+Pass	Bad algorithm: generateKey({name: AES}, RED, [sign])	
+Pass	Bad algorithm: generateKey({name: AES}, 7, [sign])	
+Pass	Bad algorithm: generateKey({name: AES}, false, [deriveBits, sign])	
+Pass	Bad algorithm: generateKey({name: AES}, true, [deriveBits, sign])	
+Pass	Bad algorithm: generateKey({name: AES}, RED, [deriveBits, sign])	
+Pass	Bad algorithm: generateKey({name: AES}, 7, [deriveBits, sign])	
+Pass	Bad algorithm: generateKey({name: AES}, false, [deriveBits])	
+Pass	Bad algorithm: generateKey({name: AES}, true, [deriveBits])	
+Pass	Bad algorithm: generateKey({name: AES}, RED, [deriveBits])	
+Pass	Bad algorithm: generateKey({name: AES}, 7, [deriveBits])	
+Pass	Bad algorithm: generateKey({name: AES}, false, [])	
+Pass	Bad algorithm: generateKey({name: AES}, true, [])	
+Pass	Bad algorithm: generateKey({name: AES}, RED, [])	
+Pass	Bad algorithm: generateKey({name: AES}, 7, [])	
+Pass	Bad algorithm: generateKey({name: AES}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Pass	Bad algorithm: generateKey({name: AES}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Pass	Bad algorithm: generateKey({name: AES}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Pass	Bad algorithm: generateKey({name: AES}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES}, false, [decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES}, true, [decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES}, RED, [decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES}, 7, [decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES}, false, [sign, decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES}, true, [sign, decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES}, RED, [sign, decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES}, 7, [sign, decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES}, false, [deriveBits, sign, decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES}, true, [deriveBits, sign, decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES}, RED, [deriveBits, sign, decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES}, 7, [deriveBits, sign, decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES}, false, [deriveBits, decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES}, true, [deriveBits, decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES}, RED, [deriveBits, decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES}, 7, [deriveBits, decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES}, false, [sign])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES}, true, [sign])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES}, RED, [sign])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES}, 7, [sign])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES}, false, [deriveBits, sign])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES}, true, [deriveBits, sign])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES}, RED, [deriveBits, sign])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES}, 7, [deriveBits, sign])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES}, false, [deriveBits])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES}, true, [deriveBits])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES}, RED, [deriveBits])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES}, 7, [deriveBits])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES}, false, [])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES}, true, [])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES}, RED, [])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES}, 7, [])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [sign, decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [sign, decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [sign, decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [sign, decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [deriveBits, sign, decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [deriveBits, sign, decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [deriveBits, sign, decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [deriveBits, sign, decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [deriveBits, decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [deriveBits, decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [deriveBits, decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [deriveBits, decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [sign])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [sign])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [sign])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [sign])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [deriveBits, sign])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [deriveBits, sign])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [deriveBits, sign])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [deriveBits, sign])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [deriveBits])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [deriveBits])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [deriveBits])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [deriveBits])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CMAC}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CMAC}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CMAC}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CMAC}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [sign, decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [sign, decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [sign, decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [sign, decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [deriveBits, sign, decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [deriveBits, sign, decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [deriveBits, sign, decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [deriveBits, sign, decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [deriveBits, decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [deriveBits, decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [deriveBits, decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [deriveBits, decrypt])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [sign])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [sign])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [sign])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [sign])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [deriveBits, sign])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [deriveBits, sign])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [deriveBits, sign])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [deriveBits, sign])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [deriveBits])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [deriveBits])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [deriveBits])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [deriveBits])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CFB}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CFB}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CFB}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Pass	Bad algorithm: generateKey({length: 128, name: AES-CFB}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Fail	Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [decrypt])	
+Fail	Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [decrypt])	
+Fail	Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [decrypt])	
+Fail	Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [decrypt])	
+Fail	Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [sign, decrypt])	
+Fail	Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [sign, decrypt])	
+Fail	Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [sign, decrypt])	
+Fail	Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [sign, decrypt])	
+Fail	Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [deriveBits, sign, decrypt])	
+Fail	Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [deriveBits, sign, decrypt])	
+Fail	Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [deriveBits, sign, decrypt])	
+Fail	Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [deriveBits, sign, decrypt])	
+Fail	Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [deriveBits, decrypt])	
+Fail	Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [deriveBits, decrypt])	
+Fail	Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [deriveBits, decrypt])	
+Fail	Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [deriveBits, decrypt])	
+Pass	Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [sign])	
+Pass	Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [sign])	
+Pass	Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [sign])	
+Pass	Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [sign])	
+Fail	Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [deriveBits, sign])	
+Fail	Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [deriveBits, sign])	
+Fail	Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [deriveBits, sign])	
+Fail	Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [deriveBits, sign])	
+Fail	Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [deriveBits])	
+Fail	Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [deriveBits])	
+Fail	Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [deriveBits])	
+Fail	Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [deriveBits])	
+Pass	Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [])	
+Pass	Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [])	
+Pass	Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [])	
+Pass	Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [])	
+Fail	Bad algorithm: generateKey({hash: MD5, name: HMAC}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Fail	Bad algorithm: generateKey({hash: MD5, name: HMAC}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Fail	Bad algorithm: generateKey({hash: MD5, name: HMAC}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Fail	Bad algorithm: generateKey({hash: MD5, name: HMAC}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Pass	Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [decrypt])	
+Pass	Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt])	
+Pass	Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [decrypt])	
+Pass	Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [decrypt])	
+Pass	Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign, decrypt])	
+Pass	Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, decrypt])	
+Pass	Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [sign, decrypt])	
+Pass	Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [sign, decrypt])	
+Pass	Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits, sign, decrypt])	
+Pass	Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits, sign, decrypt])	
+Pass	Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits, sign, decrypt])	
+Pass	Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits, sign, decrypt])	
+Pass	Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits, decrypt])	
+Pass	Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits, decrypt])	
+Pass	Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits, decrypt])	
+Pass	Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits, decrypt])	
+Pass	Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign])	
+Pass	Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign])	
+Pass	Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [sign])	
+Pass	Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [sign])	
+Pass	Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits, sign])	
+Pass	Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits, sign])	
+Pass	Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits, sign])	
+Pass	Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits, sign])	
+Pass	Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits])	
+Pass	Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits])	
+Pass	Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits])	
+Pass	Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits])	
+Pass	Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [])	
+Pass	Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [])	
+Pass	Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [])	
+Pass	Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [])	
+Pass	Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Pass	Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Pass	Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Pass	Bad algorithm: generateKey({hash: SHA-256, modulusLength: 2048, name: RSA, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Pass	Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [decrypt])	
+Pass	Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt])	
+Pass	Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [decrypt])	
+Pass	Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [decrypt])	
+Pass	Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign, decrypt])	
+Pass	Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign, decrypt])	
+Pass	Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [sign, decrypt])	
+Pass	Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [sign, decrypt])	
+Pass	Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits, sign, decrypt])	
+Pass	Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits, sign, decrypt])	
+Pass	Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits, sign, decrypt])	
+Pass	Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits, sign, decrypt])	
+Pass	Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits, decrypt])	
+Pass	Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits, decrypt])	
+Pass	Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits, decrypt])	
+Pass	Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits, decrypt])	
+Pass	Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [sign])	
+Pass	Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [sign])	
+Pass	Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [sign])	
+Pass	Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [sign])	
+Pass	Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits, sign])	
+Pass	Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits, sign])	
+Pass	Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits, sign])	
+Pass	Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits, sign])	
+Pass	Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [deriveBits])	
+Pass	Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [deriveBits])	
+Pass	Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [deriveBits])	
+Pass	Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [deriveBits])	
+Pass	Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [])	
+Pass	Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [])	
+Pass	Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [])	
+Pass	Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [])	
+Pass	Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Pass	Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Pass	Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Pass	Bad algorithm: generateKey({hash: SHA, modulusLength: 2048, name: RSA-PSS, publicExponent: {0: 1, 1: 0, 2: 1}}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Pass	Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [decrypt])	
+Pass	Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [decrypt])	
+Pass	Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [decrypt])	
+Pass	Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [decrypt])	
+Pass	Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [sign, decrypt])	
+Pass	Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [sign, decrypt])	
+Pass	Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [sign, decrypt])	
+Pass	Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [sign, decrypt])	
+Pass	Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [deriveBits, sign, decrypt])	
+Pass	Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [deriveBits, sign, decrypt])	
+Pass	Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [deriveBits, sign, decrypt])	
+Pass	Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [deriveBits, sign, decrypt])	
+Pass	Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [deriveBits, decrypt])	
+Pass	Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [deriveBits, decrypt])	
+Pass	Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [deriveBits, decrypt])	
+Pass	Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [deriveBits, decrypt])	
+Pass	Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [sign])	
+Pass	Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [sign])	
+Pass	Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [sign])	
+Pass	Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [sign])	
+Pass	Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [deriveBits, sign])	
+Pass	Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [deriveBits, sign])	
+Pass	Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [deriveBits, sign])	
+Pass	Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [deriveBits, sign])	
+Pass	Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [deriveBits])	
+Pass	Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [deriveBits])	
+Pass	Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [deriveBits])	
+Pass	Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [deriveBits])	
+Pass	Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [])	
+Pass	Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [])	
+Pass	Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [])	
+Pass	Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [])	
+Pass	Bad algorithm: generateKey({name: EC, namedCurve: P521}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Pass	Bad algorithm: generateKey({name: EC, namedCurve: P521}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Pass	Bad algorithm: generateKey({name: EC, namedCurve: P521}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Pass	Bad algorithm: generateKey({name: EC, namedCurve: P521}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Fail	Empty algorithm: generateKey({}, false, [decrypt])	
+Fail	Empty algorithm: generateKey({}, true, [decrypt])	
+Fail	Empty algorithm: generateKey({}, RED, [decrypt])	
+Fail	Empty algorithm: generateKey({}, 7, [decrypt])	
+Fail	Empty algorithm: generateKey({}, false, [sign, decrypt])	
+Fail	Empty algorithm: generateKey({}, true, [sign, decrypt])	
+Fail	Empty algorithm: generateKey({}, RED, [sign, decrypt])	
+Fail	Empty algorithm: generateKey({}, 7, [sign, decrypt])	
+Fail	Empty algorithm: generateKey({}, false, [deriveBits, sign, decrypt])	
+Fail	Empty algorithm: generateKey({}, true, [deriveBits, sign, decrypt])	
+Fail	Empty algorithm: generateKey({}, RED, [deriveBits, sign, decrypt])	
+Fail	Empty algorithm: generateKey({}, 7, [deriveBits, sign, decrypt])	
+Fail	Empty algorithm: generateKey({}, false, [deriveBits, decrypt])	
+Fail	Empty algorithm: generateKey({}, true, [deriveBits, decrypt])	
+Fail	Empty algorithm: generateKey({}, RED, [deriveBits, decrypt])	
+Fail	Empty algorithm: generateKey({}, 7, [deriveBits, decrypt])	
+Fail	Empty algorithm: generateKey({}, false, [sign])	
+Fail	Empty algorithm: generateKey({}, true, [sign])	
+Fail	Empty algorithm: generateKey({}, RED, [sign])	
+Fail	Empty algorithm: generateKey({}, 7, [sign])	
+Fail	Empty algorithm: generateKey({}, false, [deriveBits, sign])	
+Fail	Empty algorithm: generateKey({}, true, [deriveBits, sign])	
+Fail	Empty algorithm: generateKey({}, RED, [deriveBits, sign])	
+Fail	Empty algorithm: generateKey({}, 7, [deriveBits, sign])	
+Fail	Empty algorithm: generateKey({}, false, [deriveBits])	
+Fail	Empty algorithm: generateKey({}, true, [deriveBits])	
+Fail	Empty algorithm: generateKey({}, RED, [deriveBits])	
+Fail	Empty algorithm: generateKey({}, 7, [deriveBits])	
+Fail	Empty algorithm: generateKey({}, false, [])	
+Fail	Empty algorithm: generateKey({}, true, [])	
+Fail	Empty algorithm: generateKey({}, RED, [])	
+Fail	Empty algorithm: generateKey({}, 7, [])	
+Fail	Empty algorithm: generateKey({}, false, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Fail	Empty algorithm: generateKey({}, true, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Fail	Empty algorithm: generateKey({}, RED, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Fail	Empty algorithm: generateKey({}, 7, [decrypt, sign, deriveBits, decrypt, sign, deriveBits])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [encrypt])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey, encrypt])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits, deriveKey, encrypt])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits, encrypt])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, encrypt])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [decrypt])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey, decrypt])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits, deriveKey, decrypt])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits, decrypt])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, decrypt])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [sign])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey, sign])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits, deriveKey, sign])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits, sign])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, sign])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [verify])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey, verify])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits, deriveKey, verify])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits, verify])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, verify])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [wrapKey])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey, wrapKey])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits, deriveKey, wrapKey])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits, wrapKey])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, wrapKey])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [unwrapKey])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey, unwrapKey])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits, deriveKey, unwrapKey])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits, unwrapKey])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, unwrapKey])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [encrypt])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey, encrypt])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits, deriveKey, encrypt])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits, encrypt])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, encrypt])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [decrypt])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey, decrypt])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits, deriveKey, decrypt])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits, decrypt])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, decrypt])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [sign])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey, sign])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits, deriveKey, sign])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits, sign])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, sign])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [verify])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey, verify])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits, deriveKey, verify])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits, verify])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, verify])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [wrapKey])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey, wrapKey])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits, deriveKey, wrapKey])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits, wrapKey])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, wrapKey])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [unwrapKey])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey, unwrapKey])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits, deriveKey, unwrapKey])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits, unwrapKey])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, unwrapKey])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [encrypt])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, encrypt])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, deriveKey, encrypt])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, encrypt])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, encrypt])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [decrypt])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, decrypt])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, deriveKey, decrypt])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, decrypt])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, decrypt])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [sign])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, sign])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, deriveKey, sign])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, sign])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, sign])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [verify])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, verify])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, deriveKey, verify])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, verify])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, verify])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [wrapKey])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, wrapKey])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, deriveKey, wrapKey])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, wrapKey])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, wrapKey])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [unwrapKey])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, unwrapKey])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, deriveKey, unwrapKey])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, unwrapKey])	
+Pass	Bad usages: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, unwrapKey])	
+Pass	Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, false, [deriveKey])	
+Pass	Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, true, [deriveKey])	
+Pass	Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, false, [deriveBits, deriveKey])	
+Pass	Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, true, [deriveBits, deriveKey])	
+Pass	Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, false, [deriveBits])	
+Pass	Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, true, [deriveBits])	
+Pass	Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, false, [])	
+Pass	Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, true, [])	
+Pass	Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, false, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])	
+Pass	Bad algorithm property: generateKey({name: ECDH, namedCurve: P-512}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])	
+Pass	Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, false, [deriveKey])	
+Pass	Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, true, [deriveKey])	
+Pass	Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, false, [deriveBits, deriveKey])	
+Pass	Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, true, [deriveBits, deriveKey])	
+Pass	Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, false, [deriveBits])	
+Pass	Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, true, [deriveBits])	
+Pass	Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, false, [])	
+Pass	Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, true, [])	
+Pass	Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, false, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])	
+Pass	Bad algorithm property: generateKey({name: ECDH, namedCurve: Curve25519}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])	
+Pass	Empty usages: generateKey({name: ECDH, namedCurve: P-256}, false, [])	
+Pass	Empty usages: generateKey({name: ECDH, namedCurve: P-256}, true, [])	
+Pass	Empty usages: generateKey({name: ECDH, namedCurve: P-384}, false, [])	
+Pass	Empty usages: generateKey({name: ECDH, namedCurve: P-384}, true, [])	
+Fail	Empty usages: generateKey({name: ECDH, namedCurve: P-521}, false, [])	
+Fail	Empty usages: generateKey({name: ECDH, namedCurve: P-521}, true, [])	

+ 82 - 0
Tests/LibWeb/Text/expected/wpt-import/WebCryptoAPI/generateKey/successes_ECDH.https.any.txt

@@ -0,0 +1,82 @@
+Summary
+
+Harness status: OK
+
+Rerun
+
+Found 72 tests
+
+72 Fail
+Details
+Result	Test Name	MessageFail	Success: generateKey({name: ECDH, namedCurve: P-256}, false, [deriveKey])	
+Fail	Success: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey])	
+Fail	Success: generateKey({name: ECDH, namedCurve: P-256}, false, [deriveBits, deriveKey])	
+Fail	Success: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits, deriveKey])	
+Fail	Success: generateKey({name: ECDH, namedCurve: P-256}, false, [deriveBits])	
+Fail	Success: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveBits])	
+Fail	Success: generateKey({name: ECDH, namedCurve: P-256}, false, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])	
+Fail	Success: generateKey({name: ECDH, namedCurve: P-256}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])	
+Fail	Success: generateKey({name: ECDH, namedCurve: P-384}, false, [deriveKey])	
+Fail	Success: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey])	
+Fail	Success: generateKey({name: ECDH, namedCurve: P-384}, false, [deriveBits, deriveKey])	
+Fail	Success: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits, deriveKey])	
+Fail	Success: generateKey({name: ECDH, namedCurve: P-384}, false, [deriveBits])	
+Fail	Success: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveBits])	
+Fail	Success: generateKey({name: ECDH, namedCurve: P-384}, false, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])	
+Fail	Success: generateKey({name: ECDH, namedCurve: P-384}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])	
+Fail	Success: generateKey({name: ECDH, namedCurve: P-521}, false, [deriveKey])	
+Fail	Success: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey])	
+Fail	Success: generateKey({name: ECDH, namedCurve: P-521}, false, [deriveBits, deriveKey])	
+Fail	Success: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits, deriveKey])	
+Fail	Success: generateKey({name: ECDH, namedCurve: P-521}, false, [deriveBits])	
+Fail	Success: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveBits])	
+Fail	Success: generateKey({name: ECDH, namedCurve: P-521}, false, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])	
+Fail	Success: generateKey({name: ECDH, namedCurve: P-521}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])	
+Fail	Success: generateKey({name: ecdh, namedCurve: P-256}, false, [deriveKey])	
+Fail	Success: generateKey({name: ecdh, namedCurve: P-256}, true, [deriveKey])	
+Fail	Success: generateKey({name: ecdh, namedCurve: P-256}, false, [deriveBits, deriveKey])	
+Fail	Success: generateKey({name: ecdh, namedCurve: P-256}, true, [deriveBits, deriveKey])	
+Fail	Success: generateKey({name: ecdh, namedCurve: P-256}, false, [deriveBits])	
+Fail	Success: generateKey({name: ecdh, namedCurve: P-256}, true, [deriveBits])	
+Fail	Success: generateKey({name: ecdh, namedCurve: P-256}, false, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])	
+Fail	Success: generateKey({name: ecdh, namedCurve: P-256}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])	
+Fail	Success: generateKey({name: ecdh, namedCurve: P-384}, false, [deriveKey])	
+Fail	Success: generateKey({name: ecdh, namedCurve: P-384}, true, [deriveKey])	
+Fail	Success: generateKey({name: ecdh, namedCurve: P-384}, false, [deriveBits, deriveKey])	
+Fail	Success: generateKey({name: ecdh, namedCurve: P-384}, true, [deriveBits, deriveKey])	
+Fail	Success: generateKey({name: ecdh, namedCurve: P-384}, false, [deriveBits])	
+Fail	Success: generateKey({name: ecdh, namedCurve: P-384}, true, [deriveBits])	
+Fail	Success: generateKey({name: ecdh, namedCurve: P-384}, false, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])	
+Fail	Success: generateKey({name: ecdh, namedCurve: P-384}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])	
+Fail	Success: generateKey({name: ecdh, namedCurve: P-521}, false, [deriveKey])	
+Fail	Success: generateKey({name: ecdh, namedCurve: P-521}, true, [deriveKey])	
+Fail	Success: generateKey({name: ecdh, namedCurve: P-521}, false, [deriveBits, deriveKey])	
+Fail	Success: generateKey({name: ecdh, namedCurve: P-521}, true, [deriveBits, deriveKey])	
+Fail	Success: generateKey({name: ecdh, namedCurve: P-521}, false, [deriveBits])	
+Fail	Success: generateKey({name: ecdh, namedCurve: P-521}, true, [deriveBits])	
+Fail	Success: generateKey({name: ecdh, namedCurve: P-521}, false, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])	
+Fail	Success: generateKey({name: ecdh, namedCurve: P-521}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])	
+Fail	Success: generateKey({name: Ecdh, namedCurve: P-256}, false, [deriveKey])	
+Fail	Success: generateKey({name: Ecdh, namedCurve: P-256}, true, [deriveKey])	
+Fail	Success: generateKey({name: Ecdh, namedCurve: P-256}, false, [deriveBits, deriveKey])	
+Fail	Success: generateKey({name: Ecdh, namedCurve: P-256}, true, [deriveBits, deriveKey])	
+Fail	Success: generateKey({name: Ecdh, namedCurve: P-256}, false, [deriveBits])	
+Fail	Success: generateKey({name: Ecdh, namedCurve: P-256}, true, [deriveBits])	
+Fail	Success: generateKey({name: Ecdh, namedCurve: P-256}, false, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])	
+Fail	Success: generateKey({name: Ecdh, namedCurve: P-256}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])	
+Fail	Success: generateKey({name: Ecdh, namedCurve: P-384}, false, [deriveKey])	
+Fail	Success: generateKey({name: Ecdh, namedCurve: P-384}, true, [deriveKey])	
+Fail	Success: generateKey({name: Ecdh, namedCurve: P-384}, false, [deriveBits, deriveKey])	
+Fail	Success: generateKey({name: Ecdh, namedCurve: P-384}, true, [deriveBits, deriveKey])	
+Fail	Success: generateKey({name: Ecdh, namedCurve: P-384}, false, [deriveBits])	
+Fail	Success: generateKey({name: Ecdh, namedCurve: P-384}, true, [deriveBits])	
+Fail	Success: generateKey({name: Ecdh, namedCurve: P-384}, false, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])	
+Fail	Success: generateKey({name: Ecdh, namedCurve: P-384}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])	
+Fail	Success: generateKey({name: Ecdh, namedCurve: P-521}, false, [deriveKey])	
+Fail	Success: generateKey({name: Ecdh, namedCurve: P-521}, true, [deriveKey])	
+Fail	Success: generateKey({name: Ecdh, namedCurve: P-521}, false, [deriveBits, deriveKey])	
+Fail	Success: generateKey({name: Ecdh, namedCurve: P-521}, true, [deriveBits, deriveKey])	
+Fail	Success: generateKey({name: Ecdh, namedCurve: P-521}, false, [deriveBits])	
+Fail	Success: generateKey({name: Ecdh, namedCurve: P-521}, true, [deriveBits])	
+Fail	Success: generateKey({name: Ecdh, namedCurve: P-521}, false, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])	
+Fail	Success: generateKey({name: Ecdh, namedCurve: P-521}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits])	

+ 228 - 0
Tests/LibWeb/Text/input/wpt-import/WebCryptoAPI/generateKey/failures.js

@@ -0,0 +1,228 @@
+function run_test(algorithmNames) {
+    var subtle = crypto.subtle; // Change to test prefixed implementations
+
+    setup({explicit_timeout: true});
+
+// These tests check that generateKey throws an error, and that
+// the error is of the right type, for a wide set of incorrect parameters.
+//
+// Error testing occurs by setting the parameter that should trigger the
+// error to an invalid value, then combining that with all valid
+// parameters that should be checked earlier by generateKey, and all
+// valid and invalid parameters that should be checked later by
+// generateKey.
+//
+// There are a lot of combinations of possible parameters for both
+// success and failure modes, resulting in a very large number of tests
+// performed.
+
+
+// Setup: define the correct behaviors that should be sought, and create
+// helper functions that generate all possible test parameters for
+// different situations.
+
+    var allTestVectors = [ // Parameters that should work for generateKey
+        {name: "AES-CTR",  resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []},
+        {name: "AES-CBC",  resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []},
+        {name: "AES-GCM",  resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []},
+        {name: "AES-KW",   resultType: CryptoKey, usages: ["wrapKey", "unwrapKey"], mandatoryUsages: []},
+        {name: "HMAC",     resultType: CryptoKey, usages: ["sign", "verify"], mandatoryUsages: []},
+        {name: "RSASSA-PKCS1-v1_5", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
+        {name: "RSA-PSS",  resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
+        {name: "RSA-OAEP", resultType: "CryptoKeyPair", usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: ["decrypt", "unwrapKey"]},
+        {name: "ECDSA",    resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
+        {name: "ECDH",     resultType: "CryptoKeyPair", usages: ["deriveKey", "deriveBits"], mandatoryUsages: ["deriveKey", "deriveBits"]},
+        {name: "Ed25519",  resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
+        {name: "Ed448",    resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
+        {name: "X25519",   resultType: "CryptoKeyPair", usages: ["deriveKey", "deriveBits"], mandatoryUsages: ["deriveKey", "deriveBits"]},
+        {name: "X448",     resultType: "CryptoKeyPair", usages: ["deriveKey", "deriveBits"], mandatoryUsages: ["deriveKey", "deriveBits"]},
+    ];
+
+    var testVectors = [];
+    if (algorithmNames && !Array.isArray(algorithmNames)) {
+        algorithmNames = [algorithmNames];
+    };
+    allTestVectors.forEach(function(vector) {
+        if (!algorithmNames || algorithmNames.includes(vector.name)) {
+            testVectors.push(vector);
+        }
+    });
+
+
+    function parameterString(algorithm, extractable, usages) {
+        if (typeof algorithm !== "object" && typeof algorithm !== "string") {
+            alert(algorithm);
+        }
+
+        var result = "(" +
+                        objectToString(algorithm) + ", " +
+                        objectToString(extractable) + ", " +
+                        objectToString(usages) +
+                     ")";
+
+        return result;
+    }
+
+    // Test that a given combination of parameters results in an error,
+    // AND that it is the correct kind of error.
+    //
+    // Expected error is either a number, tested against the error code,
+    // or a string, tested against the error name.
+    function testError(algorithm, extractable, usages, expectedError, testTag) {
+        promise_test(function(test) {
+            return crypto.subtle.generateKey(algorithm, extractable, usages)
+            .then(function(result) {
+                assert_unreached("Operation succeeded, but should not have");
+            }, function(err) {
+                if (typeof expectedError === "number") {
+                    assert_equals(err.code, expectedError, testTag + " not supported");
+                } else {
+                    assert_equals(err.name, expectedError, testTag + " not supported");
+                }
+            });
+        }, testTag + ": generateKey" + parameterString(algorithm, extractable, usages));
+    }
+
+
+    // Given an algorithm name, create several invalid parameters.
+    function badAlgorithmPropertySpecifiersFor(algorithmName) {
+        var results = [];
+
+        if (algorithmName.toUpperCase().substring(0, 3) === "AES") {
+            // Specifier properties are name and length
+            [64, 127, 129, 255, 257, 512].forEach(function(length) {
+                results.push({name: algorithmName, length: length});
+            });
+        } else if (algorithmName.toUpperCase().substring(0, 3) === "RSA") {
+            [new Uint8Array([1]), new Uint8Array([1,0,0])].forEach(function(publicExponent) {
+                results.push({name: algorithmName, hash: "SHA-256", modulusLength: 1024, publicExponent: publicExponent});
+            });
+        } else if (algorithmName.toUpperCase().substring(0, 2) === "EC") {
+            ["P-512", "Curve25519"].forEach(function(curveName) {
+                results.push({name: algorithmName, namedCurve: curveName});
+            });
+        }
+
+        return results;
+    }
+
+
+    // Don't create an exhaustive list of all invalid usages,
+    // because there would usually be nearly 2**8 of them,
+    // way too many to test. Instead, create every singleton
+    // of an illegal usage, and "poison" every valid usage
+    // with an illegal one.
+    function invalidUsages(validUsages, mandatoryUsages) {
+        var results = [];
+
+        var illegalUsages = [];
+        ["encrypt", "decrypt", "sign", "verify", "wrapKey", "unwrapKey", "deriveKey", "deriveBits"].forEach(function(usage) {
+            if (!validUsages.includes(usage)) {
+                illegalUsages.push(usage);
+            }
+        });
+
+        var goodUsageCombinations = allValidUsages(validUsages, false, mandatoryUsages);
+
+        illegalUsages.forEach(function(illegalUsage) {
+            results.push([illegalUsage]);
+            goodUsageCombinations.forEach(function(usageCombination) {
+                results.push(usageCombination.concat([illegalUsage]));
+            });
+        });
+
+        return results;
+    }
+
+
+// Now test for properly handling errors
+// - Unsupported algorithm
+// - Bad usages for algorithm
+// - Bad key lengths
+
+    // Algorithm normalization should fail with "Not supported"
+    var badAlgorithmNames = [
+        "AES",
+        {name: "AES"},
+        {name: "AES", length: 128},
+        {name: "AES-CMAC", length: 128},    // Removed after CR
+        {name: "AES-CFB", length: 128},      // Removed after CR
+        {name: "HMAC", hash: "MD5"},
+        {name: "RSA", hash: "SHA-256", modulusLength: 2048, publicExponent: new Uint8Array([1,0,1])},
+        {name: "RSA-PSS", hash: "SHA", modulusLength: 2048, publicExponent: new Uint8Array([1,0,1])},
+        {name: "EC", namedCurve: "P521"}
+    ];
+
+
+    // Algorithm normalization failures should be found first
+    // - all other parameters can be good or bad, should fail
+    //   due to NotSupportedError.
+    badAlgorithmNames.forEach(function(algorithm) {
+        allValidUsages(["decrypt", "sign", "deriveBits"], true, []) // Small search space, shouldn't matter because should fail before used
+        .forEach(function(usages) {
+            [false, true, "RED", 7].forEach(function(extractable){
+                testError(algorithm, extractable, usages, "NotSupportedError", "Bad algorithm");
+            });
+        });
+    });
+
+    // Empty algorithm should fail with TypeError
+    allValidUsages(["decrypt", "sign", "deriveBits"], true, []) // Small search space, shouldn't matter because should fail before used
+        .forEach(function(usages) {
+            [false, true, "RED", 7].forEach(function(extractable){
+                testError({}, extractable, usages, "TypeError", "Empty algorithm");
+            });
+        });
+
+
+    // Algorithms normalize okay, but usages bad (though not empty).
+    // It shouldn't matter what other extractable is. Should fail
+    // due to SyntaxError
+    testVectors.forEach(function(vector) {
+        var name = vector.name;
+
+        allAlgorithmSpecifiersFor(name).forEach(function(algorithm) {
+            invalidUsages(vector.usages, vector.mandatoryUsages).forEach(function(usages) {
+                [true].forEach(function(extractable) {
+                    testError(algorithm, extractable, usages, "SyntaxError", "Bad usages");
+                });
+            });
+        });
+    });
+
+
+    // Other algorithm properties should be checked next, so try good
+    // algorithm names and usages, but bad algorithm properties next.
+    // - Special case: normally bad usage [] isn't checked until after properties,
+    //   so it's included in this test case. It should NOT cause an error.
+    testVectors.forEach(function(vector) {
+        var name = vector.name;
+        badAlgorithmPropertySpecifiersFor(name).forEach(function(algorithm) {
+            allValidUsages(vector.usages, true, vector.mandatoryUsages)
+            .forEach(function(usages) {
+                [false, true].forEach(function(extractable) {
+                    if (name.substring(0,2) === "EC") {
+                        testError(algorithm, extractable, usages, "NotSupportedError", "Bad algorithm property");
+                    } else {
+                        testError(algorithm, extractable, usages, "OperationError", "Bad algorithm property");
+                    }
+                });
+            });
+        });
+    });
+
+
+    // The last thing that should be checked is empty usages (disallowed for secret and private keys).
+    testVectors.forEach(function(vector) {
+        var name = vector.name;
+
+        allAlgorithmSpecifiersFor(name).forEach(function(algorithm) {
+            var usages = [];
+            [false, true].forEach(function(extractable) {
+                testError(algorithm, extractable, usages, "SyntaxError", "Empty usages");
+            });
+        });
+    });
+
+
+}

+ 17 - 0
Tests/LibWeb/Text/input/wpt-import/WebCryptoAPI/generateKey/failures_ECDH.https.any.html

@@ -0,0 +1,17 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>WebCryptoAPI: generateKey() for Failures</title>
+<meta name="timeout" content="long">
+<script>
+self.GLOBAL = {
+  isWindow: function() { return true; },
+  isWorker: function() { return false; },
+  isShadowRealm: function() { return false; },
+};
+</script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../util/helpers.js"></script>
+<script src="failures.js"></script>
+<div id=log></div>
+<script src="../../WebCryptoAPI/generateKey/failures_ECDH.https.any.js"></script>

+ 5 - 0
Tests/LibWeb/Text/input/wpt-import/WebCryptoAPI/generateKey/failures_ECDH.https.any.js

@@ -0,0 +1,5 @@
+// META: title=WebCryptoAPI: generateKey() for Failures
+// META: timeout=long
+// META: script=../util/helpers.js
+// META: script=failures.js
+run_test(["ECDH"]);

+ 115 - 0
Tests/LibWeb/Text/input/wpt-import/WebCryptoAPI/generateKey/successes.js

@@ -0,0 +1,115 @@
+
+function run_test(algorithmNames, slowTest) {
+    var subtle = crypto.subtle; // Change to test prefixed implementations
+
+    setup({explicit_timeout: true});
+
+// These tests check that generateKey successfully creates keys
+// when provided any of a wide set of correct parameters
+// and that they can be exported afterwards.
+//
+// There are a lot of combinations of possible parameters,
+// resulting in a very large number of tests
+// performed.
+
+
+// Setup: define the correct behaviors that should be sought, and create
+// helper functions that generate all possible test parameters for
+// different situations.
+
+    var allTestVectors = [ // Parameters that should work for generateKey
+        {name: "AES-CTR",  resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []},
+        {name: "AES-CBC",  resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []},
+        {name: "AES-GCM",  resultType: CryptoKey, usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: []},
+        {name: "AES-KW",   resultType: CryptoKey, usages: ["wrapKey", "unwrapKey"], mandatoryUsages: []},
+        {name: "HMAC",     resultType: CryptoKey, usages: ["sign", "verify"], mandatoryUsages: []},
+        {name: "RSASSA-PKCS1-v1_5", resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
+        {name: "RSA-PSS",  resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
+        {name: "RSA-OAEP", resultType: "CryptoKeyPair", usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"], mandatoryUsages: ["decrypt", "unwrapKey"]},
+        {name: "ECDSA",    resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
+        {name: "ECDH",     resultType: "CryptoKeyPair", usages: ["deriveKey", "deriveBits"], mandatoryUsages: ["deriveKey", "deriveBits"]},
+        {name: "Ed25519",  resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
+        {name: "Ed448",    resultType: "CryptoKeyPair", usages: ["sign", "verify"], mandatoryUsages: ["sign"]},
+        {name: "X25519",   resultType: "CryptoKeyPair", usages: ["deriveKey", "deriveBits"], mandatoryUsages: ["deriveKey", "deriveBits"]},
+        {name: "X448",     resultType: "CryptoKeyPair", usages: ["deriveKey", "deriveBits"], mandatoryUsages: ["deriveKey", "deriveBits"]},
+    ];
+
+    var testVectors = [];
+    if (algorithmNames && !Array.isArray(algorithmNames)) {
+        algorithmNames = [algorithmNames];
+    };
+    allTestVectors.forEach(function(vector) {
+        if (!algorithmNames || algorithmNames.includes(vector.name)) {
+            testVectors.push(vector);
+        }
+    });
+
+    function parameterString(algorithm, extractable, usages) {
+        var result = "(" +
+                        objectToString(algorithm) + ", " +
+                        objectToString(extractable) + ", " +
+                        objectToString(usages) +
+                     ")";
+
+        return result;
+    }
+
+    // Test that a given combination of parameters is successful
+    function testSuccess(algorithm, extractable, usages, resultType, testTag) {
+        // algorithm, extractable, and usages are the generateKey parameters
+        // resultType is the expected result, either the CryptoKey object or "CryptoKeyPair"
+        // testTag is a string to prepend to the test name.
+
+        promise_test(function(test) {
+            return subtle.generateKey(algorithm, extractable, usages)
+            .then(function(result) {
+                if (resultType === "CryptoKeyPair") {
+                    assert_goodCryptoKey(result.privateKey, algorithm, extractable, usages, "private");
+                    assert_goodCryptoKey(result.publicKey, algorithm, true, usages, "public");
+                } else {
+                    assert_goodCryptoKey(result, algorithm, extractable, usages, "secret");
+                }
+                return result;
+            }, function(err) {
+                assert_unreached("generateKey threw an unexpected error: " + err.toString());
+            })
+            .then(async function (result) {
+                if (resultType === "CryptoKeyPair") {
+                    await Promise.all([
+                        subtle.exportKey('jwk', result.publicKey),
+                        subtle.exportKey('spki', result.publicKey),
+                        result.publicKey.algorithm.name.startsWith('RSA') ? undefined : subtle.exportKey('raw', result.publicKey),
+                        ...(extractable ? [
+                            subtle.exportKey('jwk', result.privateKey),
+                            subtle.exportKey('pkcs8', result.privateKey),
+                        ] : [])
+                    ]);
+                } else {
+                    if (extractable) {
+                        await Promise.all([
+                            subtle.exportKey('raw', result),
+                            subtle.exportKey('jwk', result),
+                        ]);
+                    }
+                }
+            }, function(err) {
+                assert_unreached("exportKey threw an unexpected error: " + err.toString());
+            })
+        }, testTag + ": generateKey" + parameterString(algorithm, extractable, usages));
+    }
+
+    // Test all valid sets of parameters for successful
+    // key generation.
+    testVectors.forEach(function(vector) {
+        allNameVariants(vector.name, slowTest).forEach(function(name) {
+            allAlgorithmSpecifiersFor(name).forEach(function(algorithm) {
+                allValidUsages(vector.usages, false, vector.mandatoryUsages).forEach(function(usages) {
+                    [false, true].forEach(function(extractable) {
+                        subsetTest(testSuccess, algorithm, extractable, usages, vector.resultType, "Success");
+                    });
+                });
+            });
+        });
+    });
+
+}

+ 18 - 0
Tests/LibWeb/Text/input/wpt-import/WebCryptoAPI/generateKey/successes_ECDH.https.any.html

@@ -0,0 +1,18 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>WebCryptoAPI: generateKey() Successful Calls</title>
+<meta name="timeout" content="long">
+<script>
+self.GLOBAL = {
+  isWindow: function() { return true; },
+  isWorker: function() { return false; },
+  isShadowRealm: function() { return false; },
+};
+</script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../util/helpers.js"></script>
+<script src="../../common/subset-tests.js"></script>
+<script src="successes.js"></script>
+<div id=log></div>
+<script src="../../WebCryptoAPI/generateKey/successes_ECDH.https.any.js"></script>

+ 6 - 0
Tests/LibWeb/Text/input/wpt-import/WebCryptoAPI/generateKey/successes_ECDH.https.any.js

@@ -0,0 +1,6 @@
+// META: title=WebCryptoAPI: generateKey() Successful Calls
+// META: timeout=long
+// META: script=../util/helpers.js
+// META: script=/common/subset-tests.js
+// META: script=successes.js
+run_test(["ECDH"]);

+ 299 - 0
Tests/LibWeb/Text/input/wpt-import/WebCryptoAPI/util/helpers.js

@@ -0,0 +1,299 @@
+//
+// helpers.js
+//
+// Helper functions used by several WebCryptoAPI tests
+//
+
+var registeredAlgorithmNames = [
+    "RSASSA-PKCS1-v1_5",
+    "RSA-PSS",
+    "RSA-OAEP",
+    "ECDSA",
+    "ECDH",
+    "AES-CTR",
+    "AES-CBC",
+    "AES-GCM",
+    "AES-KW",
+    "HMAC",
+    "SHA-1",
+    "SHA-256",
+    "SHA-384",
+    "SHA-512",
+    "HKDF",
+    "PBKDF2",
+    "Ed25519",
+    "Ed448",
+    "X25519",
+    "X448"
+];
+
+
+// Treats an array as a set, and generates an array of all non-empty
+// subsets (which are themselves arrays).
+//
+// The order of members of the "subsets" is not guaranteed.
+function allNonemptySubsetsOf(arr) {
+    var results = [];
+    var firstElement;
+    var remainingElements;
+
+    for(var i=0; i<arr.length; i++) {
+        firstElement = arr[i];
+        remainingElements = arr.slice(i+1);
+        results.push([firstElement]);
+
+        if (remainingElements.length > 0) {
+            allNonemptySubsetsOf(remainingElements).forEach(function(combination) {
+                combination.push(firstElement);
+                results.push(combination);
+            });
+        }
+    }
+
+    return results;
+}
+
+
+// Create a string representation of keyGeneration parameters for
+// test names and labels.
+function objectToString(obj) {
+    var keyValuePairs = [];
+
+    if (Array.isArray(obj)) {
+        return "[" + obj.map(function(elem){return objectToString(elem);}).join(", ") + "]";
+    } else if (typeof obj === "object") {
+        Object.keys(obj).sort().forEach(function(keyName) {
+            keyValuePairs.push(keyName + ": " + objectToString(obj[keyName]));
+        });
+        return "{" + keyValuePairs.join(", ") + "}";
+    } else if (typeof obj === "undefined") {
+        return "undefined";
+    } else {
+        return obj.toString();
+    }
+
+    var keyValuePairs = [];
+
+    Object.keys(obj).sort().forEach(function(keyName) {
+        var value = obj[keyName];
+        if (typeof value === "object") {
+            value = objectToString(value);
+        } else if (typeof value === "array") {
+            value = "[" + value.map(function(elem){return objectToString(elem);}).join(", ") + "]";
+        } else {
+            value = value.toString();
+        }
+
+        keyValuePairs.push(keyName + ": " + value);
+    });
+
+    return "{" + keyValuePairs.join(", ") + "}";
+}
+
+// Is key a CryptoKey object with correct algorithm, extractable, and usages?
+// Is it a secret, private, or public kind of key?
+function assert_goodCryptoKey(key, algorithm, extractable, usages, kind) {
+    var correctUsages = [];
+
+    var registeredAlgorithmName;
+    registeredAlgorithmNames.forEach(function(name) {
+        if (name.toUpperCase() === algorithm.name.toUpperCase()) {
+            registeredAlgorithmName = name;
+        }
+    });
+
+    assert_equals(key.constructor, CryptoKey, "Is a CryptoKey");
+    assert_equals(key.type, kind, "Is a " + kind + " key");
+    assert_equals(key.extractable, extractable, "Extractability is correct");
+
+    assert_equals(key.algorithm.name, registeredAlgorithmName, "Correct algorithm name");
+    if (key.algorithm.name.toUpperCase() === "HMAC" && algorithm.length === undefined) {
+        switch (key.algorithm.hash.name.toUpperCase()) {
+            case 'SHA-1':
+            case 'SHA-256':
+                assert_equals(key.algorithm.length, 512, "Correct length");
+                break;
+            case 'SHA-384':
+            case 'SHA-512':
+                assert_equals(key.algorithm.length, 1024, "Correct length");
+                break;
+            default:
+                assert_unreached("Unrecognized hash");
+        }
+    } else {
+        assert_equals(key.algorithm.length, algorithm.length, "Correct length");
+    }
+    if (["HMAC", "RSASSA-PKCS1-v1_5", "RSA-PSS"].includes(registeredAlgorithmName)) {
+        assert_equals(key.algorithm.hash.name.toUpperCase(), algorithm.hash.toUpperCase(), "Correct hash function");
+    }
+
+    if (/^(?:Ed|X)(?:25519|448)$/.test(key.algorithm.name)) {
+        assert_false('namedCurve' in key.algorithm, "Does not have a namedCurve property");
+    }
+
+    // usages is expected to be provided for a key pair, but we are checking
+    // only a single key. The publicKey and privateKey portions of a key pair
+    // recognize only some of the usages appropriate for a key pair.
+    if (key.type === "public") {
+        ["encrypt", "verify", "wrapKey"].forEach(function(usage) {
+            if (usages.includes(usage)) {
+                correctUsages.push(usage);
+            }
+        });
+    } else if (key.type === "private") {
+        ["decrypt", "sign", "unwrapKey", "deriveKey", "deriveBits"].forEach(function(usage) {
+            if (usages.includes(usage)) {
+                correctUsages.push(usage);
+            }
+        });
+    } else {
+        correctUsages = usages;
+    }
+
+    assert_equals((typeof key.usages), "object", key.type + " key.usages is an object");
+    assert_not_equals(key.usages, null, key.type + " key.usages isn't null");
+
+    // The usages parameter could have repeats, but the usages
+    // property of the result should not.
+    var usageCount = 0;
+    key.usages.forEach(function(usage) {
+        usageCount += 1;
+        assert_in_array(usage, correctUsages, "Has " + usage + " usage");
+    });
+    assert_equals(key.usages.length, usageCount, "usages property is correct");
+    assert_equals(key[Symbol.toStringTag], 'CryptoKey', "has the expected Symbol.toStringTag");
+}
+
+
+// The algorithm parameter is an object with a name and other
+// properties. Given the name, generate all valid parameters.
+function allAlgorithmSpecifiersFor(algorithmName) {
+    var results = [];
+
+    // RSA key generation is slow. Test a minimal set of parameters
+    var hashes = ["SHA-1", "SHA-256"];
+
+    // EC key generation is a lot faster. Check all curves in the spec
+    var curves = ["P-256", "P-384", "P-521"];
+
+    if (algorithmName.toUpperCase().substring(0, 3) === "AES") {
+        // Specifier properties are name and length
+        [128, 192, 256].forEach(function(length) {
+            results.push({name: algorithmName, length: length});
+        });
+    } else if (algorithmName.toUpperCase() === "HMAC") {
+        [
+            {hash: "SHA-1", length: 160},
+            {hash: "SHA-256", length: 256},
+            {hash: "SHA-384", length: 384},
+            {hash: "SHA-512", length: 512},
+            {hash: "SHA-1"},
+            {hash: "SHA-256"},
+            {hash: "SHA-384"},
+            {hash: "SHA-512"},
+        ].forEach(function(hashAlgorithm) {
+            results.push({name: algorithmName, ...hashAlgorithm});
+        });
+    } else if (algorithmName.toUpperCase().substring(0, 3) === "RSA") {
+        hashes.forEach(function(hashName) {
+            results.push({name: algorithmName, hash: hashName, modulusLength: 2048, publicExponent: new Uint8Array([1,0,1])});
+        });
+    } else if (algorithmName.toUpperCase().substring(0, 2) === "EC") {
+        curves.forEach(function(curveName) {
+            results.push({name: algorithmName, namedCurve: curveName});
+        });
+    } else if (algorithmName.toUpperCase().substring(0, 1) === "X" || algorithmName.toUpperCase().substring(0, 2) === "ED") {
+        results.push({ name: algorithmName });
+    }
+
+    return results;
+}
+
+
+// Create every possible valid usages parameter, given legal
+// usages. Note that an empty usages parameter is not always valid.
+//
+// There is an optional parameter - mandatoryUsages. If provided,
+// it should be an array containing those usages of which one must be
+// included.
+function allValidUsages(validUsages, emptyIsValid, mandatoryUsages) {
+    if (typeof mandatoryUsages === "undefined") {
+        mandatoryUsages = [];
+    }
+
+    var okaySubsets = [];
+    allNonemptySubsetsOf(validUsages).forEach(function(subset) {
+        if (mandatoryUsages.length === 0) {
+            okaySubsets.push(subset);
+        } else {
+            for (var i=0; i<mandatoryUsages.length; i++) {
+                if (subset.includes(mandatoryUsages[i])) {
+                    okaySubsets.push(subset);
+                    return;
+                }
+            }
+        }
+    });
+
+    if (emptyIsValid && validUsages.length !== 0) {
+        okaySubsets.push([]);
+    }
+
+    okaySubsets.push(validUsages.concat(mandatoryUsages).concat(validUsages)); // Repeated values are allowed
+    return okaySubsets;
+}
+
+function unique(names) {
+    return [...new Set(names)];
+}
+
+// Algorithm name specifiers are case-insensitive. Generate several
+// case variations of a given name.
+function allNameVariants(name, slowTest) {
+    var upCaseName = name.toUpperCase();
+    var lowCaseName = name.toLowerCase();
+    var mixedCaseName = upCaseName.substring(0, 1) + lowCaseName.substring(1);
+
+    // for slow tests effectively cut the amount of work in third by only
+    // returning one variation
+    if (slowTest) return [mixedCaseName];
+    return unique([upCaseName, lowCaseName, mixedCaseName]);
+}
+
+// Builds a hex string representation for an array-like input.
+// "bytes" can be an Array of bytes, an ArrayBuffer, or any TypedArray.
+// The output looks like this:
+//    ab034c99
+function bytesToHexString(bytes)
+{
+    if (!bytes)
+        return null;
+
+    bytes = new Uint8Array(bytes);
+    var hexBytes = [];
+
+    for (var i = 0; i < bytes.length; ++i) {
+        var byteString = bytes[i].toString(16);
+        if (byteString.length < 2)
+            byteString = "0" + byteString;
+        hexBytes.push(byteString);
+    }
+
+    return hexBytes.join("");
+}
+
+function hexStringToUint8Array(hexString)
+{
+    if (hexString.length % 2 != 0)
+        throw "Invalid hexString";
+    var arrayBuffer = new Uint8Array(hexString.length / 2);
+
+    for (var i = 0; i < hexString.length; i += 2) {
+        var byteValue = parseInt(hexString.substr(i, 2), 16);
+        if (byteValue == NaN)
+            throw "Invalid hexString";
+        arrayBuffer[i/2] = byteValue;
+    }
+
+    return arrayBuffer;
+}

+ 60 - 0
Tests/LibWeb/Text/input/wpt-import/common/subset-tests.js

@@ -0,0 +1,60 @@
+(function() {
+  var subTestStart = 0;
+  var subTestEnd = Infinity;
+  var match;
+  if (location.search) {
+    match = /(?:^\?|&)(\d+)-(\d+|last)(?:&|$)/.exec(location.search);
+    if (match) {
+      subTestStart = parseInt(match[1], 10);
+      if (match[2] !== "last") {
+          subTestEnd = parseInt(match[2], 10);
+      }
+    }
+    // Below is utility code to generate <meta> for copy/paste into tests.
+    // Sample usage:
+    // test.html?split=1000
+    match = /(?:^\?|&)split=(\d+)(?:&|$)/.exec(location.search);
+    if (match) {
+      var testsPerVariant = parseInt(match[1], 10);
+      add_completion_callback(tests => {
+        var total = tests.length;
+        var template = '<meta name="variant" content="?%s-%s">';
+        var metas = [];
+        for (var i = 1; i < total - testsPerVariant; i = i + testsPerVariant) {
+          metas.push(template.replace("%s", i).replace("%s", i + testsPerVariant - 1));
+        }
+        metas.push(template.replace("%s", i).replace("%s", "last"));
+        var pre = document.createElement('pre');
+        pre.textContent = metas.join('\n');
+        document.body.insertBefore(pre, document.body.firstChild);
+        document.getSelection().selectAllChildren(pre);
+      });
+    }
+  }
+  /**
+   * Check if `currentSubTest` is in the subset specified in the URL.
+   * @param {number} currentSubTest
+   * @returns {boolean}
+   */
+  function shouldRunSubTest(currentSubTest) {
+    return currentSubTest >= subTestStart && currentSubTest <= subTestEnd;
+  }
+  var currentSubTest = 0;
+  /**
+   * Only test a subset of tests with, e.g., `?1-10` in the URL.
+   * Can be used together with `<meta name="variant" content="...">`
+   * Sample usage:
+   * for (const test of tests) {
+   *   subsetTest(async_test, test.fn, test.name);
+   * }
+   */
+  function subsetTest(testFunc, ...args) {
+    currentSubTest++;
+    if (shouldRunSubTest(currentSubTest)) {
+      return testFunc(...args);
+    }
+    return null;
+  }
+  self.shouldRunSubTest = shouldRunSubTest;
+  self.subsetTest = subsetTest;
+})();