Coverage Report

Created: 2025-11-16 07:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/serenity/Userland/Libraries/LibWeb/Crypto/SubtleCrypto.cpp
Line
Count
Source
1
/*
2
 * Copyright (c) 2021-2022, Linus Groh <linusg@serenityos.org>
3
 * Copyright (c) 2023, stelar7 <dudedbz@gmail.com>
4
 *
5
 * SPDX-License-Identifier: BSD-2-Clause
6
 */
7
8
#include <AK/QuickSort.h>
9
#include <LibCrypto/Hash/HashManager.h>
10
#include <LibJS/Runtime/ArrayBuffer.h>
11
#include <LibJS/Runtime/Promise.h>
12
#include <LibWeb/Bindings/ExceptionOrUtils.h>
13
#include <LibWeb/Bindings/Intrinsics.h>
14
#include <LibWeb/Bindings/SubtleCryptoPrototype.h>
15
#include <LibWeb/Crypto/KeyAlgorithms.h>
16
#include <LibWeb/Crypto/SubtleCrypto.h>
17
#include <LibWeb/HTML/Scripting/TemporaryExecutionContext.h>
18
#include <LibWeb/Platform/EventLoopPlugin.h>
19
#include <LibWeb/WebIDL/AbstractOperations.h>
20
#include <LibWeb/WebIDL/Buffers.h>
21
#include <LibWeb/WebIDL/ExceptionOr.h>
22
#include <LibWeb/WebIDL/Promise.h>
23
24
namespace Web::Crypto {
25
26
static void normalize_key_usages(Vector<Bindings::KeyUsage>& key_usages)
27
0
{
28
0
    quick_sort(key_usages);
29
0
}
30
struct RegisteredAlgorithm {
31
    NonnullOwnPtr<AlgorithmMethods> (*create_methods)(JS::Realm&) = nullptr;
32
    JS::ThrowCompletionOr<NonnullOwnPtr<AlgorithmParams>> (*parameter_from_value)(JS::VM&, JS::Value) = nullptr;
33
};
34
using SupportedAlgorithmsMap = HashMap<String, HashMap<String, RegisteredAlgorithm, AK::ASCIICaseInsensitiveStringTraits>>;
35
36
static SupportedAlgorithmsMap& supported_algorithms_internal();
37
static SupportedAlgorithmsMap supported_algorithms();
38
39
template<typename Methods, typename Param = AlgorithmParams>
40
static void define_an_algorithm(String op, String algorithm);
41
42
JS_DEFINE_ALLOCATOR(SubtleCrypto);
43
44
JS::NonnullGCPtr<SubtleCrypto> SubtleCrypto::create(JS::Realm& realm)
45
0
{
46
0
    return realm.heap().allocate<SubtleCrypto>(realm, realm);
47
0
}
48
49
SubtleCrypto::SubtleCrypto(JS::Realm& realm)
50
0
    : PlatformObject(realm)
51
0
{
52
0
}
53
54
0
SubtleCrypto::~SubtleCrypto() = default;
55
56
void SubtleCrypto::initialize(JS::Realm& realm)
57
0
{
58
0
    Base::initialize(realm);
59
0
    WEB_SET_PROTOTYPE_FOR_INTERFACE(SubtleCrypto);
60
0
}
61
62
// https://w3c.github.io/webcrypto/#dfn-normalize-an-algorithm
63
WebIDL::ExceptionOr<NormalizedAlgorithmAndParameter> normalize_an_algorithm(JS::Realm& realm, AlgorithmIdentifier const& algorithm, String operation)
64
0
{
65
0
    auto& vm = realm.vm();
66
67
    // If alg is an instance of a DOMString:
68
0
    if (algorithm.has<String>()) {
69
        // Return the result of running the normalize an algorithm algorithm,
70
        // with the alg set to a new Algorithm dictionary whose name attribute is alg, and with the op set to op.
71
0
        auto dictionary = JS::make_handle(JS::Object::create(realm, realm.intrinsics().object_prototype()));
72
0
        TRY(dictionary->create_data_property("name", JS::PrimitiveString::create(vm, algorithm.get<String>())));
73
74
0
        return normalize_an_algorithm(realm, dictionary, operation);
75
0
    }
76
77
    // If alg is an object:
78
    // 1. Let registeredAlgorithms be the associative container stored at the op key of supportedAlgorithms.
79
    // NOTE: There should always be a container at the op key.
80
0
    auto internal_object = supported_algorithms();
81
0
    auto maybe_registered_algorithms = internal_object.get(operation);
82
0
    auto registered_algorithms = maybe_registered_algorithms.value();
83
84
    // 2. Let initialAlg be the result of converting the ECMAScript object represented by alg to
85
    // the IDL dictionary type Algorithm, as defined by [WebIDL].
86
    // 3. If an error occurred, return the error and terminate this algorithm.
87
    // Note: We're not going to bother creating an Algorithm object, all we want is the name attribute so that we can
88
    //       fetch the actual algorithm factory from the registeredAlgorithms map.
89
0
    auto initial_algorithm = TRY(algorithm.get<JS::Handle<JS::Object>>()->get("name"));
90
91
    // 4. Let algName be the value of the name attribute of initialAlg.
92
0
    auto algorithm_name = TRY(initial_algorithm.to_string(vm));
93
94
0
    RegisteredAlgorithm desired_type;
95
96
    // 5. If registeredAlgorithms contains a key that is a case-insensitive string match for algName:
97
0
    if (auto it = registered_algorithms.find(algorithm_name); it != registered_algorithms.end()) {
98
        // 1. Set algName to the value of the matching key.
99
        // 2. Let desiredType be the IDL dictionary type stored at algName in registeredAlgorithms.
100
0
        desired_type = it->value;
101
0
    } else {
102
        // Otherwise:
103
        // Return a new NotSupportedError and terminate this algorithm.
104
0
        return WebIDL::NotSupportedError::create(realm, MUST(String::formatted("Algorithm '{}' is not supported for operation '{}'", algorithm_name, operation)));
105
0
    }
106
107
    // 8. Let normalizedAlgorithm be the result of converting the ECMAScript object represented by alg
108
    // to the IDL dictionary type desiredType, as defined by [WebIDL].
109
    // 9. Set the name attribute of normalizedAlgorithm to algName.
110
    // 10. If an error occurred, return the error and terminate this algorithm.
111
    // 11. Let dictionaries be a list consisting of the IDL dictionary type desiredType
112
    // and all of desiredType's inherited dictionaries, in order from least to most derived.
113
    // 12. For each dictionary dictionary in dictionaries:
114
    //    Note: All of these steps are handled by the create_methods and parameter_from_value methods.
115
0
    auto methods = desired_type.create_methods(realm);
116
0
    auto parameter = TRY(desired_type.parameter_from_value(vm, algorithm.get<JS::Handle<JS::Object>>()));
117
0
    auto normalized_algorithm = NormalizedAlgorithmAndParameter { move(methods), move(parameter) };
118
119
    // 13. Return normalizedAlgorithm.
120
0
    return normalized_algorithm;
121
0
}
122
123
// https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-encrypt
124
JS::NonnullGCPtr<JS::Promise> SubtleCrypto::encrypt(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& data_parameter)
125
0
{
126
0
    auto& realm = this->realm();
127
0
    auto& vm = this->vm();
128
    // 1. Let algorithm and key be the algorithm and key parameters passed to the encrypt() method, respectively.
129
130
    // 2. Let data be the result of getting a copy of the bytes held by the data parameter passed to the encrypt() method.
131
0
    auto data_or_error = WebIDL::get_buffer_source_copy(*data_parameter->raw_object());
132
0
    if (data_or_error.is_error()) {
133
0
        VERIFY(data_or_error.error().code() == ENOMEM);
134
0
        return WebIDL::create_rejected_promise_from_exception(realm, vm.throw_completion<JS::InternalError>(vm.error_message(JS::VM::ErrorMessage::OutOfMemory)));
135
0
    }
136
0
    auto data = data_or_error.release_value();
137
138
    // 3. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set to algorithm and op set to "encrypt".
139
0
    auto normalized_algorithm = normalize_an_algorithm(realm, algorithm, "encrypt"_string);
140
141
    // 4. If an error occurred, return a Promise rejected with normalizedAlgorithm.
142
0
    if (normalized_algorithm.is_error())
143
0
        return WebIDL::create_rejected_promise_from_exception(realm, normalized_algorithm.release_error());
144
145
    // 5. Let promise be a new Promise.
146
0
    auto promise = WebIDL::create_promise(realm);
147
148
    // 6. Return promise and perform the remaining steps in parallel.
149
150
0
    Platform::EventLoopPlugin::the().deferred_invoke([&realm, normalized_algorithm = normalized_algorithm.release_value(), promise, key, data = move(data)]() -> void {
151
0
        HTML::TemporaryExecutionContext context(Bindings::host_defined_environment_settings_object(realm), HTML::TemporaryExecutionContext::CallbacksEnabled::Yes);
152
        // 7. If the following steps or referenced procedures say to throw an error, reject promise with the returned error and then terminate the algorithm.
153
154
        // 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.
155
0
        if (normalized_algorithm.parameter->name != key->algorithm_name()) {
156
0
            WebIDL::reject_promise(realm, promise, WebIDL::InvalidAccessError::create(realm, "Algorithm mismatch"_string));
157
0
            return;
158
0
        }
159
160
        // 9. If the [[usages]] internal slot of key does not contain an entry that is "encrypt", then throw an InvalidAccessError.
161
0
        if (!key->internal_usages().contains_slow(Bindings::KeyUsage::Encrypt)) {
162
0
            WebIDL::reject_promise(realm, promise, WebIDL::InvalidAccessError::create(realm, "Key does not support encryption"_string));
163
0
            return;
164
0
        }
165
166
        // 10. Let ciphertext be the result of performing the encrypt operation specified by normalizedAlgorithm using algorithm and key and with data as plaintext.
167
0
        auto cipher_text = normalized_algorithm.methods->encrypt(*normalized_algorithm.parameter, key, data);
168
0
        if (cipher_text.is_error()) {
169
0
            WebIDL::reject_promise(realm, promise, Bindings::dom_exception_to_throw_completion(realm.vm(), cipher_text.release_error()).release_value().value());
170
0
            return;
171
0
        }
172
173
        // 9. Resolve promise with ciphertext.
174
0
        WebIDL::resolve_promise(realm, promise, cipher_text.release_value());
175
0
    });
176
177
0
    return verify_cast<JS::Promise>(*promise->promise());
178
0
}
179
180
// https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-decrypt
181
JS::NonnullGCPtr<JS::Promise> SubtleCrypto::decrypt(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& data_parameter)
182
0
{
183
0
    auto& realm = this->realm();
184
0
    auto& vm = this->vm();
185
    // 1. Let algorithm and key be the algorithm and key parameters passed to the decrypt() method, respectively.
186
187
    // 2. Let data be the result of getting a copy of the bytes held by the data parameter passed to the decrypt() method.
188
0
    auto data_or_error = WebIDL::get_buffer_source_copy(*data_parameter->raw_object());
189
0
    if (data_or_error.is_error()) {
190
0
        VERIFY(data_or_error.error().code() == ENOMEM);
191
0
        return WebIDL::create_rejected_promise_from_exception(realm, vm.throw_completion<JS::InternalError>(vm.error_message(JS::VM::ErrorMessage::OutOfMemory)));
192
0
    }
193
0
    auto data = data_or_error.release_value();
194
195
    // 3. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set to algorithm and op set to "decrypt".
196
0
    auto normalized_algorithm = normalize_an_algorithm(realm, algorithm, "decrypt"_string);
197
198
    // 4. If an error occurred, return a Promise rejected with normalizedAlgorithm.
199
0
    if (normalized_algorithm.is_error())
200
0
        return WebIDL::create_rejected_promise_from_exception(realm, normalized_algorithm.release_error());
201
202
    // 5. Let promise be a new Promise.
203
0
    auto promise = WebIDL::create_promise(realm);
204
205
    // 6. Return promise and perform the remaining steps in parallel.
206
207
0
    Platform::EventLoopPlugin::the().deferred_invoke([&realm, normalized_algorithm = normalized_algorithm.release_value(), promise, key, data = move(data)]() -> void {
208
0
        HTML::TemporaryExecutionContext context(Bindings::host_defined_environment_settings_object(realm), HTML::TemporaryExecutionContext::CallbacksEnabled::Yes);
209
        // 7. If the following steps or referenced procedures say to throw an error, reject promise with the returned error and then terminate the algorithm.
210
211
        // 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.
212
0
        if (normalized_algorithm.parameter->name != key->algorithm_name()) {
213
0
            WebIDL::reject_promise(realm, promise, WebIDL::InvalidAccessError::create(realm, "Algorithm mismatch"_string));
214
0
            return;
215
0
        }
216
217
        // 9. If the [[usages]] internal slot of key does not contain an entry that is "decrypt", then throw an InvalidAccessError.
218
0
        if (!key->internal_usages().contains_slow(Bindings::KeyUsage::Decrypt)) {
219
0
            WebIDL::reject_promise(realm, promise, WebIDL::InvalidAccessError::create(realm, "Key does not support encryption"_string));
220
0
            return;
221
0
        }
222
223
        // 10. Let plaintext be the result of performing the decrypt operation specified by normalizedAlgorithm using algorithm and key and with data as ciphertext.
224
0
        auto plain_text = normalized_algorithm.methods->decrypt(*normalized_algorithm.parameter, key, data);
225
0
        if (plain_text.is_error()) {
226
0
            WebIDL::reject_promise(realm, promise, Bindings::dom_exception_to_throw_completion(realm.vm(), plain_text.release_error()).release_value().value());
227
0
            return;
228
0
        }
229
230
        // 9. Resolve promise with plaintext.
231
0
        WebIDL::resolve_promise(realm, promise, plain_text.release_value());
232
0
    });
233
234
0
    return verify_cast<JS::Promise>(*promise->promise());
235
0
}
236
237
// https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-digest
238
JS::NonnullGCPtr<JS::Promise> SubtleCrypto::digest(AlgorithmIdentifier const& algorithm, JS::Handle<WebIDL::BufferSource> const& data)
239
0
{
240
0
    auto& realm = this->realm();
241
0
    auto& vm = this->vm();
242
243
    // 1. Let algorithm be the algorithm parameter passed to the digest() method.
244
245
    // 2. Let data be the result of getting a copy of the bytes held by the data parameter passed to the digest() method.
246
0
    auto data_buffer_or_error = WebIDL::get_buffer_source_copy(*data->raw_object());
247
0
    if (data_buffer_or_error.is_error()) {
248
0
        VERIFY(data_buffer_or_error.error().code() == ENOMEM);
249
0
        return WebIDL::create_rejected_promise_from_exception(realm, vm.throw_completion<JS::InternalError>(vm.error_message(JS::VM::ErrorMessage::OutOfMemory)));
250
0
    }
251
0
    auto data_buffer = data_buffer_or_error.release_value();
252
253
    // 3. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set to algorithm and op set to "digest".
254
0
    auto normalized_algorithm = normalize_an_algorithm(realm, algorithm, "digest"_string);
255
256
    // 4. If an error occurred, return a Promise rejected with normalizedAlgorithm.
257
    // FIXME: Spec bug: link to https://webidl.spec.whatwg.org/#a-promise-rejected-with
258
0
    if (normalized_algorithm.is_error())
259
0
        return WebIDL::create_rejected_promise_from_exception(realm, normalized_algorithm.release_error());
260
261
    // 5. Let promise be a new Promise.
262
0
    auto promise = WebIDL::create_promise(realm);
263
264
    // 6. Return promise and perform the remaining steps in parallel.
265
0
    Platform::EventLoopPlugin::the().deferred_invoke([&realm, algorithm_object = normalized_algorithm.release_value(), promise, data_buffer = move(data_buffer)]() -> void {
266
0
        HTML::TemporaryExecutionContext context(Bindings::host_defined_environment_settings_object(realm), HTML::TemporaryExecutionContext::CallbacksEnabled::Yes);
267
        // 7. If the following steps or referenced procedures say to throw an error, reject promise with the returned error and then terminate the algorithm.
268
        // FIXME: Need spec reference to https://webidl.spec.whatwg.org/#reject
269
270
        // 8. Let result be the result of performing the digest operation specified by normalizedAlgorithm using algorithm, with data as message.
271
0
        auto result = algorithm_object.methods->digest(*algorithm_object.parameter, data_buffer);
272
273
0
        if (result.is_exception()) {
274
0
            WebIDL::reject_promise(realm, promise, Bindings::dom_exception_to_throw_completion(realm.vm(), result.release_error()).release_value().value());
275
0
            return;
276
0
        }
277
278
        // 9. Resolve promise with result.
279
0
        WebIDL::resolve_promise(realm, promise, result.release_value());
280
0
    });
281
282
0
    return verify_cast<JS::Promise>(*promise->promise());
283
0
}
284
285
// https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-generateKey
286
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> SubtleCrypto::generate_key(AlgorithmIdentifier algorithm, bool extractable, Vector<Bindings::KeyUsage> key_usages)
287
0
{
288
0
    auto& realm = this->realm();
289
290
    // 1. Let algorithm, extractable and usages be the algorithm, extractable and keyUsages
291
    //    parameters passed to the generateKey() method, respectively.
292
293
    // 2. Let normalizedAlgorithm be the result of normalizing an algorithm,
294
    //    with alg set to algorithm and op set to "generateKey".
295
0
    auto normalized_algorithm = normalize_an_algorithm(realm, algorithm, "generateKey"_string);
296
297
    // 3. If an error occurred, return a Promise rejected with normalizedAlgorithm.
298
0
    if (normalized_algorithm.is_error())
299
0
        return WebIDL::create_rejected_promise_from_exception(realm, normalized_algorithm.release_error());
300
301
    // 4. Let promise be a new Promise.
302
0
    auto promise = WebIDL::create_promise(realm);
303
304
    // 5. Return promise and perform the remaining steps in parallel.
305
0
    Platform::EventLoopPlugin::the().deferred_invoke([&realm, normalized_algorithm = normalized_algorithm.release_value(), promise, extractable, key_usages = move(key_usages)]() -> void {
306
0
        HTML::TemporaryExecutionContext context(Bindings::host_defined_environment_settings_object(realm), HTML::TemporaryExecutionContext::CallbacksEnabled::Yes);
307
        // 6. If the following steps or referenced procedures say to throw an error, reject promise with
308
        //    the returned error and then terminate the algorithm.
309
310
        // 7. Let result be the result of performing the generate key operation specified by normalizedAlgorithm
311
        //    using algorithm, extractable and usages.
312
0
        auto result_or_error = normalized_algorithm.methods->generate_key(*normalized_algorithm.parameter, extractable, key_usages);
313
314
0
        if (result_or_error.is_error()) {
315
0
            WebIDL::reject_promise(realm, promise, Bindings::dom_exception_to_throw_completion(realm.vm(), result_or_error.release_error()).release_value().value());
316
0
            return;
317
0
        }
318
0
        auto result = result_or_error.release_value();
319
320
        // 8. If result is a CryptoKey object:
321
        //      If the [[type]] internal slot of result is "secret" or "private" and usages is empty, then throw a SyntaxError.
322
        //    If result is a CryptoKeyPair object:
323
        //      If the [[usages]] internal slot of the privateKey attribute of result is the empty sequence, then throw a SyntaxError.
324
        // 9. Resolve promise with result.
325
0
        result.visit(
326
0
            [&](JS::NonnullGCPtr<CryptoKey>& key) {
327
0
                if ((key->type() == Bindings::KeyType::Secret || key->type() == Bindings::KeyType::Private) && key_usages.is_empty()) {
328
0
                    WebIDL::reject_promise(realm, promise, WebIDL::SyntaxError::create(realm, "usages must not be empty"_string));
329
0
                    return;
330
0
                }
331
0
                WebIDL::resolve_promise(realm, promise, key);
332
0
            },
333
0
            [&](JS::NonnullGCPtr<CryptoKeyPair>& key_pair) {
334
0
                if (key_pair->private_key()->internal_usages().is_empty()) {
335
0
                    WebIDL::reject_promise(realm, promise, WebIDL::SyntaxError::create(realm, "usages must not be empty"_string));
336
0
                    return;
337
0
                }
338
0
                WebIDL::resolve_promise(realm, promise, key_pair);
339
0
            });
340
0
    });
341
342
0
    return verify_cast<JS::Promise>(*promise->promise());
343
0
}
344
345
// https://w3c.github.io/webcrypto/#SubtleCrypto-method-importKey
346
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> SubtleCrypto::import_key(Bindings::KeyFormat format, KeyDataType key_data, AlgorithmIdentifier algorithm, bool extractable, Vector<Bindings::KeyUsage> key_usages)
347
0
{
348
0
    auto& realm = this->realm();
349
350
    // 1. Let format, algorithm, extractable and usages, be the format, algorithm, extractable
351
    // and key_usages parameters passed to the importKey() method, respectively.
352
353
0
    Variant<ByteBuffer, Bindings::JsonWebKey, Empty> real_key_data;
354
    // 2. If format is equal to the string "raw", "pkcs8", or "spki":
355
0
    if (format == Bindings::KeyFormat::Raw || format == Bindings::KeyFormat::Pkcs8 || format == Bindings::KeyFormat::Spki) {
356
        // 1. If the keyData parameter passed to the importKey() method is a JsonWebKey dictionary, throw a TypeError.
357
0
        if (key_data.has<Bindings::JsonWebKey>()) {
358
0
            return realm.vm().throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "BufferSource");
359
0
        }
360
361
        // 2. Let keyData be the result of getting a copy of the bytes held by the keyData parameter passed to the importKey() method.
362
0
        real_key_data = MUST(WebIDL::get_buffer_source_copy(*key_data.get<JS::Handle<WebIDL::BufferSource>>()->raw_object()));
363
0
    }
364
365
0
    if (format == Bindings::KeyFormat::Jwk) {
366
        // 1. If the keyData parameter passed to the importKey() method is not a JsonWebKey dictionary, throw a TypeError.
367
0
        if (!key_data.has<Bindings::JsonWebKey>()) {
368
0
            return realm.vm().throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "JsonWebKey");
369
0
        }
370
371
        // 2. Let keyData be the keyData parameter passed to the importKey() method.
372
0
        real_key_data = key_data.get<Bindings::JsonWebKey>();
373
0
    }
374
375
    // NOTE: The spec jumps to 5 here for some reason?
376
    // 5. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set to algorithm and op set to "importKey".
377
0
    auto normalized_algorithm = normalize_an_algorithm(realm, algorithm, "importKey"_string);
378
379
    // 6. If an error occurred, return a Promise rejected with normalizedAlgorithm.
380
0
    if (normalized_algorithm.is_error())
381
0
        return WebIDL::create_rejected_promise_from_exception(realm, normalized_algorithm.release_error());
382
383
    // 7. Let promise be a new Promise.
384
0
    auto promise = WebIDL::create_promise(realm);
385
386
    // 8. Return promise and perform the remaining steps in parallel.
387
0
    Platform::EventLoopPlugin::the().deferred_invoke([&realm, real_key_data = move(real_key_data), normalized_algorithm = normalized_algorithm.release_value(), promise, format, extractable, key_usages = move(key_usages), algorithm = move(algorithm)]() mutable -> void {
388
0
        HTML::TemporaryExecutionContext context(Bindings::host_defined_environment_settings_object(realm), HTML::TemporaryExecutionContext::CallbacksEnabled::Yes);
389
390
        // 9. If the following steps or referenced procedures say to throw an error, reject promise with the returned error and then terminate the algorithm.
391
392
        // 10. Let result be the CryptoKey object that results from performing the import key operation
393
        // specified by normalizedAlgorithm using keyData, algorithm, format, extractable and usages.
394
0
        auto maybe_result = normalized_algorithm.methods->import_key(*normalized_algorithm.parameter, format, real_key_data.downcast<CryptoKey::InternalKeyData>(), extractable, key_usages);
395
0
        if (maybe_result.is_error()) {
396
0
            WebIDL::reject_promise(realm, promise, Bindings::dom_exception_to_throw_completion(realm.vm(), maybe_result.release_error()).release_value().value());
397
0
            return;
398
0
        }
399
0
        auto result = maybe_result.release_value();
400
401
        // 11. If the [[type]] internal slot of result is "secret" or "private" and usages is empty, then throw a SyntaxError.
402
0
        if ((result->type() == Bindings::KeyType::Secret || result->type() == Bindings::KeyType::Private) && key_usages.is_empty()) {
403
0
            WebIDL::reject_promise(realm, promise, WebIDL::SyntaxError::create(realm, "usages must not be empty"_string));
404
0
            return;
405
0
        }
406
407
        // 12. Set the [[extractable]] internal slot of result to extractable.
408
0
        result->set_extractable(extractable);
409
410
        // 13. Set the [[usages]] internal slot of result to the normalized value of usages.
411
0
        normalize_key_usages(key_usages);
412
0
        result->set_usages(key_usages);
413
414
        // 14. Resolve promise with result.
415
0
        WebIDL::resolve_promise(realm, promise, result);
416
0
    });
417
418
0
    return verify_cast<JS::Promise>(*promise->promise());
419
0
}
420
421
// https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-exportKey
422
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> SubtleCrypto::export_key(Bindings::KeyFormat format, JS::NonnullGCPtr<CryptoKey> key)
423
0
{
424
0
    auto& realm = this->realm();
425
    // 1. Let format and key be the format and key parameters passed to the exportKey() method, respectively.
426
427
    // 2. Let promise be a new Promise.
428
0
    auto promise = WebIDL::create_promise(realm);
429
430
    // 3. Return promise and perform the remaining steps in parallel.
431
0
    Platform::EventLoopPlugin::the().deferred_invoke([&realm, key, promise, format]() -> void {
432
0
        HTML::TemporaryExecutionContext context(Bindings::host_defined_environment_settings_object(realm), HTML::TemporaryExecutionContext::CallbacksEnabled::Yes);
433
        // 4.  If the following steps or referenced procedures say to throw an error, reject promise with the returned error and then terminate the algorithm.
434
435
        // 5. If the name member of the [[algorithm]] internal slot of key does not identify a registered algorithm that supports the export key operation,
436
        //    then throw a NotSupportedError.
437
        // Note: Handled by the base AlgorithmMethods implementation
438
0
        auto& algorithm = verify_cast<KeyAlgorithm>(*key->algorithm());
439
        // FIXME: Stash the AlgorithmMethods on the KeyAlgorithm
440
0
        auto normalized_algorithm_or_error = normalize_an_algorithm(realm, algorithm.name(), "exportKey"_string);
441
0
        if (normalized_algorithm_or_error.is_error()) {
442
0
            WebIDL::reject_promise(realm, promise, Bindings::dom_exception_to_throw_completion(realm.vm(), normalized_algorithm_or_error.release_error()).release_value().value());
443
0
            return;
444
0
        }
445
0
        auto normalized_algorithm = normalized_algorithm_or_error.release_value();
446
447
        // 6. If the [[extractable]] internal slot of key is false, then throw an InvalidAccessError.
448
0
        if (!key->extractable()) {
449
0
            WebIDL::reject_promise(realm, promise, WebIDL::InvalidAccessError::create(realm, "Key is not extractable"_string));
450
0
            return;
451
0
        }
452
453
        // 7. Let result be the result of performing the export key operation specified by the [[algorithm]] internal slot of key using key and format.
454
0
        auto result_or_error = normalized_algorithm.methods->export_key(format, key);
455
0
        if (result_or_error.is_error()) {
456
0
            WebIDL::reject_promise(realm, promise, Bindings::dom_exception_to_throw_completion(realm.vm(), result_or_error.release_error()).release_value().value());
457
0
            return;
458
0
        }
459
460
        // 8. Resolve promise with result.
461
0
        WebIDL::resolve_promise(realm, promise, result_or_error.release_value());
462
0
    });
463
464
0
    return verify_cast<JS::Promise>(*promise->promise());
465
0
}
466
467
// https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-sign
468
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> SubtleCrypto::sign(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& data_parameter)
469
0
{
470
0
    auto& realm = this->realm();
471
0
    auto& vm = this->vm();
472
    // 1. Let algorithm and key be the algorithm and key parameters passed to the sign() method, respectively.
473
474
    // 2. Let data be the result of getting a copy of the bytes held by the data parameter passed to the sign() method.
475
0
    auto data_or_error = WebIDL::get_buffer_source_copy(*data_parameter->raw_object());
476
0
    if (data_or_error.is_error()) {
477
0
        VERIFY(data_or_error.error().code() == ENOMEM);
478
0
        return WebIDL::create_rejected_promise_from_exception(realm, vm.throw_completion<JS::InternalError>(vm.error_message(JS::VM::ErrorMessage::OutOfMemory)));
479
0
    }
480
0
    auto data = data_or_error.release_value();
481
482
    // 3. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set to algorithm and op set to "sign".
483
0
    auto normalized_algorithm = normalize_an_algorithm(realm, algorithm, "sign"_string);
484
485
    // 4. If an error occurred, return a Promise rejected with normalizedAlgorithm.
486
0
    if (normalized_algorithm.is_error())
487
0
        return WebIDL::create_rejected_promise_from_exception(realm, normalized_algorithm.release_error());
488
489
    // 5. Let promise be a new Promise.
490
0
    auto promise = WebIDL::create_promise(realm);
491
492
    // 6. Return promise and perform the remaining steps in parallel.
493
494
0
    Platform::EventLoopPlugin::the().deferred_invoke([&realm, normalized_algorithm = normalized_algorithm.release_value(), promise, key, data = move(data)]() -> void {
495
0
        HTML::TemporaryExecutionContext context(Bindings::host_defined_environment_settings_object(realm), HTML::TemporaryExecutionContext::CallbacksEnabled::Yes);
496
        // 7. If the following steps or referenced procedures say to throw an error, reject promise with the returned error and then terminate the algorithm.
497
498
        // 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.
499
0
        if (normalized_algorithm.parameter->name != key->algorithm_name()) {
500
0
            WebIDL::reject_promise(realm, promise, WebIDL::InvalidAccessError::create(realm, "Algorithm mismatch"_string));
501
0
            return;
502
0
        }
503
504
        // 9. If the [[usages]] internal slot of key does not contain an entry that is "sign", then throw an InvalidAccessError.
505
0
        if (!key->internal_usages().contains_slow(Bindings::KeyUsage::Sign)) {
506
0
            WebIDL::reject_promise(realm, promise, WebIDL::InvalidAccessError::create(realm, "Key does not support signing"_string));
507
0
            return;
508
0
        }
509
510
        // 10. Let result be the result of performing the sign operation specified by normalizedAlgorithm using key and algorithm and with data as message.
511
0
        auto result = normalized_algorithm.methods->sign(*normalized_algorithm.parameter, key, data);
512
0
        if (result.is_error()) {
513
0
            WebIDL::reject_promise(realm, promise, Bindings::dom_exception_to_throw_completion(realm.vm(), result.release_error()).release_value().value());
514
0
            return;
515
0
        }
516
517
        // 9. Resolve promise with result.
518
0
        WebIDL::resolve_promise(realm, promise, result.release_value());
519
0
    });
520
521
0
    return verify_cast<JS::Promise>(*promise->promise());
522
0
}
523
524
// https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-verify
525
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> SubtleCrypto::verify(AlgorithmIdentifier const& algorithm, JS::NonnullGCPtr<CryptoKey> key, JS::Handle<WebIDL::BufferSource> const& signature_data, JS::Handle<WebIDL::BufferSource> const& data_parameter)
526
0
{
527
0
    auto& realm = this->realm();
528
0
    auto& vm = this->vm();
529
    // 1. Let algorithm and key be the algorithm and key parameters passed to the verify() method, respectively.
530
531
    // 2. Let signature be the result of getting a copy of the bytes held by the signature parameter passed to the verify() method.
532
0
    auto signature_or_error = WebIDL::get_buffer_source_copy(*signature_data->raw_object());
533
0
    if (signature_or_error.is_error()) {
534
0
        VERIFY(signature_or_error.error().code() == ENOMEM);
535
0
        return WebIDL::create_rejected_promise_from_exception(realm, vm.throw_completion<JS::InternalError>(vm.error_message(JS::VM::ErrorMessage::OutOfMemory)));
536
0
    }
537
0
    auto signature = signature_or_error.release_value();
538
539
    // 3. Let data be the result of getting a copy of the bytes held by the data parameter passed to the verify() method.
540
0
    auto data_or_error = WebIDL::get_buffer_source_copy(*data_parameter->raw_object());
541
0
    if (data_or_error.is_error()) {
542
0
        VERIFY(data_or_error.error().code() == ENOMEM);
543
0
        return WebIDL::create_rejected_promise_from_exception(realm, vm.throw_completion<JS::InternalError>(vm.error_message(JS::VM::ErrorMessage::OutOfMemory)));
544
0
    }
545
0
    auto data = data_or_error.release_value();
546
547
    // 3. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set to algorithm and op set to "verify".
548
0
    auto normalized_algorithm = normalize_an_algorithm(realm, algorithm, "verify"_string);
549
550
    // 5. If an error occurred, return a Promise rejected with normalizedAlgorithm.
551
0
    if (normalized_algorithm.is_error())
552
0
        return WebIDL::create_rejected_promise_from_exception(realm, normalized_algorithm.release_error());
553
554
    // 6. Let promise be a new Promise.
555
0
    auto promise = WebIDL::create_promise(realm);
556
557
    // 7. Return promise and perform the remaining steps in parallel.
558
0
    Platform::EventLoopPlugin::the().deferred_invoke([&realm, normalized_algorithm = normalized_algorithm.release_value(), promise, key, signature = move(signature), data = move(data)]() -> void {
559
0
        HTML::TemporaryExecutionContext context(Bindings::host_defined_environment_settings_object(realm), HTML::TemporaryExecutionContext::CallbacksEnabled::Yes);
560
        // 8. If the following steps or referenced procedures say to throw an error, reject promise with the returned error and then terminate the algorithm.
561
562
        // 9. If the name member of normalizedAlgorithm is not equal to the name attribute of the [[algorithm]] internal slot of key then throw an InvalidAccessError.
563
0
        if (normalized_algorithm.parameter->name != key->algorithm_name()) {
564
0
            WebIDL::reject_promise(realm, promise, WebIDL::InvalidAccessError::create(realm, "Algorithm mismatch"_string));
565
0
            return;
566
0
        }
567
568
        // 10. If the [[usages]] internal slot of key does not contain an entry that is "verify", then throw an InvalidAccessError.
569
0
        if (!key->internal_usages().contains_slow(Bindings::KeyUsage::Verify)) {
570
0
            WebIDL::reject_promise(realm, promise, WebIDL::InvalidAccessError::create(realm, "Key does not support verification"_string));
571
0
            return;
572
0
        }
573
574
        // 11. Let result be the result of performing the verify operation specified by normalizedAlgorithm using key, algorithm and signature and with data as message.
575
0
        auto result = normalized_algorithm.methods->verify(*normalized_algorithm.parameter, key, signature, data);
576
0
        if (result.is_error()) {
577
0
            WebIDL::reject_promise(realm, promise, Bindings::dom_exception_to_throw_completion(realm.vm(), result.release_error()).release_value().value());
578
0
            return;
579
0
        }
580
581
        // 12. Resolve promise with result.
582
0
        WebIDL::resolve_promise(realm, promise, result.release_value());
583
0
    });
584
585
0
    return verify_cast<JS::Promise>(*promise->promise());
586
0
}
587
588
// https://w3c.github.io/webcrypto/#SubtleCrypto-method-deriveBits
589
JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Promise>> SubtleCrypto::derive_bits(AlgorithmIdentifier algorithm, JS::NonnullGCPtr<CryptoKey> base_key, u32 length)
590
0
{
591
0
    auto& realm = this->realm();
592
    // 1. Let algorithm, baseKey and length, be the algorithm, baseKey and length parameters passed to the deriveBits() method, respectively.
593
594
    // 2. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set to algorithm and op set to "deriveBits".
595
0
    auto normalized_algorithm = normalize_an_algorithm(realm, algorithm, "deriveBits"_string);
596
597
    // 3. If an error occurred, return a Promise rejected with normalizedAlgorithm.
598
0
    if (normalized_algorithm.is_error())
599
0
        return WebIDL::create_rejected_promise_from_exception(realm, normalized_algorithm.release_error());
600
601
    // 4. Let promise be a new Promise object.
602
0
    auto promise = WebIDL::create_promise(realm);
603
604
    // 5. Return promise and perform the remaining steps in parallel.
605
0
    Platform::EventLoopPlugin::the().deferred_invoke([&realm, normalized_algorithm = normalized_algorithm.release_value(), promise, base_key, length]() -> void {
606
0
        HTML::TemporaryExecutionContext context(Bindings::host_defined_environment_settings_object(realm), HTML::TemporaryExecutionContext::CallbacksEnabled::Yes);
607
        // 6. If the following steps or referenced procedures say to throw an error, reject promise with the returned error and then terminate the algorithm.
608
609
        // 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.
610
0
        if (normalized_algorithm.parameter->name != base_key->algorithm_name()) {
611
0
            WebIDL::reject_promise(realm, promise, WebIDL::InvalidAccessError::create(realm, "Algorithm mismatch"_string));
612
0
            return;
613
0
        }
614
615
        // 8. If the [[usages]] internal slot of baseKey does not contain an entry that is "deriveBits", then throw an InvalidAccessError.
616
0
        if (!base_key->internal_usages().contains_slow(Bindings::KeyUsage::Derivebits)) {
617
0
            WebIDL::reject_promise(realm, promise, WebIDL::InvalidAccessError::create(realm, "Key does not support deriving bits"_string));
618
0
            return;
619
0
        }
620
621
        // 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.
622
0
        auto result = normalized_algorithm.methods->derive_bits(*normalized_algorithm.parameter, base_key, length);
623
0
        if (result.is_error()) {
624
0
            WebIDL::reject_promise(realm, promise, Bindings::dom_exception_to_throw_completion(realm.vm(), result.release_error()).release_value().value());
625
0
            return;
626
0
        }
627
628
        // 10. Resolve promise with result.
629
0
        WebIDL::resolve_promise(realm, promise, result.release_value());
630
0
    });
631
632
0
    return verify_cast<JS::Promise>(*promise->promise());
633
0
}
634
635
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)
636
0
{
637
0
    auto& realm = this->realm();
638
0
    auto& vm = this->vm();
639
    // 1. Let algorithm, baseKey, derivedKeyType, extractable and usages be the algorithm, baseKey, derivedKeyType, extractable and keyUsages parameters passed to the deriveKey() method, respectively.
640
641
    // 2. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set to algorithm and op set to "deriveBits".
642
0
    auto normalized_algorithm = normalize_an_algorithm(realm, algorithm, "deriveBits"_string);
643
644
    // 3. If an error occurred, return a Promise rejected with normalizedAlgorithm.
645
0
    if (normalized_algorithm.is_error())
646
0
        return WebIDL::create_rejected_promise_from_exception(realm, normalized_algorithm.release_error());
647
648
    // 4. Let normalizedDerivedKeyAlgorithmImport be the result of normalizing an algorithm, with alg set to derivedKeyType and op set to "importKey".
649
0
    auto normalized_derived_key_algorithm_import = normalize_an_algorithm(realm, derived_key_type, "importKey"_string);
650
651
    // 5. If an error occurred, return a Promise rejected with normalizedDerivedKeyAlgorithmImport.
652
0
    if (normalized_derived_key_algorithm_import.is_error())
653
0
        return WebIDL::create_rejected_promise_from_exception(realm, normalized_derived_key_algorithm_import.release_error());
654
655
    // 6. Let normalizedDerivedKeyAlgorithmLength be the result of normalizing an algorithm, with alg set to derivedKeyType and op set to "get key length".
656
0
    auto normalized_derived_key_algorithm_length = normalize_an_algorithm(realm, derived_key_type, "get key length"_string);
657
658
    // 7. If an error occurred, return a Promise rejected with normalizedDerivedKeyAlgorithmLength.
659
0
    if (normalized_derived_key_algorithm_length.is_error())
660
0
        return WebIDL::create_rejected_promise_from_exception(realm, normalized_derived_key_algorithm_length.release_error());
661
662
    // 8. Let promise be a new Promise.
663
0
    auto promise = WebIDL::create_promise(realm);
664
665
    // 9. Return promise and perform the remaining steps in parallel.
666
0
    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 {
667
0
        HTML::TemporaryExecutionContext context(Bindings::host_defined_environment_settings_object(realm), HTML::TemporaryExecutionContext::CallbacksEnabled::Yes);
668
        // 10. If the following steps or referenced procedures say to throw an error, reject promise with the returned error and then terminate the algorithm.
669
670
        // 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.
671
0
        if (normalized_algorithm.parameter->name != base_key->algorithm_name()) {
672
0
            WebIDL::reject_promise(realm, promise, WebIDL::InvalidAccessError::create(realm, "Algorithm mismatch"_string));
673
0
            return;
674
0
        }
675
676
        // 12. If the [[usages]] internal slot of baseKey does not contain an entry that is "deriveKey", then throw an InvalidAccessError.
677
0
        if (!base_key->internal_usages().contains_slow(Bindings::KeyUsage::Derivekey)) {
678
0
            WebIDL::reject_promise(realm, promise, WebIDL::InvalidAccessError::create(realm, "Key does not support deriving keys"_string));
679
0
            return;
680
0
        }
681
682
        // 13. Let length be the result of performing the get key length algorithm specified by normalizedDerivedKeyAlgorithmLength using derivedKeyType.
683
0
        auto length_result = normalized_derived_key_algorithm_length.methods->get_key_length(*normalized_derived_key_algorithm_length.parameter);
684
0
        if (length_result.is_error()) {
685
0
            WebIDL::reject_promise(realm, promise, Bindings::dom_exception_to_throw_completion(realm.vm(), length_result.release_error()).release_value().value());
686
0
            return;
687
0
        }
688
689
0
        auto length_raw_value = length_result.release_value();
690
0
        Optional<u32> length = {};
691
0
        if (length_raw_value.is_number()) {
692
0
            auto maybe_length = length_raw_value.to_u32(vm);
693
0
            if (!maybe_length.has_value()) {
694
0
                WebIDL::reject_promise(realm, promise, maybe_length.release_error().release_value().value());
695
0
                return;
696
0
            }
697
698
0
            length = maybe_length.value();
699
0
        }
700
701
        // 14. Let secret be the result of performing the derive bits operation specified by normalizedAlgorithm using key, algorithm and length.
702
0
        auto secret = normalized_algorithm.methods->derive_bits(*normalized_algorithm.parameter, base_key, length);
703
0
        if (secret.is_error()) {
704
0
            WebIDL::reject_promise(realm, promise, Bindings::dom_exception_to_throw_completion(realm.vm(), secret.release_error()).release_value().value());
705
0
            return;
706
0
        }
707
708
        // 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.
709
0
        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);
710
0
        if (result.is_error()) {
711
0
            WebIDL::reject_promise(realm, promise, Bindings::dom_exception_to_throw_completion(realm.vm(), result.release_error()).release_value().value());
712
0
            return;
713
0
        }
714
715
        // 16. If the [[type]] internal slot of result is "secret" or "private" and usages is empty, then throw a SyntaxError.
716
0
        if ((result.release_value()->type() == Bindings::KeyType::Secret || result.release_value()->type() == Bindings::KeyType::Private) && key_usages.is_empty()) {
717
0
            WebIDL::reject_promise(realm, promise, WebIDL::SyntaxError::create(realm, "usages must not be empty"_string));
718
0
            return;
719
0
        }
720
721
        // 17. Resolve promise with result.
722
0
        WebIDL::resolve_promise(realm, promise, result.release_value());
723
0
    });
724
725
0
    return verify_cast<JS::Promise>(*promise->promise());
726
0
}
727
728
SupportedAlgorithmsMap& supported_algorithms_internal()
729
0
{
730
0
    static SupportedAlgorithmsMap s_supported_algorithms;
731
0
    return s_supported_algorithms;
732
0
}
733
734
// https://w3c.github.io/webcrypto/#algorithm-normalization-internalS
735
SupportedAlgorithmsMap supported_algorithms()
736
0
{
737
0
    auto& internal_object = supported_algorithms_internal();
738
739
0
    if (!internal_object.is_empty()) {
740
0
        return internal_object;
741
0
    }
742
743
    // 1. For each value, v in the List of supported operations,
744
    // set the v key of the internal object supportedAlgorithms to a new associative container.
745
0
    auto supported_operations = Vector {
746
0
        "encrypt"_string,
747
0
        "decrypt"_string,
748
0
        "sign"_string,
749
0
        "verify"_string,
750
0
        "digest"_string,
751
0
        "deriveBits"_string,
752
0
        "wrapKey"_string,
753
0
        "unwrapKey"_string,
754
0
        "generateKey"_string,
755
0
        "importKey"_string,
756
0
        "exportKey"_string,
757
0
        "get key length"_string,
758
0
    };
759
760
0
    for (auto& operation : supported_operations) {
761
0
        internal_object.set(operation, {});
762
0
    }
763
764
    // https://w3c.github.io/webcrypto/#algorithm-conventions
765
    // https://w3c.github.io/webcrypto/#sha
766
0
    define_an_algorithm<SHA>("digest"_string, "SHA-1"_string);
767
0
    define_an_algorithm<SHA>("digest"_string, "SHA-256"_string);
768
0
    define_an_algorithm<SHA>("digest"_string, "SHA-384"_string);
769
0
    define_an_algorithm<SHA>("digest"_string, "SHA-512"_string);
770
771
    // https://w3c.github.io/webcrypto/#hkdf
772
0
    define_an_algorithm<HKDF>("importKey"_string, "HKDF"_string);
773
0
    define_an_algorithm<HKDF, HKDFParams>("deriveBits"_string, "HKDF"_string);
774
0
    define_an_algorithm<HKDF>("get key length"_string, "HKDF"_string);
775
776
    // https://w3c.github.io/webcrypto/#pbkdf2
777
0
    define_an_algorithm<PBKDF2>("importKey"_string, "PBKDF2"_string);
778
0
    define_an_algorithm<PBKDF2, PBKDF2Params>("deriveBits"_string, "PBKDF2"_string);
779
0
    define_an_algorithm<PBKDF2>("get key length"_string, "PBKDF2"_string);
780
781
    // https://w3c.github.io/webcrypto/#rsa-oaep
782
0
    define_an_algorithm<RSAOAEP, RsaHashedKeyGenParams>("generateKey"_string, "RSA-OAEP"_string);
783
0
    define_an_algorithm<RSAOAEP>("exportKey"_string, "RSA-OAEP"_string);
784
0
    define_an_algorithm<RSAOAEP, RsaHashedImportParams>("importKey"_string, "RSA-OAEP"_string);
785
0
    define_an_algorithm<RSAOAEP, RsaOaepParams>("encrypt"_string, "RSA-OAEP"_string);
786
0
    define_an_algorithm<RSAOAEP, RsaOaepParams>("decrypt"_string, "RSA-OAEP"_string);
787
788
    // https://w3c.github.io/webcrypto/#ecdsa
789
0
    define_an_algorithm<ECDSA, EcdsaParams>("sign"_string, "ECDSA"_string);
790
0
    define_an_algorithm<ECDSA, EcdsaParams>("verify"_string, "ECDSA"_string);
791
0
    define_an_algorithm<ECDSA, EcKeyGenParams>("generateKey"_string, "ECDSA"_string);
792
793
    // https://wicg.github.io/webcrypto-secure-curves/#ed25519
794
0
    define_an_algorithm<ED25519>("sign"_string, "Ed25519"_string);
795
0
    define_an_algorithm<ED25519>("verify"_string, "Ed25519"_string);
796
0
    define_an_algorithm<ED25519>("generateKey"_string, "Ed25519"_string);
797
798
0
    return internal_object;
799
0
}
800
801
// https://w3c.github.io/webcrypto/#concept-define-an-algorithm
802
template<typename Methods, typename Param>
803
void define_an_algorithm(AK::String op, AK::String algorithm)
804
0
{
805
0
    auto& internal_object = supported_algorithms_internal();
806
807
    // 1. Let registeredAlgorithms be the associative container stored at the op key of supportedAlgorithms.
808
    // NOTE: There should always be a container at the op key.
809
0
    auto maybe_registered_algorithms = internal_object.get(op);
810
0
    auto registered_algorithms = maybe_registered_algorithms.value();
811
812
    // 2. Set the alg key of registeredAlgorithms to the IDL dictionary type type.
813
0
    registered_algorithms.set(algorithm, RegisteredAlgorithm { &Methods::create, &Param::from_value });
814
0
    internal_object.set(op, registered_algorithms);
815
0
}
Unexecuted instantiation: SubtleCrypto.cpp:void Web::Crypto::define_an_algorithm<Web::Crypto::SHA, Web::Crypto::AlgorithmParams>(AK::String, AK::String)
Unexecuted instantiation: SubtleCrypto.cpp:void Web::Crypto::define_an_algorithm<Web::Crypto::HKDF, Web::Crypto::AlgorithmParams>(AK::String, AK::String)
Unexecuted instantiation: SubtleCrypto.cpp:void Web::Crypto::define_an_algorithm<Web::Crypto::HKDF, Web::Crypto::HKDFParams>(AK::String, AK::String)
Unexecuted instantiation: SubtleCrypto.cpp:void Web::Crypto::define_an_algorithm<Web::Crypto::PBKDF2, Web::Crypto::AlgorithmParams>(AK::String, AK::String)
Unexecuted instantiation: SubtleCrypto.cpp:void Web::Crypto::define_an_algorithm<Web::Crypto::PBKDF2, Web::Crypto::PBKDF2Params>(AK::String, AK::String)
Unexecuted instantiation: SubtleCrypto.cpp:void Web::Crypto::define_an_algorithm<Web::Crypto::RSAOAEP, Web::Crypto::RsaHashedKeyGenParams>(AK::String, AK::String)
Unexecuted instantiation: SubtleCrypto.cpp:void Web::Crypto::define_an_algorithm<Web::Crypto::RSAOAEP, Web::Crypto::AlgorithmParams>(AK::String, AK::String)
Unexecuted instantiation: SubtleCrypto.cpp:void Web::Crypto::define_an_algorithm<Web::Crypto::RSAOAEP, Web::Crypto::RsaHashedImportParams>(AK::String, AK::String)
Unexecuted instantiation: SubtleCrypto.cpp:void Web::Crypto::define_an_algorithm<Web::Crypto::RSAOAEP, Web::Crypto::RsaOaepParams>(AK::String, AK::String)
Unexecuted instantiation: SubtleCrypto.cpp:void Web::Crypto::define_an_algorithm<Web::Crypto::ECDSA, Web::Crypto::EcdsaParams>(AK::String, AK::String)
Unexecuted instantiation: SubtleCrypto.cpp:void Web::Crypto::define_an_algorithm<Web::Crypto::ECDSA, Web::Crypto::EcKeyGenParams>(AK::String, AK::String)
Unexecuted instantiation: SubtleCrypto.cpp:void Web::Crypto::define_an_algorithm<Web::Crypto::ED25519, Web::Crypto::AlgorithmParams>(AK::String, AK::String)
816
817
}