LibWeb: Implement skeleton of SubtleCrypto.sign

This commit is contained in:
stelar7 2024-03-26 23:53:35 +01:00 committed by Andrew Kaster
parent d1fdfead54
commit cfae6523be
Notes: sideshowbarker 2024-07-16 22:16:50 +09:00
4 changed files with 64 additions and 1 deletions

View File

@ -131,6 +131,11 @@ public:
return WebIDL::NotSupportedError::create(m_realm, "decrypt is not supported"_fly_string);
}
virtual WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::ArrayBuffer>> sign(AlgorithmParams const&, JS::NonnullGCPtr<CryptoKey>, ByteBuffer const&)
{
return WebIDL::NotSupportedError::create(m_realm, "sign is not supported"_fly_string);
}
virtual WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::ArrayBuffer>> digest(AlgorithmParams const&, ByteBuffer const&)
{
return WebIDL::NotSupportedError::create(m_realm, "digest is not supported"_fly_string);

View File

@ -463,6 +463,63 @@ JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> SubtleCrypto::export_key(Bi
return verify_cast<JS::Promise>(*promise->promise());
}
// https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-sign
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> SubtleCrypto::sign(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& data_parameter)
{
auto& realm = this->realm();
auto& vm = this->vm();
// 1. Let algorithm and key be the algorithm and key parameters passed to the sign() method, respectively.
// 2. Let data be the result of getting a copy of the bytes held by the data parameter passed to the sign() method.
auto data_or_error = WebIDL::get_buffer_source_copy(*data_parameter->raw_object());
if (data_or_error.is_error()) {
VERIFY(data_or_error.error().code() == ENOMEM);
return WebIDL::create_rejected_promise_from_exception(realm, vm.throw_completion<JS::InternalError>(vm.error_message(JS::VM::ErrorMessage::OutOfMemory)));
}
auto data = data_or_error.release_value();
// 3. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set to algorithm and op set to "sign".
auto normalized_algorithm = normalize_an_algorithm(realm, algorithm, "sign"_string);
// 4. 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());
// 5. Let promise be a new Promise.
auto promise = WebIDL::create_promise(realm);
// 6. Return promise and perform the remaining steps in parallel.
Platform::EventLoopPlugin::the().deferred_invoke([&realm, normalized_algorithm = normalized_algorithm.release_value(), promise, key, data = move(data)]() -> void {
HTML::TemporaryExecutionContext context(Bindings::host_defined_environment_settings_object(realm), HTML::TemporaryExecutionContext::CallbacksEnabled::Yes);
// 7. If the following steps or referenced procedures say to throw an error, reject promise with the returned error and then terminate the algorithm.
// 8. If the name member of normalizedAlgorithm is not equal to the name attribute of the [[algorithm]] internal slot of key then throw an InvalidAccessError.
if (normalized_algorithm.parameter->name != key->algorithm_name()) {
WebIDL::reject_promise(realm, promise, WebIDL::InvalidAccessError::create(realm, "Algorithm mismatch"_fly_string));
return;
}
// 9. If the [[usages]] internal slot of key does not contain an entry that is "sign", then throw an InvalidAccessError.
if (!key->internal_usages().contains_slow(Bindings::KeyUsage::Sign)) {
WebIDL::reject_promise(realm, promise, WebIDL::InvalidAccessError::create(realm, "Key does not support signing"_fly_string));
return;
}
// 10. Let result be the result of performing the sign operation specified by normalizedAlgorithm using key and algorithm and with data as message.
auto result = normalized_algorithm.methods->sign(*normalized_algorithm.parameter, key, data);
if (result.is_error()) {
WebIDL::reject_promise(realm, promise, Bindings::dom_exception_to_throw_completion(realm.vm(), result.release_error()).release_value().value());
return;
}
// 9. 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;

View File

@ -29,6 +29,7 @@ public:
JS::NonnullGCPtr<JS::Promise> encrypt(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& data_parameter);
JS::NonnullGCPtr<JS::Promise> decrypt(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& data_parameter);
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> sign(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& data_parameter);
JS::NonnullGCPtr<JS::Promise> digest(AlgorithmIdentifier const& algorithm, JS::Handle<WebIDL::BufferSource> const& data);

View File

@ -47,7 +47,7 @@ dictionary JsonWebKey
interface SubtleCrypto {
Promise<any> encrypt(AlgorithmIdentifier algorithm, CryptoKey key, BufferSource data);
Promise<any> decrypt(AlgorithmIdentifier algorithm, CryptoKey key, BufferSource data);
// FIXME: Promise<any> sign(AlgorithmIdentifier algorithm, CryptoKey key, BufferSource data);
Promise<any> sign(AlgorithmIdentifier algorithm, CryptoKey key, BufferSource data);
// FIXME: Promise<any> verify(AlgorithmIdentifier algorithm, CryptoKey key, BufferSource signature, BufferSource data);
Promise<any> digest(AlgorithmIdentifier algorithm, BufferSource data);