LibWeb: Implement skeleton of SubtleCrypto.deriveKey
This commit is contained in:
parent
abf55fe33d
commit
9f3c3925e0
Notes:
sideshowbarker
2024-07-17 00:57:24 +09:00
Author: https://github.com/stelar7 Commit: https://github.com/SerenityOS/serenity/commit/9f3c3925e0 Pull-request: https://github.com/SerenityOS/serenity/pull/23834 Reviewed-by: https://github.com/ADKaster ✅
5 changed files with 101 additions and 5 deletions
|
@ -1339,12 +1339,14 @@ WebIDL::ExceptionOr<JS::Value> ED25519::verify([[maybe_unused]] AlgorithmParams
|
|||
return JS::Value(result);
|
||||
}
|
||||
|
||||
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::ArrayBuffer>> PBKDF2::derive_bits(AlgorithmParams const& params, JS::NonnullGCPtr<CryptoKey> key, u32 length)
|
||||
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::ArrayBuffer>> PBKDF2::derive_bits(AlgorithmParams const& params, JS::NonnullGCPtr<CryptoKey> key, Optional<u32> length_optional)
|
||||
{
|
||||
auto& realm = m_realm;
|
||||
auto const& normalized_algorithm = static_cast<PBKDF2Params const&>(params);
|
||||
|
||||
// 1. If length is null or zero, or is not a multiple of 8, then throw an OperationError.
|
||||
auto length = length_optional.value_or(0);
|
||||
|
||||
if (length == 0 || length % 8 != 0)
|
||||
return WebIDL::OperationError::create(realm, "Length must be greater than 0 and divisible by 8"_fly_string);
|
||||
|
||||
|
|
|
@ -177,7 +177,7 @@ public:
|
|||
return WebIDL::NotSupportedError::create(m_realm, "digest is not supported"_fly_string);
|
||||
}
|
||||
|
||||
virtual WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::ArrayBuffer>> derive_bits(AlgorithmParams const&, JS::NonnullGCPtr<CryptoKey>, u32)
|
||||
virtual WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::ArrayBuffer>> derive_bits(AlgorithmParams const&, JS::NonnullGCPtr<CryptoKey>, Optional<u32>)
|
||||
{
|
||||
return WebIDL::NotSupportedError::create(m_realm, "deriveBits is not supported"_fly_string);
|
||||
}
|
||||
|
@ -235,7 +235,7 @@ private:
|
|||
class PBKDF2 : public AlgorithmMethods {
|
||||
public:
|
||||
virtual WebIDL::ExceptionOr<JS::NonnullGCPtr<CryptoKey>> import_key(AlgorithmParams const&, Bindings::KeyFormat, CryptoKey::InternalKeyData, bool, Vector<Bindings::KeyUsage> const&) override;
|
||||
virtual WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::ArrayBuffer>> derive_bits(AlgorithmParams const&, JS::NonnullGCPtr<CryptoKey>, u32) override;
|
||||
virtual WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::ArrayBuffer>> derive_bits(AlgorithmParams const&, JS::NonnullGCPtr<CryptoKey>, Optional<u32>) override;
|
||||
virtual WebIDL::ExceptionOr<JS::Value> get_key_length(AlgorithmParams const&) override;
|
||||
|
||||
static NonnullOwnPtr<AlgorithmMethods> create(JS::Realm& realm) { return adopt_own(*new PBKDF2(realm)); }
|
||||
|
|
|
@ -631,6 +631,99 @@ JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> SubtleCrypto::derive_bits(A
|
|||
return verify_cast<JS::Promise>(*promise->promise());
|
||||
}
|
||||
|
||||
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> SubtleCrypto::derive_key(AlgorithmIdentifier algorithm, JS::NonnullGCPtr<CryptoKey> base_key, AlgorithmIdentifier derived_key_type, bool extractable, Vector<Bindings::KeyUsage> key_usages)
|
||||
{
|
||||
auto& realm = this->realm();
|
||||
auto& vm = this->vm();
|
||||
// 1. Let algorithm, baseKey, derivedKeyType, extractable and usages be the algorithm, baseKey, derivedKeyType, extractable and keyUsages parameters passed to the deriveKey() 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 normalizedDerivedKeyAlgorithmImport be the result of normalizing an algorithm, with alg set to derivedKeyType and op set to "importKey".
|
||||
auto normalized_derived_key_algorithm_import = normalize_an_algorithm(realm, derived_key_type, "importKey"_string);
|
||||
|
||||
// 5. If an error occurred, return a Promise rejected with normalizedDerivedKeyAlgorithmImport.
|
||||
if (normalized_derived_key_algorithm_import.is_error())
|
||||
return WebIDL::create_rejected_promise_from_exception(realm, normalized_derived_key_algorithm_import.release_error());
|
||||
|
||||
// 6. Let normalizedDerivedKeyAlgorithmLength be the result of normalizing an algorithm, with alg set to derivedKeyType and op set to "get key length".
|
||||
auto normalized_derived_key_algorithm_length = normalize_an_algorithm(realm, derived_key_type, "get key length"_string);
|
||||
|
||||
// 7. If an error occurred, return a Promise rejected with normalizedDerivedKeyAlgorithmLength.
|
||||
if (normalized_derived_key_algorithm_length.is_error())
|
||||
return WebIDL::create_rejected_promise_from_exception(realm, normalized_derived_key_algorithm_length.release_error());
|
||||
|
||||
// 8. Let promise be a new Promise.
|
||||
auto promise = WebIDL::create_promise(realm);
|
||||
|
||||
// 9. Return promise and perform the remaining steps in parallel.
|
||||
Platform::EventLoopPlugin::the().deferred_invoke([&realm, &vm, normalized_algorithm = normalized_algorithm.release_value(), promise, normalized_derived_key_algorithm_import = normalized_derived_key_algorithm_import.release_value(), normalized_derived_key_algorithm_length = normalized_derived_key_algorithm_length.release_value(), base_key = move(base_key), extractable, key_usages = move(key_usages)]() -> void {
|
||||
HTML::TemporaryExecutionContext context(Bindings::host_defined_environment_settings_object(realm), HTML::TemporaryExecutionContext::CallbacksEnabled::Yes);
|
||||
// 10. If the following steps or referenced procedures say to throw an error, reject promise with the returned error and then terminate the algorithm.
|
||||
|
||||
// 11. 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;
|
||||
}
|
||||
|
||||
// 12. If the [[usages]] internal slot of baseKey does not contain an entry that is "deriveKey", then throw an InvalidAccessError.
|
||||
if (!base_key->internal_usages().contains_slow(Bindings::KeyUsage::Derivekey)) {
|
||||
WebIDL::reject_promise(realm, promise, WebIDL::InvalidAccessError::create(realm, "Key does not support deriving keys"_fly_string));
|
||||
return;
|
||||
}
|
||||
|
||||
// 13. Let length be the result of performing the get key length algorithm specified by normalizedDerivedKeyAlgorithmLength using derivedKeyType.
|
||||
auto length_result = normalized_derived_key_algorithm_length.methods->get_key_length(*normalized_derived_key_algorithm_length.parameter);
|
||||
if (length_result.is_error()) {
|
||||
WebIDL::reject_promise(realm, promise, Bindings::dom_exception_to_throw_completion(realm.vm(), length_result.release_error()).release_value().value());
|
||||
return;
|
||||
}
|
||||
|
||||
auto length_raw_value = length_result.release_value();
|
||||
Optional<u32> length = {};
|
||||
if (length_raw_value.is_number()) {
|
||||
auto maybe_length = length_raw_value.to_u32(vm);
|
||||
if (!maybe_length.has_value()) {
|
||||
WebIDL::reject_promise(realm, promise, maybe_length.release_error().release_value().value());
|
||||
return;
|
||||
}
|
||||
|
||||
length = maybe_length.value();
|
||||
}
|
||||
|
||||
// 14. Let secret be the result of performing the derive bits operation specified by normalizedAlgorithm using key, algorithm and length.
|
||||
auto secret = normalized_algorithm.methods->derive_bits(*normalized_algorithm.parameter, base_key, length);
|
||||
if (secret.is_error()) {
|
||||
WebIDL::reject_promise(realm, promise, Bindings::dom_exception_to_throw_completion(realm.vm(), secret.release_error()).release_value().value());
|
||||
return;
|
||||
}
|
||||
|
||||
// 15. Let result be the result of performing the import key operation specified by normalizedDerivedKeyAlgorithmImport using "raw" as format, secret as keyData, derivedKeyType as algorithm and using extractable and usages.
|
||||
auto result = normalized_derived_key_algorithm_import.methods->import_key(*normalized_derived_key_algorithm_import.parameter, Bindings::KeyFormat::Raw, secret.release_value()->buffer(), extractable, key_usages);
|
||||
if (result.is_error()) {
|
||||
WebIDL::reject_promise(realm, promise, Bindings::dom_exception_to_throw_completion(realm.vm(), result.release_error()).release_value().value());
|
||||
return;
|
||||
}
|
||||
|
||||
// 16. If the [[type]] internal slot of result is "secret" or "private" and usages is empty, then throw a SyntaxError.
|
||||
if ((result.release_value()->type() == Bindings::KeyType::Secret || result.release_value()->type() == Bindings::KeyType::Private) && key_usages.is_empty()) {
|
||||
WebIDL::reject_promise(realm, promise, WebIDL::SyntaxError::create(realm, "usages must not be empty"_fly_string));
|
||||
return;
|
||||
}
|
||||
|
||||
// 17. Resolve promise with result.
|
||||
WebIDL::resolve_promise(realm, promise, result.release_value());
|
||||
});
|
||||
|
||||
return verify_cast<JS::Promise>(*promise->promise());
|
||||
}
|
||||
|
||||
SupportedAlgorithmsMap& supported_algorithms_internal()
|
||||
{
|
||||
static SupportedAlgorithmsMap s_supported_algorithms;
|
||||
|
|
|
@ -36,6 +36,7 @@ public:
|
|||
|
||||
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> generate_key(AlgorithmIdentifier algorithm, bool extractable, Vector<Bindings::KeyUsage> key_usages);
|
||||
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> derive_bits(AlgorithmIdentifier algorithm, JS::NonnullGCPtr<CryptoKey> base_key, u32 length);
|
||||
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> derive_key(AlgorithmIdentifier algorithm, JS::NonnullGCPtr<CryptoKey> base_key, AlgorithmIdentifier derived_key_type, bool extractable, Vector<Bindings::KeyUsage> key_usages);
|
||||
|
||||
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> import_key(Bindings::KeyFormat format, KeyDataType key_data, AlgorithmIdentifier algorithm, bool extractable, Vector<Bindings::KeyUsage> key_usages);
|
||||
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> export_key(Bindings::KeyFormat format, JS::NonnullGCPtr<CryptoKey> key);
|
||||
|
|
|
@ -52,8 +52,8 @@ interface SubtleCrypto {
|
|||
|
||||
Promise<any> digest(AlgorithmIdentifier algorithm, BufferSource data);
|
||||
|
||||
Promise<any> generateKey(AlgorithmIdentifier algorithm, boolean extractable, sequence<KeyUsage> keyUsages);
|
||||
// FIXME: Promise<any> deriveKey(AlgorithmIdentifier algorithm, CryptoKey baseKey, AlgorithmIdentifier derivedKeyType, boolean extractable, sequence<KeyUsage> keyUsages );
|
||||
Promise<any> generateKey(AlgorithmIdentifier algorithm, boolean extractable, sequence<KeyUsage> keyUsages);
|
||||
Promise<any> deriveKey(AlgorithmIdentifier algorithm, CryptoKey baseKey, AlgorithmIdentifier derivedKeyType, boolean extractable, sequence<KeyUsage> keyUsages);
|
||||
Promise<ArrayBuffer> deriveBits(AlgorithmIdentifier algorithm, CryptoKey baseKey, unsigned long length);
|
||||
|
||||
Promise<CryptoKey> importKey(KeyFormat format, (BufferSource or JsonWebKey) keyData, AlgorithmIdentifier algorithm, boolean extractable, sequence<KeyUsage> keyUsages);
|
||||
|
|
Loading…
Add table
Reference in a new issue