diff --git a/Userland/Libraries/LibWeb/Crypto/CryptoAlgorithms.h b/Userland/Libraries/LibWeb/Crypto/CryptoAlgorithms.h index 2ceef18009a..68cbb56596b 100644 --- a/Userland/Libraries/LibWeb/Crypto/CryptoAlgorithms.h +++ b/Userland/Libraries/LibWeb/Crypto/CryptoAlgorithms.h @@ -177,6 +177,11 @@ public: return WebIDL::NotSupportedError::create(m_realm, "digest is not supported"_fly_string); } + virtual WebIDL::ExceptionOr> derive_bits(AlgorithmParams const&, JS::NonnullGCPtr, u32) + { + return WebIDL::NotSupportedError::create(m_realm, "deriveBits is not supported"_fly_string); + } + virtual WebIDL::ExceptionOr> import_key(AlgorithmParams const&, Bindings::KeyFormat, CryptoKey::InternalKeyData, bool, Vector const&) { return WebIDL::NotSupportedError::create(m_realm, "importKey is not supported"_fly_string); diff --git a/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.cpp b/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.cpp index 7f2cf0dd6e6..6dfa986f470 100644 --- a/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.cpp +++ b/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.cpp @@ -584,6 +584,53 @@ JS::ThrowCompletionOr> SubtleCrypto::verify(Algori return verify_cast(*promise->promise()); } +// https://w3c.github.io/webcrypto/#SubtleCrypto-method-deriveBits +JS::ThrowCompletionOr> SubtleCrypto::derive_bits(AlgorithmIdentifier algorithm, JS::NonnullGCPtr base_key, u32 length) +{ + auto& realm = this->realm(); + // 1. Let algorithm, baseKey and length, be the algorithm, baseKey and length parameters passed to the deriveBits() method, respectively. + + // 2. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set to algorithm and op set to "deriveBits". + auto normalized_algorithm = normalize_an_algorithm(realm, algorithm, "deriveBits"_string); + + // 3. If an error occurred, return a Promise rejected with normalizedAlgorithm. + if (normalized_algorithm.is_error()) + return WebIDL::create_rejected_promise_from_exception(realm, normalized_algorithm.release_error()); + + // 4. Let promise be a new Promise object. + auto promise = WebIDL::create_promise(realm); + + // 5. Return promise and perform the remaining steps in parallel. + Platform::EventLoopPlugin::the().deferred_invoke([&realm, normalized_algorithm = normalized_algorithm.release_value(), promise, base_key, length]() -> void { + HTML::TemporaryExecutionContext context(Bindings::host_defined_environment_settings_object(realm), HTML::TemporaryExecutionContext::CallbacksEnabled::Yes); + // 6. If the following steps or referenced procedures say to throw an error, reject promise with the returned error and then terminate the algorithm. + + // 7. If the name member of normalizedAlgorithm is not equal to the name attribute of the [[algorithm]] internal slot of baseKey then throw an InvalidAccessError. + if (normalized_algorithm.parameter->name != base_key->algorithm_name()) { + WebIDL::reject_promise(realm, promise, WebIDL::InvalidAccessError::create(realm, "Algorithm mismatch"_fly_string)); + return; + } + + // 8. If the [[usages]] internal slot of baseKey does not contain an entry that is "deriveBits", then throw an InvalidAccessError. + if (!base_key->internal_usages().contains_slow(Bindings::KeyUsage::Derivebits)) { + WebIDL::reject_promise(realm, promise, WebIDL::InvalidAccessError::create(realm, "Key does not support deriving bits"_fly_string)); + return; + } + + // 9. Let result be the result of creating an ArrayBuffer containing the result of performing the derive bits operation specified by normalizedAlgorithm using baseKey, algorithm and length. + auto result = normalized_algorithm.methods->derive_bits(*normalized_algorithm.parameter, base_key, length); + if (result.is_error()) { + WebIDL::reject_promise(realm, promise, Bindings::dom_exception_to_throw_completion(realm.vm(), result.release_error()).release_value().value()); + return; + } + + // 10. Resolve promise with result. + WebIDL::resolve_promise(realm, promise, result.release_value()); + }); + + return verify_cast(*promise->promise()); +} + SupportedAlgorithmsMap& supported_algorithms_internal() { static SupportedAlgorithmsMap s_supported_algorithms; diff --git a/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.h b/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.h index de6d89b0618..5f622548ace 100644 --- a/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.h +++ b/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.h @@ -35,6 +35,7 @@ public: JS::NonnullGCPtr digest(AlgorithmIdentifier const& algorithm, JS::Handle const& data); JS::ThrowCompletionOr> generate_key(AlgorithmIdentifier algorithm, bool extractable, Vector key_usages); + JS::ThrowCompletionOr> derive_bits(AlgorithmIdentifier algorithm, JS::NonnullGCPtr base_key, u32 length); JS::ThrowCompletionOr> import_key(Bindings::KeyFormat format, KeyDataType key_data, AlgorithmIdentifier algorithm, bool extractable, Vector key_usages); JS::ThrowCompletionOr> export_key(Bindings::KeyFormat format, JS::NonnullGCPtr key); diff --git a/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.idl b/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.idl index e6ed6c262f9..8b1322ccf60 100644 --- a/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.idl +++ b/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.idl @@ -54,7 +54,7 @@ interface SubtleCrypto { Promise generateKey(AlgorithmIdentifier algorithm, boolean extractable, sequence keyUsages); // FIXME: Promise deriveKey(AlgorithmIdentifier algorithm, CryptoKey baseKey, AlgorithmIdentifier derivedKeyType, boolean extractable, sequence keyUsages ); - // FIXME: Promise deriveBits(AlgorithmIdentifier algorithm, CryptoKey baseKey, unsigned long length); + Promise deriveBits(AlgorithmIdentifier algorithm, CryptoKey baseKey, unsigned long length); Promise importKey(KeyFormat format, (BufferSource or JsonWebKey) keyData, AlgorithmIdentifier algorithm, boolean extractable, sequence keyUsages); Promise exportKey(KeyFormat format, CryptoKey key);