2021-12-13 19:09:55 -03:00
/*
2022-08-22 14:31:08 -03:00
* Copyright ( c ) 2021 - 2022 , Linus Groh < linusg @ serenityos . org >
2024-10-26 15:12:09 -03:00
* Copyright ( c ) 2023 - 2024 , stelar7 < dudedbz @ gmail . com >
2024-11-15 11:53:39 -03:00
* Copyright ( c ) 2024 , Jelle Raaijmakers < jelle @ ladybird . org >
2021-12-13 19:09:55 -03:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
2024-12-14 08:23:52 -03:00
# include <AK/ByteBuffer.h>
2026-06-04 05:40:32 -03:00
# include <AK/NeverDestroyed.h>
2024-03-06 23:11:08 -03:00
# include <AK/QuickSort.h>
2021-12-13 19:09:55 -03:00
# include <LibCrypto/Hash/HashManager.h>
# include <LibJS/Runtime/ArrayBuffer.h>
2024-12-14 08:23:52 -03:00
# include <LibJS/Runtime/JSONObject.h>
2025-04-09 07:29:53 -03:00
# include <LibJS/Runtime/ValueInlines.h>
2024-01-23 15:52:15 -03:00
# include <LibWeb/Bindings/ExceptionOrUtils.h>
LibWeb: Remove unecessary dependence on Window from assorted classes
These classes only needed Window to get at its realm. Pass a realm
directly to construct Crypto, Encoding, HRT, IntersectionObserver,
NavigationTiming, Page, RequestIdleCallback, Selection, Streams, URL,
and XML classes.
2022-09-25 21:11:21 -03:00
# include <LibWeb/Bindings/Intrinsics.h>
2026-04-18 05:54:06 -03:00
# include <LibWeb/Bindings/SubtleCrypto.h>
2024-03-14 00:19:57 -03:00
# include <LibWeb/Crypto/KeyAlgorithms.h>
2021-12-13 19:09:55 -03:00
# include <LibWeb/Crypto/SubtleCrypto.h>
2024-01-23 15:52:15 -03:00
# include <LibWeb/HTML/Scripting/TemporaryExecutionContext.h>
# include <LibWeb/Platform/EventLoopPlugin.h>
2022-09-24 12:14:37 -03:00
# include <LibWeb/WebIDL/AbstractOperations.h>
2023-11-23 04:07:25 -03:00
# include <LibWeb/WebIDL/Buffers.h>
2023-02-12 17:25:57 -03:00
# include <LibWeb/WebIDL/ExceptionOr.h>
2024-01-23 15:52:15 -03:00
# include <LibWeb/WebIDL/Promise.h>
2021-12-13 19:09:55 -03:00
namespace Web : : Crypto {
2024-03-06 23:11:08 -03:00
static void normalize_key_usages ( Vector < Bindings : : KeyUsage > & key_usages )
{
quick_sort ( key_usages ) ;
}
2026-05-01 14:01:23 -03:00
static JsonWebKey to_internal_json_web_key ( Bindings : : JsonWebKey bindings_jwk )
{
2026-06-21 14:03:10 -03:00
auto to_utf16 = [ ] ( Optional < String > value ) - > Optional < Utf16String > {
if ( ! value . has_value ( ) )
return { } ;
return Utf16String : : from_utf8 ( value . release_value ( ) ) ;
} ;
auto to_utf16_vector = [ ] ( Optional < Vector < String > > values ) - > Optional < Vector < Utf16String > > {
if ( ! values . has_value ( ) )
return { } ;
Vector < Utf16String > result ;
result . ensure_capacity ( values - > size ( ) ) ;
for ( auto & value : * values )
result . unchecked_append ( Utf16String : : from_utf8 ( value ) ) ;
return result ;
} ;
2026-05-01 14:01:23 -03:00
JsonWebKey jwk ;
2026-06-21 14:03:10 -03:00
jwk . alg = to_utf16 ( move ( bindings_jwk . alg ) ) ;
jwk . crv = to_utf16 ( move ( bindings_jwk . crv ) ) ;
jwk . d = to_utf16 ( move ( bindings_jwk . d ) ) ;
jwk . dp = to_utf16 ( move ( bindings_jwk . dp ) ) ;
jwk . dq = to_utf16 ( move ( bindings_jwk . dq ) ) ;
jwk . e = to_utf16 ( move ( bindings_jwk . e ) ) ;
2026-05-01 14:01:23 -03:00
jwk . ext = move ( bindings_jwk . ext ) ;
2026-06-21 14:03:10 -03:00
jwk . k = to_utf16 ( move ( bindings_jwk . k ) ) ;
jwk . key_ops = to_utf16_vector ( move ( bindings_jwk . key_ops ) ) ;
jwk . kty = to_utf16 ( move ( bindings_jwk . kty ) ) ;
jwk . n = to_utf16 ( move ( bindings_jwk . n ) ) ;
2026-05-01 14:01:23 -03:00
if ( bindings_jwk . oth . has_value ( ) ) {
Vector < RsaOtherPrimesInfo > oth ;
oth . ensure_capacity ( bindings_jwk . oth - > size ( ) ) ;
for ( auto & bindings_prime : * bindings_jwk . oth ) {
2026-06-21 14:03:10 -03:00
oth . append ( { . r = to_utf16 ( move ( bindings_prime . r ) ) , . d = to_utf16 ( move ( bindings_prime . d ) ) , . t = to_utf16 ( move ( bindings_prime . t ) ) } ) ;
2026-05-01 14:01:23 -03:00
}
jwk . oth = move ( oth ) ;
}
2026-06-21 14:03:10 -03:00
jwk . p = to_utf16 ( move ( bindings_jwk . p ) ) ;
jwk . priv = to_utf16 ( move ( bindings_jwk . priv ) ) ;
jwk . pub = to_utf16 ( move ( bindings_jwk . pub ) ) ;
jwk . q = to_utf16 ( move ( bindings_jwk . q ) ) ;
jwk . qi = to_utf16 ( move ( bindings_jwk . qi ) ) ;
jwk . use = to_utf16 ( move ( bindings_jwk . use ) ) ;
jwk . x = to_utf16 ( move ( bindings_jwk . x ) ) ;
jwk . y = to_utf16 ( move ( bindings_jwk . y ) ) ;
2026-05-01 14:01:23 -03:00
return jwk ;
}
2024-03-15 00:52:17 -03:00
struct RegisteredAlgorithm {
NonnullOwnPtr < AlgorithmMethods > ( * create_methods ) ( JS : : Realm & ) = nullptr ;
JS : : ThrowCompletionOr < NonnullOwnPtr < AlgorithmParams > > ( * parameter_from_value ) ( JS : : VM & , JS : : Value ) = nullptr ;
} ;
using SupportedAlgorithmsMap = HashMap < String , HashMap < String , RegisteredAlgorithm , AK : : ASCIICaseInsensitiveStringTraits > > ;
static SupportedAlgorithmsMap & supported_algorithms_internal ( ) ;
2024-11-24 16:53:41 -03:00
static SupportedAlgorithmsMap const & supported_algorithms ( ) ;
2024-03-15 00:52:17 -03:00
template < typename Methods , typename Param = AlgorithmParams >
static void define_an_algorithm ( String op , String algorithm ) ;
2024-03-06 23:11:08 -03:00
2024-11-14 12:01:23 -03:00
GC_DEFINE_ALLOCATOR ( SubtleCrypto ) ;
2023-11-19 15:47:52 -03:00
2024-11-14 12:01:23 -03:00
GC : : Ref < SubtleCrypto > SubtleCrypto : : create ( JS : : Realm & realm )
2022-09-03 14:59:53 -03:00
{
2024-11-13 13:50:17 -03:00
return realm . create < SubtleCrypto > ( realm ) ;
2022-09-03 14:59:53 -03:00
}
LibWeb: Remove unecessary dependence on Window from assorted classes
These classes only needed Window to get at its realm. Pass a realm
directly to construct Crypto, Encoding, HRT, IntersectionObserver,
NavigationTiming, Page, RequestIdleCallback, Selection, Streams, URL,
and XML classes.
2022-09-25 21:11:21 -03:00
SubtleCrypto : : SubtleCrypto ( JS : : Realm & realm )
: PlatformObject ( realm )
2022-09-03 14:59:53 -03:00
{
}
SubtleCrypto : : ~ SubtleCrypto ( ) = default ;
2023-08-07 03:41:28 -03:00
void SubtleCrypto : : initialize ( JS : : Realm & realm )
2023-01-10 08:28:20 -03:00
{
2024-03-16 09:13:08 -03:00
WEB_SET_PROTOTYPE_FOR_INTERFACE ( SubtleCrypto ) ;
2025-04-20 11:22:57 -03:00
Base : : initialize ( realm ) ;
2023-01-10 08:28:20 -03:00
}
2023-12-13 20:38:14 -03:00
// https://w3c.github.io/webcrypto/#dfn-normalize-an-algorithm
2024-03-15 00:52:17 -03:00
WebIDL : : ExceptionOr < NormalizedAlgorithmAndParameter > normalize_an_algorithm ( JS : : Realm & realm , AlgorithmIdentifier const & algorithm , String operation )
2023-12-13 20:38:14 -03:00
{
2024-03-15 00:52:17 -03:00
auto & vm = realm . vm ( ) ;
2023-12-13 20:38:14 -03:00
// If alg is an instance of a DOMString:
if ( algorithm . has < String > ( ) ) {
// Return the result of running the normalize an algorithm algorithm,
// with the alg set to a new Algorithm dictionary whose name attribute is alg, and with the op set to op.
2026-05-20 15:58:46 -03:00
auto dictionary = JS : : Object : : create ( realm , realm . intrinsics ( ) . object_prototype ( ) ) ;
2026-06-21 14:03:10 -03:00
TRY ( dictionary - > create_data_property ( " name " _utf16_fly_string , JS : : PrimitiveString : : create ( vm , Utf16String : : from_utf8 ( algorithm . get < String > ( ) ) ) ) ) ;
2024-03-15 00:52:17 -03:00
return normalize_an_algorithm ( realm , dictionary , operation ) ;
2023-12-13 20:38:14 -03:00
}
// If alg is an object:
// 1. Let registeredAlgorithms be the associative container stored at the op key of supportedAlgorithms.
// NOTE: There should always be a container at the op key.
2024-11-24 16:53:41 -03:00
auto const & internal_object = supported_algorithms ( ) ;
2023-12-13 20:38:14 -03:00
auto maybe_registered_algorithms = internal_object . get ( operation ) ;
auto registered_algorithms = maybe_registered_algorithms . value ( ) ;
// 2. Let initialAlg be the result of converting the ECMAScript object represented by alg to
// the IDL dictionary type Algorithm, as defined by [WebIDL].
// 3. If an error occurred, return the error and terminate this algorithm.
2024-03-06 20:53:50 -03:00
// Note: We're not going to bother creating an Algorithm object, all we want is the name attribute so that we can
// fetch the actual algorithm factory from the registeredAlgorithms map.
2026-05-20 15:58:46 -03:00
auto initial_algorithm = TRY ( algorithm . get < GC : : Ref < JS : : Object > > ( ) - > get ( " name " _utf16_fly_string ) ) ;
2023-12-13 20:38:14 -03:00
2024-11-24 18:06:59 -03:00
if ( initial_algorithm . is_undefined ( ) ) {
return vm . throw_completion < JS : : TypeError > ( JS : : ErrorType : : NotAnObjectOfType , " Algorithm " ) ;
}
2023-12-13 20:38:14 -03:00
// 4. Let algName be the value of the name attribute of initialAlg.
2026-06-21 14:03:01 -03:00
auto algorithm_name = TRY ( initial_algorithm . to_utf16_string ( vm ) ) . to_utf8_but_should_be_ported_to_utf16 ( ) ;
2023-12-13 20:38:14 -03:00
2024-03-06 20:53:50 -03:00
RegisteredAlgorithm desired_type ;
2023-12-13 20:38:14 -03:00
// 5. If registeredAlgorithms contains a key that is a case-insensitive string match for algName:
2024-03-06 20:53:50 -03:00
if ( auto it = registered_algorithms . find ( algorithm_name ) ; it ! = registered_algorithms . end ( ) ) {
2023-12-13 20:38:14 -03:00
// 1. Set algName to the value of the matching key.
2024-11-27 17:17:07 -03:00
algorithm_name = it - > key ;
2023-12-13 20:38:14 -03:00
// 2. Let desiredType be the IDL dictionary type stored at algName in registeredAlgorithms.
2024-03-06 20:53:50 -03:00
desired_type = it - > value ;
2023-12-13 20:38:14 -03:00
} else {
// Otherwise:
// Return a new NotSupportedError and terminate this algorithm.
2025-08-07 20:31:52 -03:00
return WebIDL : : NotSupportedError : : create ( realm , Utf16String : : formatted ( " Algorithm '{}' is not supported for operation '{}' " , algorithm_name , operation ) ) ;
2023-12-13 20:38:14 -03:00
}
// 8. Let normalizedAlgorithm be the result of converting the ECMAScript object represented by alg
// to the IDL dictionary type desiredType, as defined by [WebIDL].
// 10. If an error occurred, return the error and terminate this algorithm.
2024-03-06 20:53:50 -03:00
// 11. Let dictionaries be a list consisting of the IDL dictionary type desiredType
2023-12-13 20:38:14 -03:00
// and all of desiredType's inherited dictionaries, in order from least to most derived.
2024-03-06 20:53:50 -03:00
// 12. For each dictionary dictionary in dictionaries:
// Note: All of these steps are handled by the create_methods and parameter_from_value methods.
auto methods = desired_type . create_methods ( realm ) ;
2026-05-20 15:58:46 -03:00
auto parameter = TRY ( desired_type . parameter_from_value ( vm , algorithm . get < GC : : Ref < JS : : Object > > ( ) ) ) ;
2024-11-27 17:17:07 -03:00
// 9. Set the name attribute of normalizedAlgorithm to algName.
VERIFY ( parameter - > name . is_empty ( ) ) ;
parameter - > name = algorithm_name ;
2024-03-06 20:53:50 -03:00
auto normalized_algorithm = NormalizedAlgorithmAndParameter { move ( methods ) , move ( parameter ) } ;
2023-12-13 20:38:14 -03:00
// 13. Return normalizedAlgorithm.
return normalized_algorithm ;
}
2026-03-03 04:47:00 -03:00
// https://w3c.github.io/webcrypto/#SubtleCrypto-method-encrypt
2026-05-28 18:14:33 -03:00
GC : : Ref < WebIDL : : Promise > SubtleCrypto : : encrypt ( AlgorithmIdentifier const & algorithm , GC : : Ref < CryptoKey > key , WebIDL : : BufferSource data_parameter )
2024-03-15 01:39:48 -03:00
{
auto & realm = this - > realm ( ) ;
auto & vm = this - > vm ( ) ;
2026-03-03 04:47:00 -03:00
auto & global = realm . global_object ( ) ;
auto & heap = realm . heap ( ) ;
2024-03-15 01:39:48 -03:00
// 1. Let algorithm and key be the algorithm and key parameters passed to the encrypt() method, respectively.
2026-03-03 04:47:00 -03:00
// 2. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set to algorithm and op set to "encrypt".
auto normalized_algorithm = normalize_an_algorithm ( realm , algorithm , " encrypt " _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 data be the result of getting a copy of the bytes held by the data parameter passed to the encrypt() method.
2026-05-28 18:14:33 -03:00
auto data_or_error = WebIDL : : get_buffer_source_copy ( data_parameter ) ;
2024-03-15 01:39:48 -03:00
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 ( ) ;
2026-03-03 04:47:00 -03:00
// 5. Let realm be the relevant realm of this.
2024-03-15 01:39:48 -03:00
2026-03-03 04:47:00 -03:00
// 6. Let promise be a new Promise.
2024-03-15 01:39:48 -03:00
auto promise = WebIDL : : create_promise ( realm ) ;
2026-03-03 04:47:00 -03:00
// 7. Return promise and perform the remaining steps in parallel.
Platform : : EventLoopPlugin : : the ( ) . deferred_invoke ( GC : : create_function ( realm . heap ( ) , [ & realm , & global , & heap , normalized_algorithm = normalized_algorithm . release_value ( ) , promise , key , data = move ( data ) ] ( ) - > void {
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : No ) ;
2024-03-15 01:39:48 -03:00
2026-03-03 04:47:00 -03:00
// 8. If the following steps or referenced procedures say to throw an error, queue a global task on the
// crypto task source, given realm's global object, to reject promise with the returned error and then terminate the algorithm.
auto const throw_in_this_context = [ & realm , & global , & heap , & promise ] ( JS : : Value value ) {
HTML : : queue_global_task ( HTML : : Task : : Source : : Crypto , global , GC : : create_function ( heap , [ & realm , promise , value ] {
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
WebIDL : : reject_promise ( realm , promise , value ) ;
} ) ) ;
} ;
2024-03-15 01:39:48 -03:00
2026-03-03 04:47:00 -03:00
// 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.
2024-03-15 01:39:48 -03:00
if ( normalized_algorithm . parameter - > name ! = key - > algorithm_name ( ) ) {
2026-03-03 04:47:00 -03:00
throw_in_this_context ( WebIDL : : InvalidAccessError : : create ( realm , " Algorithm mismatch " _utf16 ) ) ;
2024-03-15 01:39:48 -03:00
return ;
}
2026-03-03 04:47:00 -03:00
// 10. If the [[usages]] internal slot of key does not contain an entry that is "encrypt", then throw an InvalidAccessError.
2024-03-15 01:39:48 -03:00
if ( ! key - > internal_usages ( ) . contains_slow ( Bindings : : KeyUsage : : Encrypt ) ) {
2026-03-03 04:47:00 -03:00
throw_in_this_context ( WebIDL : : InvalidAccessError : : create ( realm , " Key does not support encryption " _utf16 ) ) ;
2024-03-15 01:39:48 -03:00
return ;
}
2026-03-03 04:47:00 -03:00
// 11. Let ciphertext be the result of performing the encrypt operation specified by normalizedAlgorithm using algorithm and key and with data as plaintext.
2024-03-15 01:39:48 -03:00
auto cipher_text = normalized_algorithm . methods - > encrypt ( * normalized_algorithm . parameter , key , data ) ;
if ( cipher_text . is_error ( ) ) {
2026-03-03 04:47:00 -03:00
throw_in_this_context ( Bindings : : exception_to_throw_completion ( realm . vm ( ) , cipher_text . release_error ( ) ) . release_value ( ) ) ;
2024-03-15 01:39:48 -03:00
return ;
}
2026-03-03 04:47:00 -03:00
// 12. Queue a global task on the crypto task source, given realm's global object, to perform the remaining steps.
HTML : : queue_global_task ( HTML : : Task : : Source : : Crypto , global , GC : : create_function ( heap , [ & realm , promise , cipher_text_bytes = cipher_text . release_value ( ) ] {
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
// 13. Let result be the result of creating an ArrayBuffer in realm, containing ciphertext.
// 14. Resolve promise with result.
WebIDL : : resolve_promise ( realm , promise , cipher_text_bytes ) ;
} ) ) ;
2024-10-30 10:39:29 -03:00
} ) ) ;
2024-03-15 01:39:48 -03:00
2024-10-25 15:38:19 -03:00
return promise ;
2024-03-15 01:39:48 -03:00
}
2026-03-03 04:47:00 -03:00
// https://w3c.github.io/webcrypto/#SubtleCrypto-method-decrypt
2026-05-28 18:14:33 -03:00
GC : : Ref < WebIDL : : Promise > SubtleCrypto : : decrypt ( AlgorithmIdentifier const & algorithm , GC : : Ref < CryptoKey > key , WebIDL : : BufferSource data_parameter )
2024-03-15 01:47:06 -03:00
{
auto & realm = this - > realm ( ) ;
auto & vm = this - > vm ( ) ;
2026-03-03 04:47:00 -03:00
auto & global = realm . global_object ( ) ;
auto & heap = realm . heap ( ) ;
2024-03-15 01:47:06 -03:00
// 1. Let algorithm and key be the algorithm and key parameters passed to the decrypt() method, respectively.
2026-03-03 04:47:00 -03:00
// 2. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set to algorithm and op set to "decrypt".
auto normalized_algorithm = normalize_an_algorithm ( realm , algorithm , " decrypt " _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 data be the result of getting a copy of the bytes held by the data parameter passed to the decrypt() method.
2026-05-28 18:14:33 -03:00
auto data_or_error = WebIDL : : get_buffer_source_copy ( data_parameter ) ;
2024-03-15 01:47:06 -03:00
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 ( ) ;
2026-03-03 04:47:00 -03:00
// 5. Let realm be the relevant realm of this.
2024-03-15 01:47:06 -03:00
2026-03-03 04:47:00 -03:00
// 6. Let promise be a new Promise.
2024-03-15 01:47:06 -03:00
auto promise = WebIDL : : create_promise ( realm ) ;
2026-03-03 04:47:00 -03:00
// 7. Return promise and perform the remaining steps in parallel.
Platform : : EventLoopPlugin : : the ( ) . deferred_invoke ( GC : : create_function ( realm . heap ( ) , [ & realm , & global , & heap , normalized_algorithm = normalized_algorithm . release_value ( ) , promise , key , data = move ( data ) ] ( ) - > void {
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : No ) ;
2024-03-15 01:47:06 -03:00
2026-03-03 04:47:00 -03:00
// 8. If the following steps or referenced procedures say to throw an error, queue a global task on the
// crypto task source, given realm's global object, to reject promise with the returned error and then terminate the algorithm.
auto const throw_in_this_context = [ & realm , & global , & heap , & promise ] ( JS : : Value value ) {
HTML : : queue_global_task ( HTML : : Task : : Source : : Crypto , global , GC : : create_function ( heap , [ & realm , promise , value ] {
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
WebIDL : : reject_promise ( realm , promise , value ) ;
} ) ) ;
} ;
2024-03-15 01:47:06 -03:00
2026-03-03 04:47:00 -03:00
// 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.
2024-03-15 01:47:06 -03:00
if ( normalized_algorithm . parameter - > name ! = key - > algorithm_name ( ) ) {
2026-03-03 04:47:00 -03:00
throw_in_this_context ( WebIDL : : InvalidAccessError : : create ( realm , " Algorithm mismatch " _utf16 ) ) ;
2024-03-15 01:47:06 -03:00
return ;
}
2026-03-03 04:47:00 -03:00
// 10. If the [[usages]] internal slot of key does not contain an entry that is "decrypt", then throw an InvalidAccessError.
2024-03-15 01:47:06 -03:00
if ( ! key - > internal_usages ( ) . contains_slow ( Bindings : : KeyUsage : : Decrypt ) ) {
2026-03-03 04:47:00 -03:00
throw_in_this_context ( WebIDL : : InvalidAccessError : : create ( realm , " Key does not support decryption " _utf16 ) ) ;
2024-03-15 01:47:06 -03:00
return ;
}
2026-03-03 04:47:00 -03:00
// 11. Let plaintext be the result of performing the decrypt operation specified by normalizedAlgorithm using key and algorithm and with data as ciphertext.
2024-03-15 01:47:06 -03:00
auto plain_text = normalized_algorithm . methods - > decrypt ( * normalized_algorithm . parameter , key , data ) ;
if ( plain_text . is_error ( ) ) {
2026-03-03 04:47:00 -03:00
throw_in_this_context ( Bindings : : exception_to_throw_completion ( realm . vm ( ) , plain_text . release_error ( ) ) . release_value ( ) ) ;
2024-03-15 01:47:06 -03:00
return ;
}
2026-03-03 04:47:00 -03:00
// 12. Queue a global task on the crypto task source, given realm's global object, to perform the remaining steps.
HTML : : queue_global_task ( HTML : : Task : : Source : : Crypto , global , GC : : create_function ( heap , [ & realm , promise , plain_text_bytes = plain_text . release_value ( ) ] {
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
// 13. Let result be the result of creating an ArrayBuffer in realm, containing plaintext.
// 14. Resolve promise with result.
WebIDL : : resolve_promise ( realm , promise , plain_text_bytes ) ;
} ) ) ;
2024-10-30 10:39:29 -03:00
} ) ) ;
2024-03-15 01:47:06 -03:00
2024-10-25 15:38:19 -03:00
return promise ;
2024-03-15 01:47:06 -03:00
}
LibWeb: Remove unecessary dependence on Window from assorted classes
These classes only needed Window to get at its realm. Pass a realm
directly to construct Crypto, Encoding, HRT, IntersectionObserver,
NavigationTiming, Page, RequestIdleCallback, Selection, Streams, URL,
and XML classes.
2022-09-25 21:11:21 -03:00
// https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-digest
2026-05-28 18:14:33 -03:00
GC : : Ref < WebIDL : : Promise > SubtleCrypto : : digest ( AlgorithmIdentifier const & algorithm , WebIDL : : BufferSource data )
2021-12-13 19:09:55 -03:00
{
LibWeb: Remove unecessary dependence on Window from assorted classes
These classes only needed Window to get at its realm. Pass a realm
directly to construct Crypto, Encoding, HRT, IntersectionObserver,
NavigationTiming, Page, RequestIdleCallback, Selection, Streams, URL,
and XML classes.
2022-09-25 21:11:21 -03:00
auto & realm = this - > realm ( ) ;
2024-03-15 01:38:09 -03:00
auto & vm = this - > vm ( ) ;
2026-02-28 19:21:20 -03:00
auto & global = realm . global_object ( ) ;
auto & heap = realm . heap ( ) ;
2021-12-13 19:09:55 -03:00
// 1. Let algorithm be the algorithm parameter passed to the digest() method.
2026-02-28 19:21:20 -03:00
// 2. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set to algorithm and op set to "digest".
auto normalized_algorithm = normalize_an_algorithm ( realm , algorithm , " digest " _string ) ;
// 3. If an error occurred, return a Promise rejected with normalizedAlgorithm.
// FIXME: Spec bug: link to https://webidl.spec.whatwg.org/#a-promise-rejected-with
if ( normalized_algorithm . is_error ( ) )
return WebIDL : : create_rejected_promise_from_exception ( realm , normalized_algorithm . release_error ( ) ) ;
// 4. Let data be the result of getting a copy of the bytes held by the data parameter passed to the digest() method.
2026-05-28 18:14:33 -03:00
auto data_buffer_or_error = WebIDL : : get_buffer_source_copy ( data ) ;
2024-03-15 01:38:09 -03:00
if ( data_buffer_or_error . is_error ( ) ) {
VERIFY ( data_buffer_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 ) ) ) ;
}
2024-01-23 15:52:15 -03:00
auto data_buffer = data_buffer_or_error . release_value ( ) ;
2021-12-13 19:09:55 -03:00
2026-02-28 19:21:20 -03:00
// 5. Let realm be the relevant realm of this.
2021-12-13 19:09:55 -03:00
2026-02-28 19:21:20 -03:00
// 6. Let promise be a new Promise.
2024-01-23 15:52:15 -03:00
auto promise = WebIDL : : create_promise ( realm ) ;
2021-12-13 19:09:55 -03:00
2026-02-28 19:21:20 -03:00
// 7. Return promise and perform the remaining steps in parallel.
Platform : : EventLoopPlugin : : the ( ) . deferred_invoke ( GC : : create_function ( realm . heap ( ) , [ & realm , & global , & heap , algorithm_object = normalized_algorithm . release_value ( ) , promise , data_buffer = move ( data_buffer ) ] ( ) - > void {
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : No ) ;
2024-01-23 15:52:15 -03:00
2026-02-28 19:21:20 -03:00
// 8. If the following steps or referenced procedures say to throw an error, queue a global task on the
// crypto task source, given realm's global object, to reject promise with the returned error and then terminate the algorithm.
auto const throw_in_this_context = [ & realm , & global , & heap , & promise ] ( JS : : Value value ) {
HTML : : queue_global_task ( HTML : : Task : : Source : : Crypto , global , GC : : create_function ( heap , [ & realm , promise , value ] {
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
WebIDL : : reject_promise ( realm , promise , value ) ;
} ) ) ;
} ;
// 9. Let digest be the result of performing the digest operation specified by normalizedAlgorithm using algorithm, with data as message.
auto digest = algorithm_object . methods - > digest ( * algorithm_object . parameter , data_buffer ) ;
2024-01-23 15:52:15 -03:00
2026-02-28 19:21:20 -03:00
if ( digest . is_exception ( ) ) {
throw_in_this_context ( Bindings : : exception_to_throw_completion ( realm . vm ( ) , digest . release_error ( ) ) . release_value ( ) ) ;
2024-01-23 15:52:15 -03:00
return ;
}
2026-02-28 19:21:20 -03:00
// 10. Queue a global task on the crypto task source, given realm's global object, to perform the remaining steps.
HTML : : queue_global_task ( HTML : : Task : : Source : : Crypto , global , GC : : create_function ( heap , [ & realm , promise , digest_bytes = digest . release_value ( ) ] {
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
// 11. Let result be the result of creating an ArrayBuffer in realm, containing digest.
// 12. Resolve promise with result.
WebIDL : : resolve_promise ( realm , promise , digest_bytes ) ;
} ) ) ;
2024-10-30 10:39:29 -03:00
} ) ) ;
2024-01-23 15:52:15 -03:00
2024-10-25 15:38:19 -03:00
return promise ;
2021-12-13 19:09:55 -03:00
}
2024-03-06 23:15:03 -03:00
// https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-generateKey
2025-01-31 07:18:03 -03:00
GC : : Ref < WebIDL : : Promise > SubtleCrypto : : generate_key ( AlgorithmIdentifier algorithm , bool extractable , Vector < Bindings : : KeyUsage > key_usages )
2024-03-06 23:15:03 -03:00
{
auto & realm = this - > realm ( ) ;
// 1. Let algorithm, extractable and usages be the algorithm, extractable and keyUsages
// parameters passed to the generateKey() method, respectively.
// 2. Let normalizedAlgorithm be the result of normalizing an algorithm,
// with alg set to algorithm and op set to "generateKey".
2024-03-15 00:52:17 -03:00
auto normalized_algorithm = normalize_an_algorithm ( realm , algorithm , " generateKey " _string ) ;
2024-03-06 23:15:03 -03:00
// 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.
auto promise = WebIDL : : create_promise ( realm ) ;
// 5. Return promise and perform the remaining steps in parallel.
2024-11-14 12:01:23 -03:00
Platform : : EventLoopPlugin : : the ( ) . deferred_invoke ( GC : : create_function ( realm . heap ( ) , [ & realm , normalized_algorithm = normalized_algorithm . release_value ( ) , promise , extractable , key_usages = move ( key_usages ) ] ( ) - > void {
2024-10-24 04:39:18 -03:00
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
2024-03-06 23:15:03 -03:00
// 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. Let result be the result of performing the generate key operation specified by normalizedAlgorithm
// using algorithm, extractable and usages.
auto result_or_error = normalized_algorithm . methods - > generate_key ( * normalized_algorithm . parameter , extractable , key_usages ) ;
if ( result_or_error . is_error ( ) ) {
2025-04-04 13:11:45 -03:00
WebIDL : : reject_promise ( realm , promise , Bindings : : exception_to_throw_completion ( realm . vm ( ) , result_or_error . release_error ( ) ) . release_value ( ) ) ;
2024-03-06 23:15:03 -03:00
return ;
}
auto result = result_or_error . release_value ( ) ;
// 8. If result is a CryptoKey object:
// If the [[type]] internal slot of result is "secret" or "private" and usages is empty, then throw a SyntaxError.
// If result is a CryptoKeyPair object:
// If the [[usages]] internal slot of the privateKey attribute of result is the empty sequence, then throw a SyntaxError.
// 9. Resolve promise with result.
result . visit (
2024-11-14 12:01:23 -03:00
[ & ] ( GC : : Ref < CryptoKey > & key ) {
2024-03-06 23:15:03 -03:00
if ( ( key - > type ( ) = = Bindings : : KeyType : : Secret | | key - > type ( ) = = Bindings : : KeyType : : Private ) & & key_usages . is_empty ( ) ) {
2025-08-07 20:31:52 -03:00
WebIDL : : reject_promise ( realm , promise , WebIDL : : SyntaxError : : create ( realm , " usages must not be empty " _utf16 ) ) ;
2024-03-06 23:15:03 -03:00
return ;
}
WebIDL : : resolve_promise ( realm , promise , key ) ;
} ,
2024-11-14 12:01:23 -03:00
[ & ] ( GC : : Ref < CryptoKeyPair > & key_pair ) {
2024-03-06 23:15:03 -03:00
if ( key_pair - > private_key ( ) - > internal_usages ( ) . is_empty ( ) ) {
2025-08-07 20:31:52 -03:00
WebIDL : : reject_promise ( realm , promise , WebIDL : : SyntaxError : : create ( realm , " usages must not be empty " _utf16 ) ) ;
2024-03-06 23:15:03 -03:00
return ;
}
WebIDL : : resolve_promise ( realm , promise , key_pair ) ;
} ) ;
2024-10-30 10:39:29 -03:00
} ) ) ;
2024-03-06 23:15:03 -03:00
2024-10-25 15:38:19 -03:00
return promise ;
2024-03-06 23:15:03 -03:00
}
2023-12-15 18:03:04 -03:00
// https://w3c.github.io/webcrypto/#SubtleCrypto-method-importKey
2026-05-28 18:14:33 -03:00
JS : : ThrowCompletionOr < GC : : Ref < WebIDL : : Promise > > SubtleCrypto : : import_key ( Bindings : : KeyFormat format , ImportKeyData key_data , AlgorithmIdentifier algorithm , bool extractable , Vector < Bindings : : KeyUsage > key_usages )
2023-12-15 18:03:04 -03:00
{
auto & realm = this - > realm ( ) ;
// 1. Let format, algorithm, extractable and usages, be the format, algorithm, extractable
// and key_usages parameters passed to the importKey() method, respectively.
2026-04-22 09:42:24 -03:00
Variant < ByteBuffer , JsonWebKey , Empty > real_key_data ;
2023-12-15 18:03:04 -03:00
// 2. If format is equal to the string "raw", "pkcs8", or "spki":
2025-11-26 22:44:01 -03:00
if ( format = = Bindings : : KeyFormat : : Raw
| | format = = Bindings : : KeyFormat : : RawPublic
| | format = = Bindings : : KeyFormat : : RawPrivate
| | format = = Bindings : : KeyFormat : : RawSeed
| | format = = Bindings : : KeyFormat : : RawSecret
| | format = = Bindings : : KeyFormat : : Pkcs8
| | format = = Bindings : : KeyFormat : : Spki ) {
2023-12-15 18:03:04 -03:00
// 1. If the keyData parameter passed to the importKey() method is a JsonWebKey dictionary, throw a TypeError.
2026-05-01 14:01:23 -03:00
if ( key_data . has < Bindings : : JsonWebKey > ( ) ) {
2023-12-15 18:03:04 -03:00
return realm . vm ( ) . throw_completion < JS : : TypeError > ( JS : : ErrorType : : NotAnObjectOfType , " BufferSource " ) ;
}
// 2. Let keyData be the result of getting a copy of the bytes held by the keyData parameter passed to the importKey() method.
2026-05-28 18:14:33 -03:00
real_key_data = MUST ( WebIDL : : get_buffer_source_copy ( key_data . downcast < WebIDL : : BufferSourceVariant > ( ) ) ) ;
2023-12-15 18:03:04 -03:00
}
if ( format = = Bindings : : KeyFormat : : Jwk ) {
// 1. If the keyData parameter passed to the importKey() method is not a JsonWebKey dictionary, throw a TypeError.
2026-05-01 14:01:23 -03:00
if ( ! key_data . has < Bindings : : JsonWebKey > ( ) ) {
2023-12-15 18:03:04 -03:00
return realm . vm ( ) . throw_completion < JS : : TypeError > ( JS : : ErrorType : : NotAnObjectOfType , " JsonWebKey " ) ;
}
// 2. Let keyData be the keyData parameter passed to the importKey() method.
2026-05-01 14:01:23 -03:00
real_key_data = to_internal_json_web_key ( key_data . get < Bindings : : JsonWebKey > ( ) ) ;
2023-12-15 18:03:04 -03:00
}
// NOTE: The spec jumps to 5 here for some reason?
// 5. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set to algorithm and op set to "importKey".
2024-03-15 00:52:17 -03:00
auto normalized_algorithm = normalize_an_algorithm ( realm , algorithm , " importKey " _string ) ;
2023-12-15 18:03:04 -03:00
// 6. If an error occurred, return a Promise rejected with normalizedAlgorithm.
2024-03-08 12:37:28 -03:00
if ( normalized_algorithm . is_error ( ) )
return WebIDL : : create_rejected_promise_from_exception ( realm , normalized_algorithm . release_error ( ) ) ;
2023-12-15 18:03:04 -03:00
// 7. Let promise be a new Promise.
auto promise = WebIDL : : create_promise ( realm ) ;
// 8. Return promise and perform the remaining steps in parallel.
2024-11-14 12:01:23 -03:00
Platform : : EventLoopPlugin : : the ( ) . deferred_invoke ( GC : : create_function ( heap ( ) , [ & 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 {
2024-10-24 04:39:18 -03:00
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
2023-12-15 18:03:04 -03:00
// 9. If the following steps or referenced procedures say to throw an error, reject promise with the returned error and then terminate the algorithm.
// 10. Let result be the CryptoKey object that results from performing the import key operation
// specified by normalizedAlgorithm using keyData, algorithm, format, extractable and usages.
2024-03-06 20:53:50 -03:00
auto maybe_result = normalized_algorithm . methods - > import_key ( * normalized_algorithm . parameter , format , real_key_data . downcast < CryptoKey : : InternalKeyData > ( ) , extractable , key_usages ) ;
2023-12-15 18:03:04 -03:00
if ( maybe_result . is_error ( ) ) {
2025-04-04 13:11:45 -03:00
WebIDL : : reject_promise ( realm , promise , Bindings : : exception_to_throw_completion ( realm . vm ( ) , maybe_result . release_error ( ) ) . release_value ( ) ) ;
2023-12-15 18:03:04 -03:00
return ;
}
auto result = maybe_result . release_value ( ) ;
// 11. If the [[type]] internal slot of result is "secret" or "private" and usages is empty, then throw a SyntaxError.
if ( ( result - > type ( ) = = Bindings : : KeyType : : Secret | | result - > type ( ) = = Bindings : : KeyType : : Private ) & & key_usages . is_empty ( ) ) {
2025-08-07 20:31:52 -03:00
WebIDL : : reject_promise ( realm , promise , WebIDL : : SyntaxError : : create ( realm , " usages must not be empty " _utf16 ) ) ;
2023-12-15 18:03:04 -03:00
return ;
}
// 12. Set the [[extractable]] internal slot of result to extractable.
result - > set_extractable ( extractable ) ;
// 13. Set the [[usages]] internal slot of result to the normalized value of usages.
2024-03-06 23:11:08 -03:00
normalize_key_usages ( key_usages ) ;
result - > set_usages ( key_usages ) ;
2023-12-15 18:03:04 -03:00
// 14. Resolve promise with result.
WebIDL : : resolve_promise ( realm , promise , result ) ;
2024-10-30 10:39:29 -03:00
} ) ) ;
2023-12-15 18:03:04 -03:00
2024-10-25 15:38:19 -03:00
return promise ;
2023-12-15 18:03:04 -03:00
}
2024-03-14 00:19:57 -03:00
// https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-exportKey
2025-01-31 07:18:03 -03:00
GC : : Ref < WebIDL : : Promise > SubtleCrypto : : export_key ( Bindings : : KeyFormat format , GC : : Ref < CryptoKey > key )
2024-03-14 00:19:57 -03:00
{
auto & realm = this - > realm ( ) ;
// 1. Let format and key be the format and key parameters passed to the exportKey() method, respectively.
// 2. Let promise be a new Promise.
auto promise = WebIDL : : create_promise ( realm ) ;
// 3. Return promise and perform the remaining steps in parallel.
2024-11-14 12:01:23 -03:00
Platform : : EventLoopPlugin : : the ( ) . deferred_invoke ( GC : : create_function ( heap ( ) , [ & realm , key , promise , format ] ( ) - > void {
2024-10-24 04:39:18 -03:00
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
2024-03-14 00:19:57 -03:00
// 4. If the following steps or referenced procedures say to throw an error, reject promise with the returned error and then terminate the algorithm.
// 5. If the name member of the [[algorithm]] internal slot of key does not identify a registered algorithm that supports the export key operation,
// then throw a NotSupportedError.
// Note: Handled by the base AlgorithmMethods implementation
2025-01-21 11:12:05 -03:00
auto & algorithm = as < KeyAlgorithm > ( * key - > algorithm ( ) ) ;
2024-03-14 00:19:57 -03:00
// FIXME: Stash the AlgorithmMethods on the KeyAlgorithm
2024-03-15 00:52:17 -03:00
auto normalized_algorithm_or_error = normalize_an_algorithm ( realm , algorithm . name ( ) , " exportKey " _string ) ;
2024-03-14 00:19:57 -03:00
if ( normalized_algorithm_or_error . is_error ( ) ) {
2025-04-04 13:11:45 -03:00
WebIDL : : reject_promise ( realm , promise , Bindings : : exception_to_throw_completion ( realm . vm ( ) , normalized_algorithm_or_error . release_error ( ) ) . release_value ( ) ) ;
2024-03-14 00:19:57 -03:00
return ;
}
auto normalized_algorithm = normalized_algorithm_or_error . release_value ( ) ;
// 6. If the [[extractable]] internal slot of key is false, then throw an InvalidAccessError.
if ( ! key - > extractable ( ) ) {
2025-08-07 20:31:52 -03:00
WebIDL : : reject_promise ( realm , promise , WebIDL : : InvalidAccessError : : create ( realm , " Key is not extractable " _utf16 ) ) ;
2024-03-14 00:19:57 -03:00
return ;
}
// 7. Let result be the result of performing the export key operation specified by the [[algorithm]] internal slot of key using key and format.
auto result_or_error = normalized_algorithm . methods - > export_key ( format , key ) ;
if ( result_or_error . is_error ( ) ) {
2025-04-04 13:11:45 -03:00
WebIDL : : reject_promise ( realm , promise , Bindings : : exception_to_throw_completion ( realm . vm ( ) , result_or_error . release_error ( ) ) . release_value ( ) ) ;
2024-03-14 00:19:57 -03:00
return ;
}
// 8. Resolve promise with result.
WebIDL : : resolve_promise ( realm , promise , result_or_error . release_value ( ) ) ;
2024-10-30 10:39:29 -03:00
} ) ) ;
2024-03-14 00:19:57 -03:00
2024-10-25 15:38:19 -03:00
return promise ;
2024-03-26 19:53:35 -03:00
}
2026-03-15 09:28:03 -03:00
// https://w3c.github.io/webcrypto/#SubtleCrypto-method-sign
2026-05-28 18:14:33 -03:00
GC : : Ref < WebIDL : : Promise > SubtleCrypto : : sign ( AlgorithmIdentifier const & algorithm , GC : : Ref < CryptoKey > key , WebIDL : : BufferSource data_parameter )
2024-03-26 19:53:35 -03:00
{
auto & realm = this - > realm ( ) ;
auto & vm = this - > vm ( ) ;
2026-03-15 09:28:03 -03:00
auto & global = realm . global_object ( ) ;
auto & heap = realm . heap ( ) ;
2024-03-26 19:53:35 -03:00
// 1. Let algorithm and key be the algorithm and key parameters passed to the sign() method, respectively.
2026-03-15 09:28:03 -03:00
// 2. 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 ) ;
// 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 data be the result of getting a copy of the bytes held by the data parameter passed to the sign() method.
2026-05-28 18:14:33 -03:00
auto data_or_error = WebIDL : : get_buffer_source_copy ( data_parameter ) ;
2024-03-26 19:53:35 -03:00
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 ( ) ;
2026-03-15 09:28:03 -03:00
// 5. Let realm be the relevant realm of this.
2024-03-26 19:53:35 -03:00
2026-03-15 09:28:03 -03:00
// 6. Let promise be a new Promise.
2024-03-26 19:53:35 -03:00
auto promise = WebIDL : : create_promise ( realm ) ;
2026-03-15 09:28:03 -03:00
// 7. Return promise and perform the remaining steps in parallel.
Platform : : EventLoopPlugin : : the ( ) . deferred_invoke ( GC : : create_function ( realm . heap ( ) , [ & realm , & global , & heap , normalized_algorithm = normalized_algorithm . release_value ( ) , promise , key , data = move ( data ) ] ( ) mutable {
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : No ) ;
2024-03-26 19:53:35 -03:00
2026-03-15 09:28:03 -03:00
// 8. If the following steps or referenced procedures say to throw an error, queue a global task on the
// crypto task source, given realm's global object, to reject promise with the returned error; and then
// terminate the algorithm.
auto const throw_in_this_context = [ & realm , & global , & heap , & promise ] ( JS : : Value value ) {
HTML : : queue_global_task ( HTML : : Task : : Source : : Crypto , global , GC : : create_function ( heap , [ & realm , promise , value ] {
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
WebIDL : : reject_promise ( realm , promise , value ) ;
} ) ) ;
} ;
2024-03-26 19:53:35 -03:00
2026-03-15 09:28:03 -03:00
// 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.
2024-03-26 19:53:35 -03:00
if ( normalized_algorithm . parameter - > name ! = key - > algorithm_name ( ) ) {
2026-03-15 09:28:03 -03:00
throw_in_this_context ( WebIDL : : InvalidAccessError : : create ( realm , " Algorithm mismatch " _utf16 ) ) ;
2024-03-26 19:53:35 -03:00
return ;
}
2026-03-15 09:28:03 -03:00
// 10. If the [[usages]] internal slot of key does not contain an entry that is "sign", then throw an InvalidAccessError.
2024-03-26 19:53:35 -03:00
if ( ! key - > internal_usages ( ) . contains_slow ( Bindings : : KeyUsage : : Sign ) ) {
2026-03-15 09:28:03 -03:00
throw_in_this_context ( WebIDL : : InvalidAccessError : : create ( realm , " Key does not support signing " _utf16 ) ) ;
2024-03-26 19:53:35 -03:00
return ;
}
2026-03-15 09:28:03 -03:00
// 11. Let signature be the result of performing the sign operation specified by normalizedAlgorithm using key
// and algorithm and with data as message.
auto signature = normalized_algorithm . methods - > sign ( * normalized_algorithm . parameter , key , data ) ;
if ( signature . is_error ( ) ) {
throw_in_this_context ( Bindings : : exception_to_throw_completion ( realm . vm ( ) , signature . release_error ( ) ) . release_value ( ) ) ;
2024-03-26 19:53:35 -03:00
return ;
}
2026-03-15 09:28:03 -03:00
// 12. Queue a global task on the crypto task source, given realm's global object, to perform the remaining steps.
HTML : : queue_global_task ( HTML : : Task : : Source : : Crypto , global , GC : : create_function ( heap , [ & realm , promise , signature_bytes = signature . release_value ( ) ] {
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
// 13. Let result be the result of creating an ArrayBuffer in realm, containing signature.
// 14. Resolve promise with result.
WebIDL : : resolve_promise ( realm , promise , signature_bytes ) ;
} ) ) ;
2024-10-30 10:39:29 -03:00
} ) ) ;
2024-03-26 19:53:35 -03:00
2024-10-25 15:38:19 -03:00
return promise ;
2024-03-14 00:19:57 -03:00
}
2026-03-15 09:28:03 -03:00
// https://w3c.github.io/webcrypto/#SubtleCrypto-method-verify
2026-05-28 18:14:33 -03:00
GC : : Ref < WebIDL : : Promise > SubtleCrypto : : verify ( AlgorithmIdentifier const & algorithm , GC : : Ref < CryptoKey > key , WebIDL : : BufferSource signature_data , WebIDL : : BufferSource data_parameter )
2024-03-26 21:50:25 -03:00
{
auto & realm = this - > realm ( ) ;
auto & vm = this - > vm ( ) ;
2026-03-15 09:28:03 -03:00
auto & global = realm . global_object ( ) ;
auto & heap = realm . heap ( ) ;
2024-03-26 21:50:25 -03:00
// 1. Let algorithm and key be the algorithm and key parameters passed to the verify() method, respectively.
2026-03-15 09:28:03 -03:00
// 2. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set to algorithm and op set to "verify".
auto normalized_algorithm = normalize_an_algorithm ( realm , algorithm , " verify " _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 signature be the result of getting a copy of the bytes held by the signature parameter passed to the verify() method.
2026-05-28 18:14:33 -03:00
auto signature_or_error = WebIDL : : get_buffer_source_copy ( signature_data ) ;
2024-03-26 21:50:25 -03:00
if ( signature_or_error . is_error ( ) ) {
VERIFY ( signature_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 signature = signature_or_error . release_value ( ) ;
2026-03-15 09:28:03 -03:00
// 5. Let data be the result of getting a copy of the bytes held by the data parameter passed to the verify() method.
2026-05-28 18:14:33 -03:00
auto data_or_error = WebIDL : : get_buffer_source_copy ( data_parameter ) ;
2024-03-26 21:50:25 -03:00
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 ( ) ;
2026-03-15 09:28:03 -03:00
// 6. Let realm be the relevant realm of this.
2024-03-26 21:50:25 -03:00
2026-03-15 09:28:03 -03:00
// 7. Let promise be a new Promise.
2024-03-26 21:50:25 -03:00
auto promise = WebIDL : : create_promise ( realm ) ;
2026-03-15 09:28:03 -03:00
// 8. Return promise and perform the remaining steps in parallel.
Platform : : EventLoopPlugin : : the ( ) . deferred_invoke ( GC : : create_function ( realm . heap ( ) , [ & realm , & global , & heap , normalized_algorithm = normalized_algorithm . release_value ( ) , promise , key , signature = move ( signature ) , data = move ( data ) ] ( ) mutable {
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : No ) ;
2024-03-26 21:50:25 -03:00
2026-03-15 09:28:03 -03:00
// 9. If the following steps or referenced procedures say to throw an error, queue a global task on the
// crypto task source, given realm's global object, to reject promise with the returned error; and then
// terminate the algorithm.
auto const throw_in_this_context = [ & realm , & global , & heap , & promise ] ( JS : : Value value ) {
HTML : : queue_global_task ( HTML : : Task : : Source : : Crypto , global , GC : : create_function ( heap , [ & realm , promise , value ] {
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
WebIDL : : reject_promise ( realm , promise , value ) ;
} ) ) ;
} ;
// 10. If the name member of normalizedAlgorithm is not equal to the name attribute of the [[algorithm]]
// internal slot of key then throw an InvalidAccessError.
2024-03-26 21:50:25 -03:00
if ( normalized_algorithm . parameter - > name ! = key - > algorithm_name ( ) ) {
2026-03-15 09:28:03 -03:00
throw_in_this_context ( WebIDL : : InvalidAccessError : : create ( realm , " Algorithm mismatch " _utf16 ) ) ;
2024-03-26 21:50:25 -03:00
return ;
}
2026-03-15 09:28:03 -03:00
// 11. If the [[usages]] internal slot of key does not contain an entry that is "verify", then throw an InvalidAccessError.
2024-03-26 21:50:25 -03:00
if ( ! key - > internal_usages ( ) . contains_slow ( Bindings : : KeyUsage : : Verify ) ) {
2026-03-15 09:28:03 -03:00
throw_in_this_context ( WebIDL : : InvalidAccessError : : create ( realm , " Key does not support verification " _utf16 ) ) ;
2024-03-26 21:50:25 -03:00
return ;
}
2026-03-15 09:28:03 -03:00
// 12. Let result be the result of performing the verify operation specified by normalizedAlgorithm using key,
// algorithm and signature and with data as message.
2024-03-26 21:50:25 -03:00
auto result = normalized_algorithm . methods - > verify ( * normalized_algorithm . parameter , key , signature , data ) ;
if ( result . is_error ( ) ) {
2026-03-15 09:28:03 -03:00
throw_in_this_context ( Bindings : : exception_to_throw_completion ( realm . vm ( ) , result . release_error ( ) ) . release_value ( ) ) ;
2024-03-26 21:50:25 -03:00
return ;
}
2026-03-15 09:28:03 -03:00
// 13. Queue a global task on the crypto task source, given realm's global object, to perform the remaining steps.
HTML : : queue_global_task ( HTML : : Task : : Source : : Crypto , global , GC : : create_function ( heap , [ & realm , promise , verification_result = result . release_value ( ) ] {
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
// 14. Resolve promise with result.
WebIDL : : resolve_promise ( realm , promise , verification_result ) ;
} ) ) ;
2024-10-30 10:39:29 -03:00
} ) ) ;
2024-03-26 21:50:25 -03:00
2024-10-25 15:38:19 -03:00
return promise ;
2024-03-26 21:50:25 -03:00
}
2024-03-27 15:15:49 -03:00
// https://w3c.github.io/webcrypto/#SubtleCrypto-method-deriveBits
2025-01-31 07:18:03 -03:00
GC : : Ref < WebIDL : : Promise > SubtleCrypto : : derive_bits ( AlgorithmIdentifier algorithm , GC : : Ref < CryptoKey > base_key , Optional < u32 > length_optional )
2024-03-27 15:15:49 -03:00
{
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.
2024-12-17 12:13:20 -03:00
Platform : : EventLoopPlugin : : the ( ) . deferred_invoke ( GC : : create_function ( realm . heap ( ) , [ & realm , normalized_algorithm = normalized_algorithm . release_value ( ) , promise , base_key , length_optional ] ( ) - > void {
2024-10-24 04:39:18 -03:00
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
2024-03-27 15:15:49 -03:00
// 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 ( ) ) {
2025-08-07 20:31:52 -03:00
WebIDL : : reject_promise ( realm , promise , WebIDL : : InvalidAccessError : : create ( realm , " Algorithm mismatch " _utf16 ) ) ;
2024-03-27 15:15:49 -03:00
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 ) ) {
2025-08-07 20:31:52 -03:00
WebIDL : : reject_promise ( realm , promise , WebIDL : : InvalidAccessError : : create ( realm , " Key does not support deriving bits " _utf16 ) ) ;
2024-03-27 15:15:49 -03:00
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.
2024-12-17 12:13:20 -03:00
auto result = normalized_algorithm . methods - > derive_bits ( * normalized_algorithm . parameter , base_key , length_optional ) ;
2024-03-27 15:15:49 -03:00
if ( result . is_error ( ) ) {
2025-04-04 13:11:45 -03:00
WebIDL : : reject_promise ( realm , promise , Bindings : : exception_to_throw_completion ( realm . vm ( ) , result . release_error ( ) ) . release_value ( ) ) ;
2024-03-27 15:15:49 -03:00
return ;
}
// 10. Resolve promise with result.
WebIDL : : resolve_promise ( realm , promise , result . release_value ( ) ) ;
2024-10-30 10:39:29 -03:00
} ) ) ;
2024-03-27 15:15:49 -03:00
2024-10-25 15:38:19 -03:00
return promise ;
2024-03-27 15:15:49 -03:00
}
2024-11-15 06:10:13 -03:00
// https://w3c.github.io/webcrypto/#SubtleCrypto-method-deriveKey
2025-01-31 07:18:03 -03:00
GC : : Ref < WebIDL : : Promise > SubtleCrypto : : derive_key ( AlgorithmIdentifier algorithm , GC : : Ref < CryptoKey > base_key , AlgorithmIdentifier derived_key_type , bool extractable , Vector < Bindings : : KeyUsage > key_usages )
2024-03-27 16:51:18 -03:00
{
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.
2024-11-15 11:53:39 -03:00
Platform : : EventLoopPlugin : : the ( ) . deferred_invoke ( GC : : create_function ( realm . heap ( ) , [ & 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 ) ] ( ) mutable - > void {
2024-10-24 04:39:18 -03:00
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
2024-03-27 16:51:18 -03:00
// 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 ( ) ) {
2025-08-07 20:31:52 -03:00
WebIDL : : reject_promise ( realm , promise , WebIDL : : InvalidAccessError : : create ( realm , " Algorithm mismatch " _utf16 ) ) ;
2024-03-27 16:51:18 -03:00
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 ) ) {
2025-08-07 20:31:52 -03:00
WebIDL : : reject_promise ( realm , promise , WebIDL : : InvalidAccessError : : create ( realm , " Key does not support deriving keys " _utf16 ) ) ;
2024-03-27 16:51:18 -03:00
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 ( ) ) {
2025-04-04 13:11:45 -03:00
WebIDL : : reject_promise ( realm , promise , Bindings : : exception_to_throw_completion ( realm . vm ( ) , length_result . release_error ( ) ) . release_value ( ) ) ;
2024-03-27 16:51:18 -03:00
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 ( ) ) {
2025-04-04 13:11:45 -03:00
WebIDL : : reject_promise ( realm , promise , maybe_length . release_error ( ) . release_value ( ) ) ;
2024-03-27 16:51:18 -03:00
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 ( ) ) {
2025-04-04 13:11:45 -03:00
WebIDL : : reject_promise ( realm , promise , Bindings : : exception_to_throw_completion ( realm . vm ( ) , secret . release_error ( ) ) . release_value ( ) ) ;
2024-03-27 16:51:18 -03:00
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.
2026-04-04 14:25:48 -03:00
auto secret_bytes = MUST ( ByteBuffer : : copy ( secret . release_value ( ) - > bytes ( ) ) ) ;
auto result_or_error = normalized_derived_key_algorithm_import . methods - > import_key ( * normalized_derived_key_algorithm_import . parameter , Bindings : : KeyFormat : : Raw , move ( secret_bytes ) , extractable , key_usages ) ;
2024-11-15 11:53:39 -03:00
if ( result_or_error . is_error ( ) ) {
2025-04-04 13:11:45 -03:00
WebIDL : : reject_promise ( realm , promise , Bindings : : exception_to_throw_completion ( realm . vm ( ) , result_or_error . release_error ( ) ) . release_value ( ) ) ;
2024-03-27 16:51:18 -03:00
return ;
}
2024-11-15 11:53:39 -03:00
auto result = result_or_error . release_value ( ) ;
2024-03-27 16:51:18 -03:00
// 16. If the [[type]] internal slot of result is "secret" or "private" and usages is empty, then throw a SyntaxError.
2024-11-15 11:53:39 -03:00
if ( ( result - > type ( ) = = Bindings : : KeyType : : Secret | | result - > type ( ) = = Bindings : : KeyType : : Private ) & & key_usages . is_empty ( ) ) {
2025-08-07 20:31:52 -03:00
WebIDL : : reject_promise ( realm , promise , WebIDL : : SyntaxError : : create ( realm , " usages must not be empty " _utf16 ) ) ;
2024-03-27 16:51:18 -03:00
return ;
}
2024-11-15 11:53:39 -03:00
// 17. Set the [[extractable]] internal slot of result to extractable.
result - > set_extractable ( extractable ) ;
2024-11-15 06:36:34 -03:00
2024-11-15 11:53:39 -03:00
// 18. Set the [[usages]] internal slot of result to the normalized value of usages.
normalize_key_usages ( key_usages ) ;
result - > set_usages ( key_usages ) ;
// 19. Resolve promise with result.
WebIDL : : resolve_promise ( realm , promise , result ) ;
2024-10-30 10:39:29 -03:00
} ) ) ;
2024-03-27 16:51:18 -03:00
2024-10-25 15:38:19 -03:00
return promise ;
2024-03-27 16:51:18 -03:00
}
2024-12-14 08:23:52 -03:00
// https://w3c.github.io/webcrypto/#SubtleCrypto-method-wrapKey
2025-01-31 07:18:03 -03:00
GC : : Ref < WebIDL : : Promise > SubtleCrypto : : wrap_key ( Bindings : : KeyFormat format , GC : : Ref < CryptoKey > key , GC : : Ref < CryptoKey > wrapping_key , AlgorithmIdentifier algorithm )
2024-12-14 08:23:52 -03:00
{
2026-03-29 06:56:52 -03:00
// 5. Let realm be the relevant realm of this.
2024-12-14 08:23:52 -03:00
auto & realm = this - > realm ( ) ;
// 1. Let format, key, wrappingKey and algorithm be the format, key, wrappingKey and wrapAlgorithm parameters passed to the wrapKey() method, respectively.
StringView operation ;
auto normalized_algorithm_or_error = [ & ] ( ) - > WebIDL : : ExceptionOr < NormalizedAlgorithmAndParameter > {
// 2. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set to algorithm and op set to "wrapKey".
auto normalized_algorithm_wrap_key_or_error = normalize_an_algorithm ( realm , algorithm , " wrapKey " _string ) ;
// 3. If an error occurred, let normalizedAlgorithm be the result of normalizing an algorithm, with alg set to algorithm and op set to "encrypt".
// 4. If an error occurred, return a Promise rejected with normalizedAlgorithm.
if ( normalized_algorithm_wrap_key_or_error . is_error ( ) ) {
auto normalized_algorithm_encrypt_or_error = normalize_an_algorithm ( realm , algorithm , " encrypt " _string ) ;
if ( normalized_algorithm_encrypt_or_error . is_error ( ) )
return normalized_algorithm_encrypt_or_error . release_error ( ) ;
operation = " encrypt " sv ;
return normalized_algorithm_encrypt_or_error . release_value ( ) ;
} else {
operation = " wrapKey " sv ;
return normalized_algorithm_wrap_key_or_error . release_value ( ) ;
}
} ( ) ;
if ( normalized_algorithm_or_error . is_error ( ) )
return WebIDL : : create_rejected_promise_from_exception ( realm , normalized_algorithm_or_error . release_error ( ) ) ;
auto normalized_algorithm = normalized_algorithm_or_error . release_value ( ) ;
2026-03-29 06:56:52 -03:00
// 6. Let promise be a new Promise.
2024-12-14 08:23:52 -03:00
auto promise = WebIDL : : create_promise ( realm ) ;
2026-03-29 06:56:52 -03:00
// 7. Return promise and perform the remaining steps in parallel.
2024-12-14 08:23:52 -03:00
Platform : : EventLoopPlugin : : the ( ) . deferred_invoke ( GC : : create_function ( realm . heap ( ) , [ & realm , normalized_algorithm = move ( normalized_algorithm ) , promise , wrapping_key = move ( wrapping_key ) , key = move ( key ) , format , operation ] ( ) mutable - > void {
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
2026-03-29 06:56:52 -03:00
// FIXME: 8. If the following steps or referenced procedures say to throw an error, queue a global task on the crypto task source, given realm's global object, to reject promise with the returned error; and then terminate the algorithm.
2024-12-14 08:23:52 -03:00
2026-03-29 06:56:52 -03:00
// 9. If the name member of normalizedAlgorithm is not equal to the name attribute
2024-12-14 08:23:52 -03:00
// of the [[algorithm]] internal slot of wrappingKey then throw an InvalidAccessError.
if ( normalized_algorithm . parameter - > name ! = wrapping_key - > algorithm_name ( ) ) {
2025-08-07 20:31:52 -03:00
WebIDL : : reject_promise ( realm , promise , WebIDL : : InvalidAccessError : : create ( realm , " Algorithm mismatch " _utf16 ) ) ;
2024-12-14 08:23:52 -03:00
return ;
}
2026-03-29 06:56:52 -03:00
// 10. If the [[usages]] internal slot of wrappingKey does not contain an entry that is "wrapKey", then throw an InvalidAccessError.
2024-12-14 08:23:52 -03:00
if ( ! wrapping_key - > internal_usages ( ) . contains_slow ( Bindings : : KeyUsage : : Wrapkey ) ) {
2025-08-07 20:31:52 -03:00
WebIDL : : reject_promise ( realm , promise , WebIDL : : InvalidAccessError : : create ( realm , " Key does not support wrapping keys " _utf16 ) ) ;
2024-12-14 08:23:52 -03:00
return ;
}
2026-03-29 06:56:52 -03:00
// 11. If the algorithm identified by the [[algorithm]] internal slot of key does not support the export key operation, then throw a NotSupportedError.
2024-12-14 08:23:52 -03:00
// Note: Handled by the base AlgorithmMethods implementation
2026-03-29 06:56:52 -03:00
// 12. If the [[extractable]] internal slot of key is false, then throw an InvalidAccessError.
2024-12-14 08:23:52 -03:00
if ( ! key - > extractable ( ) ) {
2025-08-07 20:31:52 -03:00
WebIDL : : reject_promise ( realm , promise , WebIDL : : InvalidAccessError : : create ( realm , " Key is not extractable " _utf16 ) ) ;
2024-12-14 08:23:52 -03:00
return ;
}
2026-03-29 06:56:52 -03:00
// 13. Let exportedKey be the result of performing the export key operation specified by the [[algorithm]] internal slot of key using key and format.
2024-12-14 08:23:52 -03:00
// NOTE: The spec does not mention we need to normalize this, but it's the only way we have to get to export_key.
2025-01-21 11:12:05 -03:00
auto & key_algorithm = as < KeyAlgorithm > ( * key - > algorithm ( ) ) ;
2024-12-14 08:23:52 -03:00
auto normalized_key_algorithm = normalize_an_algorithm ( realm , key_algorithm . name ( ) , " exportKey " _string ) ;
if ( normalized_key_algorithm . is_error ( ) ) {
2025-04-04 13:11:45 -03:00
WebIDL : : reject_promise ( realm , promise , Bindings : : exception_to_throw_completion ( realm . vm ( ) , normalized_key_algorithm . release_error ( ) ) . release_value ( ) ) ;
2024-12-14 08:23:52 -03:00
return ;
}
2026-03-29 06:56:52 -03:00
auto exported_key_or_error = normalized_key_algorithm . release_value ( ) . methods - > export_key ( format , key ) ;
if ( exported_key_or_error . is_error ( ) ) {
WebIDL : : reject_promise ( realm , promise , Bindings : : exception_to_throw_completion ( realm . vm ( ) , exported_key_or_error . release_error ( ) ) . release_value ( ) ) ;
2024-12-14 08:23:52 -03:00
return ;
}
2026-03-29 06:56:52 -03:00
auto exported_key = exported_key_or_error . release_value ( ) ;
2024-12-14 08:23:52 -03:00
ByteBuffer bytes ;
2026-03-29 06:56:52 -03:00
// 14. If format is equal to the string "jwk":
if ( format = = Bindings : : KeyFormat : : Jwk ) {
// 1. Let json be the result of representing exportedKey as a UTF-16 string conforming to the JSON grammar;
2024-12-14 08:23:52 -03:00
// for example, by executing the JSON.stringify algorithm specified in [ECMA-262] in the context of a new global object.
2026-03-29 06:56:52 -03:00
auto maybe_json = JS : : JSONObject : : stringify_impl ( realm . vm ( ) , exported_key , JS : : Value { } , JS : : Value { } ) ;
2024-12-14 08:23:52 -03:00
if ( maybe_json . is_error ( ) ) {
2025-04-04 13:11:45 -03:00
WebIDL : : reject_promise ( realm , promise , maybe_json . release_error ( ) . release_value ( ) ) ;
2024-12-14 08:23:52 -03:00
return ;
}
2026-03-29 06:56:52 -03:00
// 2. Let bytes be the result of UTF-8 encoding json.
2026-06-22 08:06:30 -03:00
auto json = MUST ( maybe_json . value ( ) - > utf16_view ( ) . to_utf8 ( ) ) ;
bytes = MUST ( ByteBuffer : : copy ( json . bytes ( ) ) ) ;
2026-03-29 06:56:52 -03:00
}
// Otherwise:
2026-03-29 06:38:28 -03:00
else if ( format = = Bindings : : KeyFormat : : Raw
| | format = = Bindings : : KeyFormat : : RawPublic
| | format = = Bindings : : KeyFormat : : RawPrivate
| | format = = Bindings : : KeyFormat : : RawSeed
| | format = = Bindings : : KeyFormat : : RawSecret
| | format = = Bindings : : KeyFormat : : Pkcs8
| | format = = Bindings : : KeyFormat : : Spki ) {
2026-03-29 06:56:52 -03:00
// Let bytes be exportedKey.
2026-06-10 07:39:59 -03:00
bytes = MUST ( ByteBuffer : : copy ( as < JS : : ArrayBuffer > ( * exported_key ) . bytes ( ) ) ) ;
2024-12-14 08:23:52 -03:00
} else {
VERIFY_NOT_REACHED ( ) ;
}
JS : : Value result ;
2026-03-29 06:56:52 -03:00
// 15. If normalizedAlgorithm supports the wrap key operation:
2024-12-14 08:23:52 -03:00
if ( operation = = " wrapKey " ) {
// Let result be the result of performing the wrap key operation specified by normalizedAlgorithm
// using algorithm, wrappingKey as key and bytes as plaintext.
auto result_or_error = normalized_algorithm . methods - > wrap_key ( * normalized_algorithm . parameter , wrapping_key , bytes ) ;
if ( result_or_error . is_error ( ) ) {
2025-04-04 13:11:45 -03:00
WebIDL : : reject_promise ( realm , promise , Bindings : : exception_to_throw_completion ( realm . vm ( ) , result_or_error . release_error ( ) ) . release_value ( ) ) ;
2024-12-14 08:23:52 -03:00
return ;
}
result = result_or_error . release_value ( ) ;
}
// Otherwise, if normalizedAlgorithm supports the encrypt operation:
else if ( operation = = " encrypt " ) {
// Let result be the result of performing the encrypt operation specified by normalizedAlgorithm
// using algorithm, wrappingKey as key and bytes as plaintext.
auto result_or_error = normalized_algorithm . methods - > encrypt ( * normalized_algorithm . parameter , wrapping_key , bytes ) ;
if ( result_or_error . is_error ( ) ) {
2025-04-04 13:11:45 -03:00
WebIDL : : reject_promise ( realm , promise , Bindings : : exception_to_throw_completion ( realm . vm ( ) , result_or_error . release_error ( ) ) . release_value ( ) ) ;
2024-12-14 08:23:52 -03:00
return ;
}
result = result_or_error . release_value ( ) ;
}
// Otherwise:
else {
// throw a NotSupportedError.
2025-08-07 20:31:52 -03:00
WebIDL : : reject_promise ( realm , promise , WebIDL : : NotSupportedError : : create ( realm , " Algorithm does not support wrapping " _utf16 ) ) ;
2024-12-14 08:23:52 -03:00
return ;
}
2026-03-29 06:56:52 -03:00
// FIXME: 16. Queue a global task on the crypto task source, given realm's global object, to perform the remaining steps.
// FIXME: 17. Let result be the result of creating an ArrayBuffer in realm, containing result.
// 18. Resolve promise with result.
2024-12-14 08:23:52 -03:00
WebIDL : : resolve_promise ( realm , promise , result ) ;
} ) ) ;
return promise ;
}
// https://w3c.github.io/webcrypto/#SubtleCrypto-method-unwrapKey
2026-05-28 18:14:33 -03:00
GC : : Ref < WebIDL : : Promise > SubtleCrypto : : unwrap_key ( Bindings : : KeyFormat format , WebIDL : : BufferSource wrapped_key , GC : : Ref < CryptoKey > unwrapping_key , AlgorithmIdentifier algorithm , AlgorithmIdentifier unwrapped_key_algorithm , bool extractable , Vector < Bindings : : KeyUsage > key_usages )
2024-12-14 08:23:52 -03:00
{
2026-03-29 06:56:52 -03:00
// 8. Let realm be the relevant realm of this.
2024-12-14 08:23:52 -03:00
auto & realm = this - > realm ( ) ;
// 1. Let format, unwrappingKey, algorithm, unwrappedKeyAlgorithm, extractable and usages, be the format, unwrappingKey, unwrapAlgorithm,
// unwrappedKeyAlgorithm, extractable and keyUsages parameters passed to the unwrapKey() method, respectively.
StringView operation ;
auto normalized_algorithm_or_error = [ & ] ( ) - > WebIDL : : ExceptionOr < NormalizedAlgorithmAndParameter > {
2026-03-29 06:56:52 -03:00
// 2. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set to algorithm and op set to "unwrapKey".
2024-12-14 08:23:52 -03:00
auto normalized_algorithm_unwrap_key_or_error = normalize_an_algorithm ( realm , algorithm , " unwrapKey " _string ) ;
2026-03-29 06:56:52 -03:00
// 3. If an error occurred, let normalizedAlgorithm be the result of normalizing an algorithm, with alg set to algorithm and op set to "decrypt".
// 4. If an error occurred, return a Promise rejected with normalizedAlgorithm.
2024-12-14 08:23:52 -03:00
if ( normalized_algorithm_unwrap_key_or_error . is_error ( ) ) {
auto normalized_algorithm_decrypt_or_error = normalize_an_algorithm ( realm , algorithm , " decrypt " _string ) ;
if ( normalized_algorithm_decrypt_or_error . is_error ( ) )
return normalized_algorithm_decrypt_or_error . release_error ( ) ;
operation = " decrypt " sv ;
return normalized_algorithm_decrypt_or_error . release_value ( ) ;
} else {
operation = " unwrapKey " sv ;
return normalized_algorithm_unwrap_key_or_error . release_value ( ) ;
}
} ( ) ;
if ( normalized_algorithm_or_error . is_error ( ) )
return WebIDL : : create_rejected_promise_from_exception ( realm , normalized_algorithm_or_error . release_error ( ) ) ;
auto normalized_algorithm = normalized_algorithm_or_error . release_value ( ) ;
2026-03-29 06:56:52 -03:00
// 5. Let normalizedKeyAlgorithm be the result of normalizing an algorithm, with alg set to unwrappedKeyAlgorithm and op set to "importKey".
2024-12-14 08:23:52 -03:00
auto normalized_key_algorithm_or_error = normalize_an_algorithm ( realm , unwrapped_key_algorithm , " importKey " _string ) ;
if ( normalized_key_algorithm_or_error . is_error ( ) ) {
2026-03-29 06:56:52 -03:00
// 6. If an error occurred, return a Promise rejected with normalizedKeyAlgorithm.
2024-12-14 08:23:52 -03:00
return WebIDL : : create_rejected_promise_from_exception ( realm , normalized_key_algorithm_or_error . release_error ( ) ) ;
}
auto normalized_key_algorithm = normalized_key_algorithm_or_error . release_value ( ) ;
2026-03-29 06:56:52 -03:00
// 7. Let wrappedKey be the result of getting a copy of the bytes held by the wrappedKey parameter passed to the unwrapKey() method.
2026-05-28 18:14:33 -03:00
auto real_wrapped_key = MUST ( WebIDL : : get_buffer_source_copy ( wrapped_key ) ) ;
2026-03-29 06:56:52 -03:00
// 9. Let promise be a new Promise.
2024-12-14 08:23:52 -03:00
auto promise = WebIDL : : create_promise ( realm ) ;
2026-03-29 06:56:52 -03:00
// 10. Return promise and perform the remaining steps in parallel.
2024-12-14 08:23:52 -03:00
Platform : : EventLoopPlugin : : the ( ) . deferred_invoke ( GC : : create_function ( realm . heap ( ) , [ & realm , normalized_algorithm = move ( normalized_algorithm ) , promise , unwrapping_key = unwrapping_key , real_wrapped_key = move ( real_wrapped_key ) , operation , format , extractable , key_usages = move ( key_usages ) , normalized_key_algorithm = move ( normalized_key_algorithm ) ] ( ) mutable - > void {
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
2026-03-29 06:56:52 -03:00
// FIXME: 11. If the following steps or referenced procedures say to throw an error, queue a global task on the crypto task source, given realm's global object, to reject promise with the returned error; and then terminate the algorithm.
2024-12-14 08:23:52 -03:00
2026-03-29 06:56:52 -03:00
// 12. If the name member of normalizedAlgorithm is not equal to the name attribute of the [[algorithm]] internal slot
2024-12-14 08:23:52 -03:00
// of unwrappingKey then throw an InvalidAccessError.
if ( normalized_algorithm . parameter - > name ! = unwrapping_key - > algorithm_name ( ) ) {
2025-08-07 20:31:52 -03:00
WebIDL : : reject_promise ( realm , promise , WebIDL : : InvalidAccessError : : create ( realm , " Algorithm mismatch " _utf16 ) ) ;
2024-12-14 08:23:52 -03:00
return ;
}
2026-03-29 06:56:52 -03:00
// 13. If the [[usages]] internal slot of unwrappingKey does not contain an entry that is "unwrapKey", then throw an InvalidAccessError.
2024-12-14 08:23:52 -03:00
if ( ! unwrapping_key - > internal_usages ( ) . contains_slow ( Bindings : : KeyUsage : : Unwrapkey ) ) {
2025-08-07 20:31:52 -03:00
WebIDL : : reject_promise ( realm , promise , WebIDL : : InvalidAccessError : : create ( realm , " Key does not support unwrapping keys " _utf16 ) ) ;
2024-12-14 08:23:52 -03:00
return ;
}
2026-03-29 06:56:52 -03:00
auto bytes_or_error = [ & ] ( ) - > WebIDL : : ExceptionOr < GC : : Ref < JS : : ArrayBuffer > > {
// 14. If normalizedAlgorithm supports an unwrap key operation:
2024-12-14 08:23:52 -03:00
if ( operation = = " unwrapKey " ) {
2026-03-29 06:56:52 -03:00
// Let bytes be the result of performing the unwrap key operation specified by normalizedAlgorithm
2024-12-14 08:23:52 -03:00
// using algorithm, unwrappingKey as key and wrappedKey as ciphertext.
return normalized_algorithm . methods - > unwrap_key ( * normalized_algorithm . parameter , unwrapping_key , real_wrapped_key ) ;
}
// Otherwise, if normalizedAlgorithm supports a decrypt operation:
else if ( operation = = " decrypt " ) {
2026-03-29 06:56:52 -03:00
// Let bytes be the result of performing the decrypt operation specified by normalizedAlgorithm
2024-12-14 08:23:52 -03:00
// using algorithm, unwrappingKey as key and wrappedKey as ciphertext.
return normalized_algorithm . methods - > decrypt ( * normalized_algorithm . parameter , unwrapping_key , real_wrapped_key ) ;
}
// Otherwise:
else {
// throw a NotSupportedError.
2025-08-07 20:31:52 -03:00
return WebIDL : : NotSupportedError : : create ( realm , " Algorithm does not support wrapping " _utf16 ) ;
2024-12-14 08:23:52 -03:00
}
} ( ) ;
2026-03-29 06:56:52 -03:00
if ( bytes_or_error . is_error ( ) ) {
WebIDL : : reject_promise ( realm , promise , Bindings : : exception_to_throw_completion ( realm . vm ( ) , bytes_or_error . release_error ( ) ) . release_value ( ) ) ;
2024-12-14 08:23:52 -03:00
return ;
}
2026-03-29 06:56:52 -03:00
auto bytes = bytes_or_error . release_value ( ) ;
2024-12-14 08:23:52 -03:00
2026-04-22 09:42:24 -03:00
Variant < ByteBuffer , JsonWebKey , Empty > key ;
2024-12-14 08:23:52 -03:00
2026-03-29 06:56:52 -03:00
// 15. If format is equal to the string "jwk":
if ( format = = Bindings : : KeyFormat : : Jwk ) {
// Let key be the result of executing the parse a JWK algorithm, with bytes as the data to be parsed.
2026-04-04 14:25:48 -03:00
auto maybe_parsed = JsonWebKey : : parse ( realm , bytes - > bytes ( ) ) ;
2024-12-14 08:23:52 -03:00
if ( maybe_parsed . is_error ( ) ) {
2025-04-04 13:11:45 -03:00
WebIDL : : reject_promise ( realm , promise , maybe_parsed . release_error ( ) . release_value ( ) ) ;
2024-12-14 08:23:52 -03:00
return ;
}
2026-03-29 06:56:52 -03:00
key = maybe_parsed . release_value ( ) ;
}
// Otherwise:
2026-03-29 06:38:28 -03:00
else if ( format = = Bindings : : KeyFormat : : Raw
| | format = = Bindings : : KeyFormat : : RawPublic
| | format = = Bindings : : KeyFormat : : RawPrivate
| | format = = Bindings : : KeyFormat : : RawSeed
| | format = = Bindings : : KeyFormat : : RawSecret
| | format = = Bindings : : KeyFormat : : Pkcs8
| | format = = Bindings : : KeyFormat : : Spki ) {
2026-03-29 06:56:52 -03:00
// Let key be bytes.
2026-06-10 07:39:59 -03:00
key = MUST ( ByteBuffer : : copy ( bytes - > bytes ( ) ) ) ;
2024-12-14 08:23:52 -03:00
} else {
VERIFY_NOT_REACHED ( ) ;
}
2026-03-29 06:56:52 -03:00
// 16. Let result be the result of performing the import key operation specified by normalizedKeyAlgorithm
// using unwrappedKeyAlgorithm as algorithm, format, usages and extractable and with key as keyData.
auto result_or_error = normalized_key_algorithm . methods - > import_key ( * normalized_key_algorithm . parameter , format , key . downcast < CryptoKey : : InternalKeyData > ( ) , extractable , key_usages ) ;
2024-12-14 08:23:52 -03:00
if ( result_or_error . is_error ( ) ) {
2025-04-04 13:11:45 -03:00
WebIDL : : reject_promise ( realm , promise , Bindings : : exception_to_throw_completion ( realm . vm ( ) , result_or_error . release_error ( ) ) . release_value ( ) ) ;
2024-12-14 08:23:52 -03:00
return ;
}
auto result = result_or_error . release_value ( ) ;
2026-03-29 06:56:52 -03:00
// 17. If the [[type]] internal slot of result is "secret" or "private" and usages is empty, then throw a SyntaxError.
2024-12-14 08:23:52 -03:00
if ( ( result - > type ( ) = = Bindings : : KeyType : : Secret | | result - > type ( ) = = Bindings : : KeyType : : Private ) & & key_usages . is_empty ( ) ) {
2025-08-07 20:31:52 -03:00
WebIDL : : reject_promise ( realm , promise , WebIDL : : SyntaxError : : create ( realm , " Usages must not be empty " _utf16 ) ) ;
2024-12-14 08:23:52 -03:00
return ;
}
2026-03-29 06:56:52 -03:00
// 18. Set the [[extractable]] internal slot of result to extractable.
2024-12-14 08:23:52 -03:00
result - > set_extractable ( extractable ) ;
2026-03-29 06:56:52 -03:00
// 19. Set the [[usages]] internal slot of result to the normalized value of usages.
2024-12-14 08:23:52 -03:00
normalize_key_usages ( key_usages ) ;
result - > set_usages ( key_usages ) ;
2026-03-29 06:56:52 -03:00
// FIXME: 20. Queue a global task on the crypto task source, given realm's global object, to perform the remaining steps.
// FIXME: 21. Let result be the result of converting result to an ECMAScript Object in realm, as defined by [WebIDL].
// 22. Resolve promise with result.
2024-12-14 08:23:52 -03:00
WebIDL : : resolve_promise ( realm , promise , result ) ;
} ) ) ;
return promise ;
}
2025-11-27 15:16:27 -03:00
// https://wicg.github.io/webcrypto-modern-algos/#dfn-SubtleCrypto-method-encapsulateKey
GC : : Ref < WebIDL : : Promise > SubtleCrypto : : encapsulate_key ( AlgorithmIdentifier encapsulation_algorithm , GC : : Ref < CryptoKey > encapsulation_key , AlgorithmIdentifier shared_key_algorithm , bool extractable , Vector < Bindings : : KeyUsage > key_usages )
{
auto & realm = this - > realm ( ) ;
2025-12-06 17:23:45 -03:00
auto & global = realm . global_object ( ) ;
auto & heap = realm . heap ( ) ;
2025-11-27 15:16:27 -03:00
// 1. Let encapsulationAlgorithm, encapsulationKey, sharedKeyAlgorithm, extractable and usages be the
// encapsulationAlgorithm, encapsulationKey, sharedKeyAlgorithm, extractable and keyUsages parameters passed to
// the encapsulateKey() method, respectively.
// 2. Let normalizedEncapsulationAlgorithm be the result of normalizing an algorithm, with alg set to
// encapsulationAlgorithm and op set to "encapsulate".
auto maybe_normalized_encapsulation_algorithm = normalize_an_algorithm ( realm , encapsulation_algorithm , " encapsulate " _string ) ;
// 3. If an error occurred, return a Promise rejected with normalizedEncapsulationAlgorithm.
if ( maybe_normalized_encapsulation_algorithm . is_error ( ) ) {
return WebIDL : : create_rejected_promise_from_exception ( realm , maybe_normalized_encapsulation_algorithm . exception ( ) ) ;
}
auto normalized_encapsulation_algorithm = maybe_normalized_encapsulation_algorithm . release_value ( ) ;
// 4. Let normalizedSharedKeyAlgorithm be the result of normalizing an algorithm, with alg
// set to sharedKeyAlgorithm and op set to "importKey".
auto maybe_normalized_shared_key_algorithm = normalize_an_algorithm ( realm , shared_key_algorithm , " importKey " _string ) ;
// 5. If an error occurred, return a Promise rejected with normalizedSharedKeyAlgorithm.
if ( maybe_normalized_shared_key_algorithm . is_error ( ) ) {
return WebIDL : : create_rejected_promise_from_exception ( realm , maybe_normalized_shared_key_algorithm . exception ( ) ) ;
}
auto normalized_shared_key_algorithm = maybe_normalized_shared_key_algorithm . release_value ( ) ;
// 6. Let realm be the relevant realm of this.
// 7. Let promise be a new Promise.
auto promise = WebIDL : : create_promise ( realm ) ;
// 8. Return promise and perform the remaining steps in parallel.
2025-12-06 17:23:45 -03:00
Platform : : EventLoopPlugin : : the ( ) . deferred_invoke ( GC : : create_function ( heap , [ & realm , & global , & heap , normalized_encapsulation_algorithm = move ( normalized_encapsulation_algorithm ) , encapsulation_key = encapsulation_key , promise , normalized_shared_key_algorithm = move ( normalized_shared_key_algorithm ) , extractable , usages = move ( key_usages ) ] ( ) mutable - > void {
2025-12-28 21:27:39 -03:00
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
2025-11-27 15:16:27 -03:00
// 9. If the following steps or referenced procedures say to throw an error, queue a global task on the crypto task
// source, given realm's global object, to reject promise with the returned error; and then terminate the algorithm.
2025-12-06 17:23:45 -03:00
auto const throw_in_this_context = [ & realm , & global , & heap , & promise ] ( JS : : Value value ) {
HTML : : queue_global_task ( HTML : : Task : : Source : : Crypto , global , GC : : create_function ( heap , [ & realm , promise , value ] {
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
WebIDL : : reject_promise ( realm , promise , value ) ;
} ) ) ;
} ;
2025-11-27 15:16:27 -03:00
// 10. If the name member of normalizedEncapsulationAlgorithm is not equal to the name attribute of the [[algorithm]]
// internal slot of encapsulationKey then throw an InvalidAccessError.
if ( normalized_encapsulation_algorithm . parameter - > name ! = encapsulation_key - > algorithm_name ( ) ) {
2025-12-06 17:23:45 -03:00
throw_in_this_context ( WebIDL : : InvalidAccessError : : create ( realm , " Invalid encapsulation key algorithm " _utf16 ) ) ;
2025-11-27 15:16:27 -03:00
return ;
}
// 11. If the [[usages]] internal slot of encapsulationKey does not contain an entry that is "encapsulateKey", then
// throw an InvalidAccessError.
2025-11-28 18:47:38 -03:00
if ( ! encapsulation_key - > internal_usages ( ) . contains_slow ( Bindings : : KeyUsage : : Encapsulatekey ) ) {
2025-12-06 17:23:45 -03:00
throw_in_this_context ( WebIDL : : InvalidAccessError : : create ( realm , " Invalid encapsulation key usage " _utf16 ) ) ;
2025-11-27 15:16:27 -03:00
return ;
}
// 12. Let encapsulatedBits be the result of performing the encapsulate operation specified by the [[algorithm]]
// internal slot of encapsulationKey using encapsulationKey.
auto maybe_encapsulated_bits = normalized_encapsulation_algorithm . methods - > encapsulate ( * normalized_encapsulation_algorithm . parameter , encapsulation_key ) ;
if ( maybe_encapsulated_bits . is_error ( ) ) {
2025-12-06 17:23:45 -03:00
throw_in_this_context ( Bindings : : exception_to_throw_completion ( realm . vm ( ) , maybe_encapsulated_bits . release_error ( ) ) . release_value ( ) ) ;
2025-11-27 15:16:27 -03:00
return ;
}
auto encapsulated_bits = maybe_encapsulated_bits . release_value ( ) ;
// 13. Let sharedKey be the result of performing the import key operation specified by
// normalizedSharedKeyAlgorithm using "raw-secret" as format, the sharedKey field of encapsulatedBits as
// keyData, sharedKeyAlgorithm as algorithm and using extractable and usages.
auto maybe_shared_key = normalized_shared_key_algorithm . methods - > import_key (
* normalized_shared_key_algorithm . parameter ,
Bindings : : KeyFormat : : RawSecret ,
2025-11-28 17:54:03 -03:00
encapsulated_bits . shared_key . value ( ) ,
2025-11-27 15:16:27 -03:00
extractable ,
usages ) ;
if ( maybe_shared_key . is_error ( ) ) {
2025-12-06 17:23:45 -03:00
throw_in_this_context ( Bindings : : exception_to_throw_completion ( realm . vm ( ) , maybe_shared_key . release_error ( ) ) . release_value ( ) ) ;
2025-11-27 15:16:27 -03:00
return ;
}
auto shared_key = maybe_shared_key . release_value ( ) ;
2025-11-28 19:56:25 -03:00
// 14. Set the [[extractable]] internal slot of sharedKey to extractable.
shared_key - > set_extractable ( extractable ) ;
// 15. Set the [[usages]] internal slot of sharedKey to the normalized value of usages.
normalize_key_usages ( usages ) ;
shared_key - > set_usages ( usages ) ;
// 16. Let encapsulatedKey be a new EncapsulatedKey dictionary with sharedKey set to sharedKey and ciphertext set
2025-11-27 15:16:27 -03:00
// to the ciphertext field of encapsulatedBits.
2025-11-28 17:54:03 -03:00
auto encapsulated_key = EncapsulatedKey { shared_key , encapsulated_bits . ciphertext } ;
2025-11-27 15:16:27 -03:00
2025-11-28 19:56:25 -03:00
// 17. Queue a global task on the crypto task source, given realm's global object, to perform the remaining steps.
2025-12-06 17:23:45 -03:00
HTML : : queue_global_task ( HTML : : Task : : Source : : Crypto , global , GC : : create_function ( heap , [ & realm , promise , encapsulated_key ] mutable {
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
2025-11-28 19:56:25 -03:00
// 18. Let result be the result of converting encapsulatedKey to an ECMAScript Object in realm, as defined by [WebIDL].
2025-12-06 17:23:45 -03:00
auto maybe_result = encapsulated_key . to_object ( realm ) ;
if ( maybe_result . is_error ( ) ) {
WebIDL : : reject_promise ( realm , promise , maybe_result . release_error ( ) . value ( ) ) ;
return ;
}
auto const result = maybe_result . release_value ( ) ;
2025-11-27 15:16:27 -03:00
2025-11-28 19:56:25 -03:00
// 19. Resolve promise with result.
2025-12-06 17:23:45 -03:00
WebIDL : : resolve_promise ( realm , promise , result ) ;
} ) ) ;
2025-11-27 15:16:27 -03:00
} ) ) ;
return promise ;
}
2025-11-27 15:36:42 -03:00
// https://wicg.github.io/webcrypto-modern-algos/#dfn-SubtleCrypto-method-encapsulateBits
GC : : Ref < WebIDL : : Promise > SubtleCrypto : : encapsulate_bits ( AlgorithmIdentifier encapsulation_algorithm , GC : : Ref < CryptoKey > encapsulation_key )
{
auto & realm = this - > realm ( ) ;
2025-12-06 17:23:45 -03:00
auto & global = realm . global_object ( ) ;
auto & heap = realm . heap ( ) ;
2025-11-27 15:36:42 -03:00
// 1. Let encapsulationAlgorithm and encapsulationKey be the encapsulationAlgorithm and encapsulationKey
// parameters passed to the encapsulateBits() method, respectively.
// 2. Let normalizedEncapsulationAlgorithm be the result of normalizing an algorithm, with alg set to
// encapsulationAlgorithm and op set to "encapsulate".
auto maybe_normalized_encapsulation_algorithm = normalize_an_algorithm ( realm , encapsulation_algorithm , " encapsulate " _string ) ;
// 3. If an error occurred, return a Promise rejected with normalizedEncapsulationAlgorithm.
if ( maybe_normalized_encapsulation_algorithm . is_error ( ) ) {
return WebIDL : : create_rejected_promise_from_exception ( realm , maybe_normalized_encapsulation_algorithm . release_error ( ) ) ;
}
auto normalized_encapsulation_algorithm = maybe_normalized_encapsulation_algorithm . release_value ( ) ;
// 4. Let realm be the relevant realm of this.
// 5. Let promise be a new Promise.
auto promise = WebIDL : : create_promise ( realm ) ;
// 6. Return promise and perform the remaining steps in parallel.
2025-12-06 17:23:45 -03:00
Platform : : EventLoopPlugin : : the ( ) . deferred_invoke ( GC : : create_function ( heap , [ & realm , & global , & heap , normalized_encapsulation_algorithm = move ( normalized_encapsulation_algorithm ) , promise , encapsulation_key = encapsulation_key ] ( ) mutable - > void {
2025-12-28 21:27:39 -03:00
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
2025-11-27 15:36:42 -03:00
// 7. If the following steps or referenced procedures say to throw an error, queue a global task on the crypto task
// source, given realm's global object, to reject promise with the returned error; and then terminate the algorithm.
2025-12-06 17:23:45 -03:00
auto const throw_in_this_context = [ & realm , & global , & heap , & promise ] ( JS : : Value value ) {
HTML : : queue_global_task ( HTML : : Task : : Source : : Crypto , global , GC : : create_function ( heap , [ & realm , promise , value ] {
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
WebIDL : : reject_promise ( realm , promise , value ) ;
} ) ) ;
} ;
2025-11-27 15:36:42 -03:00
// 8. If the name member of normalizedEncapsulationAlgorithm is not equal to the name attribute of the [[algorithm]]
// internal slot of encapsulationKey then throw an InvalidAccessError.
if ( normalized_encapsulation_algorithm . parameter - > name ! = encapsulation_key - > algorithm_name ( ) ) {
2025-12-06 17:23:45 -03:00
throw_in_this_context ( WebIDL : : InvalidAccessError : : create ( realm , " Invalid encapsulation key algorithm " _utf16 ) ) ;
2025-11-27 15:36:42 -03:00
return ;
}
// 9. If the [[usages]] internal slot of encapsulationKey does not contain an entry that is "encapsulateBits", then
// throw an InvalidAccessError.
2025-11-28 18:47:38 -03:00
if ( ! encapsulation_key - > internal_usages ( ) . contains_slow ( Bindings : : KeyUsage : : Encapsulatebits ) ) {
2025-12-06 17:23:45 -03:00
throw_in_this_context ( WebIDL : : InvalidAccessError : : create ( realm , " Invalid encapsulation key usages " _utf16 ) ) ;
2025-11-27 15:36:42 -03:00
return ;
}
// 10. Let encapsulatedBits be the result of performing the encapsulate operation specified by the [[algorithm]]
// internal slot of encapsulationKey using encapsulationKey.
auto maybe_encapsulated_bits = normalized_encapsulation_algorithm . methods - > encapsulate ( * normalized_encapsulation_algorithm . parameter , encapsulation_key ) ;
if ( maybe_encapsulated_bits . is_error ( ) ) {
2025-12-06 17:23:45 -03:00
throw_in_this_context ( Bindings : : exception_to_throw_completion ( realm . vm ( ) , maybe_encapsulated_bits . release_error ( ) ) . release_value ( ) ) ;
2025-11-27 15:36:42 -03:00
return ;
}
auto encapsulated_bits = maybe_encapsulated_bits . release_value ( ) ;
// 11. Queue a global task on the crypto task source, given realm's global object, to perform the remaining steps.
2025-12-06 17:23:45 -03:00
HTML : : queue_global_task ( HTML : : Task : : Source : : Crypto , global , GC : : create_function ( heap , [ & realm , promise , encapsulated_bits ] {
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
2025-11-27 15:36:42 -03:00
2025-12-06 17:23:45 -03:00
// 12. Let result be the result of converting encapsulatedBits to an ECMAScript Object in realm, as defined by [WebIDL].
2025-11-28 17:54:03 -03:00
auto maybe_result = encapsulated_bits . to_object ( realm ) ;
2025-12-06 17:23:45 -03:00
if ( maybe_result . is_error ( ) ) {
WebIDL : : reject_promise ( realm , promise , maybe_result . release_error ( ) . value ( ) ) ;
return ;
}
auto const result = maybe_result . release_value ( ) ;
// 13. Resolve promise with result.
WebIDL : : resolve_promise ( realm , promise , result ) ;
} ) ) ;
2025-11-27 15:36:42 -03:00
} ) ) ;
return promise ;
}
2025-12-06 16:22:19 -03:00
// https://wicg.github.io/webcrypto-modern-algos/#dfn-SubtleCrypto-method-decapsulateKey
2026-05-28 18:14:33 -03:00
GC : : Ref < WebIDL : : Promise > SubtleCrypto : : decapsulate_key ( AlgorithmIdentifier decapsulation_algorithm , GC : : Ref < CryptoKey > decapsulation_key , WebIDL : : BufferSource ciphertext , AlgorithmIdentifier shared_key_algorithm , bool extractable , Vector < Bindings : : KeyUsage > const & usages )
2025-12-06 16:22:19 -03:00
{
auto & realm = this - > realm ( ) ;
2025-12-06 17:23:45 -03:00
auto & global = realm . global_object ( ) ;
auto & heap = realm . heap ( ) ;
2025-12-06 16:22:19 -03:00
// 1. Let decapsulationAlgorithm, decapsulationKey, sharedKeyAlgorithm, extractable and usages be the
// decapsulationAlgorithm, decapsulationKey, sharedKeyAlgorithm, extractable and keyUsages parameters passed to
// the decapsulateKey() method, respectively.
// 2. Let ciphertext be the result of getting a copy of the bytes held by the ciphertext parameter passed to the
// decapsulateKey() method.
2026-05-28 18:14:33 -03:00
auto cipher_text = MUST ( WebIDL : : get_buffer_source_copy ( ciphertext ) ) ;
2025-12-06 16:22:19 -03:00
// 3. Let normalizedDecapsulationAlgorithm be the result of normalizing an algorithm, with alg set to
// decapsulationAlgorithm and op set to "decapsulate".
auto normalized_decapsulation_algorithm = normalize_an_algorithm ( realm , decapsulation_algorithm , " decapsulate " _string ) ;
// 4. If an error occurred, return a Promise rejected with normalizedDecapsulationAlgorithm.
if ( normalized_decapsulation_algorithm . is_error ( ) ) {
return WebIDL : : create_rejected_promise_from_exception ( realm , normalized_decapsulation_algorithm . release_error ( ) ) ;
}
// 5. Let normalizedSharedKeyAlgorithm be the result of normalizing an algorithm, with alg
// set to sharedKeyAlgorithm and op set to "importKey".
auto normalized_shared_key_algorithm = normalize_an_algorithm ( realm , shared_key_algorithm , " importKey " _string ) ;
// 6. If an error occurred, return a Promise rejected with normalizedSharedKeyAlgorithm.
if ( normalized_shared_key_algorithm . is_error ( ) ) {
return WebIDL : : create_rejected_promise_from_exception ( realm , normalized_shared_key_algorithm . release_error ( ) ) ;
}
// 7. Let realm be the relevant realm of this.
// 8. Let promise be a new Promise.
auto promise = WebIDL : : create_promise ( realm ) ;
// 9. Return promise and perform the remaining steps in parallel.
2025-12-06 17:23:45 -03:00
Platform : : EventLoopPlugin : : the ( ) . deferred_invoke ( GC : : create_function ( heap , [ & realm , & global , & heap , normalized_decapsulation_algorithm = normalized_decapsulation_algorithm . release_value ( ) , promise , decapsulation_key , cipher_text = move ( cipher_text ) , normalized_shared_key_algorithm = normalized_shared_key_algorithm . release_value ( ) , extractable , usages ] ( ) - > void {
2025-12-06 16:22:19 -03:00
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
// 10. If the following steps or referenced procedures say to throw an error, queue a global task on the crypto task
// source, given realm's global object, to reject promise with the returned error; and then terminate the algorithm.
2025-12-06 17:23:45 -03:00
auto const throw_in_this_context = [ & realm , & global , & heap , & promise ] ( JS : : Value value ) {
HTML : : queue_global_task ( HTML : : Task : : Source : : Crypto , global , GC : : create_function ( heap , [ & realm , promise , value ] {
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
WebIDL : : reject_promise ( realm , promise , value ) ;
} ) ) ;
} ;
2025-12-06 16:22:19 -03:00
// 11. If the name member of normalizedDecapsulationAlgorithm is not equal to the name attribute of the [[algorithm]]
// internal slot of decapsulationKey then throw an InvalidAccessError.
if ( normalized_decapsulation_algorithm . parameter - > name ! = decapsulation_key - > algorithm_name ( ) ) {
2025-12-06 17:23:45 -03:00
throw_in_this_context ( WebIDL : : InvalidAccessError : : create ( realm , " Invalid algorithm name " _utf16 ) ) ;
2025-12-06 16:22:19 -03:00
return ;
}
// 12. If the [[usages]] internal slot of decapsulationKey does not contain an entry that is "decapsulateKey", then
// throw an InvalidAccessError.
if ( ! decapsulation_key - > internal_usages ( ) . contains_slow ( Bindings : : KeyUsage : : Decapsulatekey ) ) {
2025-12-06 17:23:45 -03:00
throw_in_this_context ( WebIDL : : InvalidAccessError : : create ( realm , " Invalid key usages " _utf16 ) ) ;
2025-12-06 16:22:19 -03:00
return ;
}
// 13. Let decapsulatedBits be the result of performing the decapsulate operation specified by the [[algorithm]]
// internal slot of decapsulationKey using decapsulationKey and ciphertext.
auto maybe_decapsulated_bits = normalized_decapsulation_algorithm . methods - > decapsulate (
* normalized_decapsulation_algorithm . parameter ,
2026-01-04 17:01:01 -03:00
decapsulation_key ,
2025-12-06 16:22:19 -03:00
cipher_text ) ;
if ( maybe_decapsulated_bits . is_error ( ) ) {
2025-12-06 17:23:45 -03:00
throw_in_this_context ( Bindings : : exception_to_throw_completion ( realm . vm ( ) , maybe_decapsulated_bits . release_error ( ) ) . release_value ( ) ) ;
2025-12-06 16:22:19 -03:00
return ;
}
auto const decapsulated_bits = maybe_decapsulated_bits . release_value ( ) ;
// 14. Let sharedKey be the result of performing the import key operation specified by
// normalizedSharedKeyAlgorithm using "raw-secret" as format, the decapsulatedBits as keyData,
// sharedKeyAlgorithm as algorithm and using extractable and usages.
auto maybe_shared_key = normalized_shared_key_algorithm . methods - > import_key (
2026-01-04 17:29:21 -03:00
* normalized_shared_key_algorithm . parameter ,
2025-12-06 16:22:19 -03:00
Bindings : : KeyFormat : : RawSecret ,
2026-04-04 14:25:48 -03:00
MUST ( ByteBuffer : : copy ( decapsulated_bits - > bytes ( ) ) ) ,
2025-12-06 16:22:19 -03:00
extractable ,
usages ) ;
if ( maybe_shared_key . is_error ( ) ) {
2025-12-06 17:23:45 -03:00
throw_in_this_context ( Bindings : : exception_to_throw_completion ( realm . vm ( ) , maybe_shared_key . release_error ( ) ) . release_value ( ) ) ;
2025-12-06 16:22:19 -03:00
return ;
}
auto const shared_key = maybe_shared_key . release_value ( ) ;
// 15. Set the [[extractable]] internal slot of sharedKey to extractable.
shared_key - > set_extractable ( extractable ) ;
// 16. Set the [[usages]] internal slot of sharedKey to the normalized value of usages.
shared_key - > set_usages ( usages ) ;
// 17. Queue a global task on the crypto task source, given realm's global object, to perform the remaining steps.
2025-12-06 17:23:45 -03:00
HTML : : queue_global_task ( HTML : : Task : : Source : : Crypto , global , GC : : create_function ( heap , [ & realm , promise , shared_key ] {
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
// 18. Let result be the result of converting sharedKey to an ECMAScript Object in realm, as defined by [WebIDL].
// 19. Resolve promise with result.
WebIDL : : resolve_promise ( realm , promise , shared_key ) ;
} ) ) ;
2025-12-06 16:22:19 -03:00
} ) ) ;
return promise ;
}
2025-12-06 16:36:12 -03:00
// https://wicg.github.io/webcrypto-modern-algos/#dfn-SubtleCrypto-method-decapsulateBits
2026-05-28 18:14:33 -03:00
GC : : Ref < WebIDL : : Promise > SubtleCrypto : : decapsulate_bits ( AlgorithmIdentifier decapsulation_algorithm , GC : : Ref < CryptoKey > decapsulation_key , WebIDL : : BufferSource ciphertext )
2025-12-06 16:36:12 -03:00
{
auto & realm = this - > realm ( ) ;
2025-12-06 17:23:45 -03:00
auto & global = realm . global_object ( ) ;
auto & heap = realm . heap ( ) ;
2025-12-06 16:36:12 -03:00
// 1. Let decapsulationAlgorithm and decapsulationKey be the decapsulationAlgorithm and decapsulationKey
// parameters passed to the decapsulateBits() method, respectively.
// 2. Let ciphertext be the result of getting a copy of the bytes held by the ciphertext parameter passed to the
// decapsulateBits() method.
2026-05-28 18:14:33 -03:00
auto cipher_text = MUST ( WebIDL : : get_buffer_source_copy ( ciphertext ) ) ;
2025-12-06 16:36:12 -03:00
// 3. Let normalizedDecapsulationAlgorithm be the result of normalizing an algorithm, with alg set to
// decapsulationAlgorithm and op set to "decapsulate".
auto normalized_decapsulation_algorithm = normalize_an_algorithm ( realm , decapsulation_algorithm , " decapsulate " _string ) ;
// 4. If an error occurred, return a Promise rejected with normalizedDecapsulationAlgorithm.
if ( normalized_decapsulation_algorithm . is_error ( ) ) {
return WebIDL : : create_rejected_promise_from_exception ( realm , normalized_decapsulation_algorithm . release_error ( ) ) ;
}
// 5. Let realm be the relevant realm of this.
// 6. Let promise be a new Promise.
auto promise = WebIDL : : create_promise ( realm ) ;
// 7. Return promise and perform the remaining steps in parallel.
2025-12-06 17:23:45 -03:00
Platform : : EventLoopPlugin : : the ( ) . deferred_invoke ( GC : : create_function ( heap , [ & realm , & global , & heap , normalized_decapsulation_algorithm = normalized_decapsulation_algorithm . release_value ( ) , promise , decapsulation_key , cipher_text = move ( cipher_text ) ] ( ) - > void {
2025-12-28 21:27:39 -03:00
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
2025-12-06 16:36:12 -03:00
// 8. If the following steps or referenced procedures say to throw an error, queue a global task on the crypto task
// source, given realm's global object, to reject promise with the returned error; and then terminate the algorithm.
2025-12-06 17:23:45 -03:00
auto const throw_in_this_context = [ & realm , & global , & heap , & promise ] ( JS : : Value value ) {
HTML : : queue_global_task ( HTML : : Task : : Source : : Crypto , global , GC : : create_function ( heap , [ & realm , promise , value ] {
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
WebIDL : : reject_promise ( realm , promise , value ) ;
} ) ) ;
} ;
2025-12-06 16:36:12 -03:00
// 9. If the name member of normalizedDecapsulationAlgorithm is not equal to the name attribute of the [[algorithm]]
// internal slot of decapsulationKey then throw an InvalidAccessError.
if ( normalized_decapsulation_algorithm . parameter - > name ! = decapsulation_key - > algorithm_name ( ) ) {
2025-12-06 17:23:45 -03:00
throw_in_this_context ( WebIDL : : InvalidAccessError : : create ( realm , " Invalid algorithm name " _utf16 ) ) ;
2025-12-06 16:36:12 -03:00
return ;
}
// 10. If the [[usages]] internal slot of decapsulationKey does not contain an entry that is "decapsulateBits", then
// throw an InvalidAccessError.
if ( ! decapsulation_key - > internal_usages ( ) . contains_slow ( Bindings : : KeyUsage : : Decapsulatebits ) ) {
2025-12-06 17:23:45 -03:00
throw_in_this_context ( WebIDL : : InvalidAccessError : : create ( realm , " Invalid key usages " _utf16 ) ) ;
2025-12-06 16:36:12 -03:00
return ;
}
// 11. Let decapsulatedBits be the result of performing the decapsulate operation specified by the [[algorithm]]
// internal slot of decapsulationKey using decapsulationKey and ciphertext.
auto maybe_decapsulated_bits = normalized_decapsulation_algorithm . methods - > decapsulate (
* normalized_decapsulation_algorithm . parameter ,
2026-01-04 17:01:01 -03:00
decapsulation_key ,
2025-12-06 16:36:12 -03:00
cipher_text ) ;
if ( maybe_decapsulated_bits . is_error ( ) ) {
2025-12-06 17:23:45 -03:00
throw_in_this_context ( Bindings : : exception_to_throw_completion ( realm . vm ( ) , maybe_decapsulated_bits . release_error ( ) ) . release_value ( ) ) ;
2025-12-06 16:36:12 -03:00
return ;
}
auto const decapsulated_bits = maybe_decapsulated_bits . release_value ( ) ;
// 12. Queue a global task on the crypto task source, given realm's global object, to perform the remaining steps.
2025-12-06 17:23:45 -03:00
HTML : : queue_global_task ( HTML : : Task : : Source : : Crypto , global , GC : : create_function ( heap , [ & realm , promise , decapsulated_bits ] {
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
// 13. Let result be the result of creating an ArrayBuffer in realm, containing decapsulatedBits.
// 14. Resolve promise with result.
WebIDL : : resolve_promise ( realm , promise , decapsulated_bits ) ;
} ) ) ;
2025-12-06 16:36:12 -03:00
} ) ) ;
return promise ;
}
2024-03-15 00:52:17 -03:00
SupportedAlgorithmsMap & supported_algorithms_internal ( )
2023-12-13 20:38:14 -03:00
{
2026-06-04 05:40:32 -03:00
static NeverDestroyed < SupportedAlgorithmsMap > supported_algorithms ;
return * supported_algorithms ;
2023-12-13 20:38:14 -03:00
}
2025-11-21 21:23:09 -03:00
// https://w3c.github.io/webcrypto/#algorithm-normalization-internal
2024-11-24 16:53:41 -03:00
SupportedAlgorithmsMap const & supported_algorithms ( )
2023-12-13 20:38:14 -03:00
{
auto & internal_object = supported_algorithms_internal ( ) ;
if ( ! internal_object . is_empty ( ) ) {
return internal_object ;
}
// 1. For each value, v in the List of supported operations,
// set the v key of the internal object supportedAlgorithms to a new associative container.
auto supported_operations = Vector {
" encrypt " _string ,
" decrypt " _string ,
" sign " _string ,
" verify " _string ,
" digest " _string ,
" deriveBits " _string ,
" wrapKey " _string ,
" unwrapKey " _string ,
" generateKey " _string ,
" importKey " _string ,
" exportKey " _string ,
" get key length " _string ,
2025-11-28 17:54:54 -03:00
" encapsulate " _string ,
" decapsulate " _string
2023-12-13 20:38:14 -03:00
} ;
for ( auto & operation : supported_operations ) {
internal_object . set ( operation , { } ) ;
}
// https://w3c.github.io/webcrypto/#algorithm-conventions
2024-11-01 12:35:30 -03:00
// https://w3c.github.io/webcrypto/#rsassa-pkcs1-registration
2024-12-26 14:55:31 -03:00
define_an_algorithm < RSASSAPKCS1 > ( " sign " _string , " RSASSA-PKCS1-v1_5 " _string ) ;
define_an_algorithm < RSASSAPKCS1 > ( " verify " _string , " RSASSA-PKCS1-v1_5 " _string ) ;
define_an_algorithm < RSASSAPKCS1 , RsaHashedKeyGenParams > ( " generateKey " _string , " RSASSA-PKCS1-v1_5 " _string ) ;
define_an_algorithm < RSASSAPKCS1 , RsaHashedImportParams > ( " importKey " _string , " RSASSA-PKCS1-v1_5 " _string ) ;
define_an_algorithm < RSASSAPKCS1 > ( " exportKey " _string , " RSASSA-PKCS1-v1_5 " _string ) ;
2024-11-01 12:35:30 -03:00
// https://w3c.github.io/webcrypto/#rsa-pss-registration
2024-12-25 19:47:06 -03:00
define_an_algorithm < RSAPSS , RsaPssParams > ( " sign " _string , " RSA-PSS " _string ) ;
define_an_algorithm < RSAPSS , RsaPssParams > ( " verify " _string , " RSA-PSS " _string ) ;
define_an_algorithm < RSAPSS , RsaHashedKeyGenParams > ( " generateKey " _string , " RSA-PSS " _string ) ;
define_an_algorithm < RSAPSS , RsaHashedImportParams > ( " importKey " _string , " RSA-PSS " _string ) ;
define_an_algorithm < RSAPSS > ( " exportKey " _string , " RSA-PSS " _string ) ;
2024-11-01 12:35:30 -03:00
// https://w3c.github.io/webcrypto/#rsa-oaep-registration
define_an_algorithm < RSAOAEP , RsaOaepParams > ( " encrypt " _string , " RSA-OAEP " _string ) ;
define_an_algorithm < RSAOAEP , RsaOaepParams > ( " decrypt " _string , " RSA-OAEP " _string ) ;
define_an_algorithm < RSAOAEP , RsaHashedKeyGenParams > ( " generateKey " _string , " RSA-OAEP " _string ) ;
define_an_algorithm < RSAOAEP , RsaHashedImportParams > ( " importKey " _string , " RSA-OAEP " _string ) ;
define_an_algorithm < RSAOAEP > ( " exportKey " _string , " RSA-OAEP " _string ) ;
// https://w3c.github.io/webcrypto/#ecdsa-registration
define_an_algorithm < ECDSA , EcdsaParams > ( " sign " _string , " ECDSA " _string ) ;
define_an_algorithm < ECDSA , EcdsaParams > ( " verify " _string , " ECDSA " _string ) ;
define_an_algorithm < ECDSA , EcKeyGenParams > ( " generateKey " _string , " ECDSA " _string ) ;
2024-12-02 13:36:21 -03:00
define_an_algorithm < ECDSA , EcKeyImportParams > ( " importKey " _string , " ECDSA " _string ) ;
define_an_algorithm < ECDSA > ( " exportKey " _string , " ECDSA " _string ) ;
2024-11-01 12:35:30 -03:00
// https://w3c.github.io/webcrypto/#ecdh-registration
2024-11-26 15:46:04 -03:00
define_an_algorithm < ECDH , EcKeyImportParams > ( " importKey " _string , " ECDH " _string ) ;
2024-11-26 16:26:48 -03:00
define_an_algorithm < ECDH > ( " exportKey " _string , " ECDH " _string ) ;
2024-11-27 16:31:37 -03:00
define_an_algorithm < ECDH , EcdhKeyDeriveParams > ( " deriveBits " _string , " ECDH " _string ) ;
2024-11-17 14:14:13 -03:00
define_an_algorithm < ECDH , EcKeyGenParams > ( " generateKey " _string , " ECDH " _string ) ;
2024-10-25 00:58:30 -03:00
2024-10-30 18:44:20 -03:00
// https://w3c.github.io/webcrypto/#aes-ctr-registration
2024-10-30 19:53:48 -03:00
define_an_algorithm < AesCtr , AesCtrParams > ( " encrypt " _string , " AES-CTR " _string ) ;
2024-10-30 20:28:41 -03:00
define_an_algorithm < AesCtr , AesCtrParams > ( " decrypt " _string , " AES-CTR " _string ) ;
2024-11-01 12:35:30 -03:00
define_an_algorithm < AesCtr , AesKeyGenParams > ( " generateKey " _string , " AES-CTR " _string ) ;
2024-10-30 18:44:20 -03:00
define_an_algorithm < AesCtr > ( " importKey " _string , " AES-CTR " _string ) ;
2024-10-30 19:06:13 -03:00
define_an_algorithm < AesCtr > ( " exportKey " _string , " AES-CTR " _string ) ;
2024-10-30 18:53:47 -03:00
define_an_algorithm < AesCtr , AesDerivedKeyParams > ( " get key length " _string , " AES-CTR " _string ) ;
2024-11-01 12:35:30 -03:00
// https://w3c.github.io/webcrypto/#aes-cbc-registration
define_an_algorithm < AesCbc , AesCbcParams > ( " encrypt " _string , " AES-CBC " _string ) ;
define_an_algorithm < AesCbc , AesCbcParams > ( " decrypt " _string , " AES-CBC " _string ) ;
define_an_algorithm < AesCbc , AesKeyGenParams > ( " generateKey " _string , " AES-CBC " _string ) ;
define_an_algorithm < AesCbc > ( " importKey " _string , " AES-CBC " _string ) ;
define_an_algorithm < AesCbc > ( " exportKey " _string , " AES-CBC " _string ) ;
define_an_algorithm < AesCbc , AesDerivedKeyParams > ( " get key length " _string , " AES-CBC " _string ) ;
2024-10-30 18:44:20 -03:00
2024-10-31 11:57:19 -03:00
// https://w3c.github.io/webcrypto/#aes-gcm-registration
2024-10-31 12:29:39 -03:00
define_an_algorithm < AesGcm , AesGcmParams > ( " encrypt " _string , " AES-GCM " _string ) ;
2024-10-31 12:37:51 -03:00
define_an_algorithm < AesGcm , AesGcmParams > ( " decrypt " _string , " AES-GCM " _string ) ;
2024-11-01 12:35:30 -03:00
define_an_algorithm < AesGcm , AesKeyGenParams > ( " generateKey " _string , " AES-GCM " _string ) ;
define_an_algorithm < AesGcm > ( " importKey " _string , " AES-GCM " _string ) ;
define_an_algorithm < AesGcm > ( " exportKey " _string , " AES-GCM " _string ) ;
define_an_algorithm < AesGcm , AesDerivedKeyParams > ( " get key length " _string , " AES-GCM " _string ) ;
2024-10-31 11:57:19 -03:00
2024-11-01 12:35:30 -03:00
// https://w3c.github.io/webcrypto/#aes-kw-registration
2024-12-16 15:38:10 -03:00
define_an_algorithm < AesKw > ( " wrapKey " _string , " AES-KW " _string ) ;
define_an_algorithm < AesKw > ( " unwrapKey " _string , " AES-KW " _string ) ;
define_an_algorithm < AesKw , AesKeyGenParams > ( " generateKey " _string , " AES-KW " _string ) ;
define_an_algorithm < AesKw > ( " importKey " _string , " AES-KW " _string ) ;
define_an_algorithm < AesKw > ( " exportKey " _string , " AES-KW " _string ) ;
define_an_algorithm < AesKw , AesDerivedKeyParams > ( " get key length " _string , " AES-KW " _string ) ;
2024-11-01 12:35:30 -03:00
// https://w3c.github.io/webcrypto/#hmac-registration
2024-11-13 11:23:50 -03:00
define_an_algorithm < HMAC > ( " sign " _string , " HMAC " _string ) ;
define_an_algorithm < HMAC > ( " verify " _string , " HMAC " _string ) ;
define_an_algorithm < HMAC , HmacKeyGenParams > ( " generateKey " _string , " HMAC " _string ) ;
define_an_algorithm < HMAC , HmacImportParams > ( " importKey " _string , " HMAC " _string ) ;
define_an_algorithm < HMAC > ( " exportKey " _string , " HMAC " _string ) ;
define_an_algorithm < HMAC , HmacImportParams > ( " get key length " _string , " HMAC " _string ) ;
2024-11-01 12:35:30 -03:00
// https://w3c.github.io/webcrypto/#sha-registration
define_an_algorithm < SHA > ( " digest " _string , " SHA-1 " _string ) ;
define_an_algorithm < SHA > ( " digest " _string , " SHA-256 " _string ) ;
define_an_algorithm < SHA > ( " digest " _string , " SHA-384 " _string ) ;
define_an_algorithm < SHA > ( " digest " _string , " SHA-512 " _string ) ;
2025-11-26 15:37:04 -03:00
// https://wicg.github.io/webcrypto-modern-algos/#sha3-registration
define_an_algorithm < SHA > ( " digest " _string , " SHA3-256 " _string ) ;
define_an_algorithm < SHA > ( " digest " _string , " SHA3-384 " _string ) ;
define_an_algorithm < SHA > ( " digest " _string , " SHA3-512 " _string ) ;
2026-01-16 19:52:12 -03:00
// https://wicg.github.io/webcrypto-modern-algos/#cshake-registration
define_an_algorithm < CShake , CShakeParams > ( " digest " _string , " cSHAKE128 " _string ) ;
define_an_algorithm < CShake , CShakeParams > ( " digest " _string , " cSHAKE256 " _string ) ;
2024-11-01 12:35:30 -03:00
// https://w3c.github.io/webcrypto/#hkdf-registration
2024-10-20 01:10:36 -03:00
define_an_algorithm < HKDF , HKDFParams > ( " deriveBits " _string , " HKDF " _string ) ;
2024-11-01 12:35:30 -03:00
define_an_algorithm < HKDF > ( " importKey " _string , " HKDF " _string ) ;
2024-10-20 01:10:36 -03:00
define_an_algorithm < HKDF > ( " get key length " _string , " HKDF " _string ) ;
2024-11-01 12:35:30 -03:00
// https://w3c.github.io/webcrypto/#pbkdf2-registration
2024-03-27 15:53:08 -03:00
define_an_algorithm < PBKDF2 , PBKDF2Params > ( " deriveBits " _string , " PBKDF2 " _string ) ;
2024-11-01 12:35:30 -03:00
define_an_algorithm < PBKDF2 > ( " importKey " _string , " PBKDF2 " _string ) ;
2024-03-27 16:30:11 -03:00
define_an_algorithm < PBKDF2 > ( " get key length " _string , " PBKDF2 " _string ) ;
2023-12-15 18:03:04 -03:00
2024-11-01 12:35:30 -03:00
// https://wicg.github.io/webcrypto-secure-curves/#x25519-registration
2024-11-27 16:31:37 -03:00
define_an_algorithm < X25519 , EcdhKeyDeriveParams > ( " deriveBits " _string , " X25519 " _string ) ;
2024-11-01 12:35:30 -03:00
define_an_algorithm < X25519 > ( " generateKey " _string , " X25519 " _string ) ;
define_an_algorithm < X25519 > ( " importKey " _string , " X25519 " _string ) ;
define_an_algorithm < X25519 > ( " exportKey " _string , " X25519 " _string ) ;
2024-03-08 20:30:17 -03:00
2024-11-01 12:35:30 -03:00
// https://wicg.github.io/webcrypto-secure-curves/#x448-registration
2024-11-27 16:31:37 -03:00
define_an_algorithm < X448 , EcdhKeyDeriveParams > ( " deriveBits " _string , " X448 " _string ) ;
2024-11-25 07:18:05 -03:00
define_an_algorithm < X448 > ( " generateKey " _string , " X448 " _string ) ;
2024-11-25 11:46:21 -03:00
define_an_algorithm < X448 > ( " importKey " _string , " X448 " _string ) ;
2024-11-25 07:35:09 -03:00
define_an_algorithm < X448 > ( " exportKey " _string , " X448 " _string ) ;
2024-03-26 21:27:42 -03:00
2024-11-01 12:35:30 -03:00
// https://wicg.github.io/webcrypto-secure-curves/#ed25519-registration
2024-03-31 18:04:58 -03:00
define_an_algorithm < ED25519 > ( " sign " _string , " Ed25519 " _string ) ;
2024-03-31 18:05:05 -03:00
define_an_algorithm < ED25519 > ( " verify " _string , " Ed25519 " _string ) ;
2024-03-31 18:04:12 -03:00
define_an_algorithm < ED25519 > ( " generateKey " _string , " Ed25519 " _string ) ;
2024-11-24 16:21:51 -03:00
define_an_algorithm < ED25519 > ( " importKey " _string , " Ed25519 " _string ) ;
2024-11-24 16:48:46 -03:00
define_an_algorithm < ED25519 > ( " exportKey " _string , " Ed25519 " _string ) ;
2024-11-01 12:35:30 -03:00
// https://wicg.github.io/webcrypto-secure-curves/#ed448-registration
2024-12-21 10:45:29 -03:00
define_an_algorithm < ED448 , Ed448Params > ( " sign " _string , " Ed448 " _string ) ;
define_an_algorithm < ED448 , Ed448Params > ( " verify " _string , " Ed448 " _string ) ;
define_an_algorithm < ED448 > ( " generateKey " _string , " Ed448 " _string ) ;
define_an_algorithm < ED448 > ( " importKey " _string , " Ed448 " _string ) ;
define_an_algorithm < ED448 > ( " exportKey " _string , " Ed448 " _string ) ;
2024-10-26 14:57:59 -03:00
2025-11-21 21:43:10 -03:00
// https://wicg.github.io/webcrypto-modern-algos/#ml-dsa-registration
for ( auto const & name : { " ML-DSA-44 " _string , " ML-DSA-65 " _string , " ML-DSA-87 " _string } ) {
2025-11-22 18:13:01 -03:00
define_an_algorithm < MLDSA , ContextParams > ( " sign " _string , name ) ;
2025-11-22 18:52:06 -03:00
define_an_algorithm < MLDSA , ContextParams > ( " verify " _string , name ) ;
2025-11-21 21:43:10 -03:00
define_an_algorithm < MLDSA > ( " generateKey " _string , name ) ;
2025-11-23 19:25:32 -03:00
define_an_algorithm < MLDSA > ( " importKey " _string , name ) ;
2025-11-23 20:39:43 -03:00
define_an_algorithm < MLDSA > ( " exportKey " _string , name ) ;
2025-11-21 21:43:10 -03:00
}
2025-11-28 14:04:13 -03:00
// https://wicg.github.io/webcrypto-modern-algos/#ml-kem-registration
for ( auto const & name : { " ML-KEM-512 " _string , " ML-KEM-768 " _string , " ML-KEM-1024 " _string } ) {
define_an_algorithm < MLKEM > ( " generateKey " _string , name ) ;
2025-11-28 18:06:58 -03:00
define_an_algorithm < MLKEM > ( " importKey " _string , name ) ;
2025-12-30 19:07:36 -03:00
define_an_algorithm < MLKEM > ( " exportKey " _string , name ) ;
2025-11-28 17:54:54 -03:00
define_an_algorithm < MLKEM > ( " encapsulate " _string , name ) ;
2026-01-04 17:27:07 -03:00
define_an_algorithm < MLKEM > ( " decapsulate " _string , name ) ;
2025-11-28 14:04:13 -03:00
}
2025-11-26 20:50:18 -03:00
// https://wicg.github.io/webcrypto-modern-algos/#argon2-registration
for ( auto const & algorithm : { " Argon2d " _string , " Argon2i " _string , " Argon2id " _string } ) {
2025-11-26 21:02:28 -03:00
define_an_algorithm < Argon2 > ( " importKey " _string , algorithm ) ;
2025-11-26 22:44:23 -03:00
define_an_algorithm < Argon2 , Argon2Params > ( " deriveBits " _string , algorithm ) ;
2025-11-26 20:50:18 -03:00
define_an_algorithm < Argon2 > ( " get key length " _string , algorithm ) ;
}
2026-01-21 16:36:07 -03:00
// https://wicg.github.io/webcrypto-modern-algos/#chacha20-poly1305-registration
define_an_algorithm < ChaCha20Poly1305 , AeadParams > ( " encrypt " _string , " ChaCha20-Poly1305 " _string ) ;
define_an_algorithm < ChaCha20Poly1305 , AeadParams > ( " decrypt " _string , " ChaCha20-Poly1305 " _string ) ;
define_an_algorithm < ChaCha20Poly1305 > ( " generateKey " _string , " ChaCha20-Poly1305 " _string ) ;
define_an_algorithm < ChaCha20Poly1305 > ( " importKey " _string , " ChaCha20-Poly1305 " _string ) ;
define_an_algorithm < ChaCha20Poly1305 > ( " exportKey " _string , " ChaCha20-Poly1305 " _string ) ;
define_an_algorithm < ChaCha20Poly1305 > ( " get key length " _string , " ChaCha20-Poly1305 " _string ) ;
2026-02-06 19:28:32 -03:00
// https://wicg.github.io/webcrypto-modern-algos/#aes-ocb-registration
define_an_algorithm < AesOcb , AeadParams > ( " encrypt " _string , " AES-OCB " _string ) ;
define_an_algorithm < AesOcb , AeadParams > ( " decrypt " _string , " AES-OCB " _string ) ;
define_an_algorithm < AesOcb , AesKeyGenParams > ( " generateKey " _string , " AES-OCB " _string ) ;
define_an_algorithm < AesOcb > ( " importKey " _string , " AES-OCB " _string ) ;
define_an_algorithm < AesOcb > ( " exportKey " _string , " AES-OCB " _string ) ;
define_an_algorithm < AesOcb , AesDerivedKeyParams > ( " get key length " _string , " AES-OCB " _string ) ;
2026-03-15 04:09:09 -03:00
// https://wicg.github.io/webcrypto-modern-algos/#kmac-registration
for ( auto const & algorithm : { " KMAC128 " _string , " KMAC256 " _string } ) {
define_an_algorithm < KMAC , KmacParams > ( " sign " _string , algorithm ) ;
define_an_algorithm < KMAC , KmacParams > ( " verify " _string , algorithm ) ;
define_an_algorithm < KMAC , KmacKeyGenParams > ( " generateKey " _string , algorithm ) ;
define_an_algorithm < KMAC , KmacImportParams > ( " importKey " _string , algorithm ) ;
define_an_algorithm < KMAC > ( " exportKey " _string , algorithm ) ;
define_an_algorithm < KMAC , KmacImportParams > ( " get key length " _string , algorithm ) ;
}
2023-12-13 20:38:14 -03:00
return internal_object ;
}
// https://w3c.github.io/webcrypto/#concept-define-an-algorithm
2024-03-06 20:53:50 -03:00
template < typename Methods , typename Param >
2024-03-15 00:52:17 -03:00
void define_an_algorithm ( AK : : String op , AK : : String algorithm )
2023-12-13 20:38:14 -03:00
{
auto & internal_object = supported_algorithms_internal ( ) ;
// 1. Let registeredAlgorithms be the associative container stored at the op key of supportedAlgorithms.
// NOTE: There should always be a container at the op key.
auto maybe_registered_algorithms = internal_object . get ( op ) ;
auto registered_algorithms = maybe_registered_algorithms . value ( ) ;
// 2. Set the alg key of registeredAlgorithms to the IDL dictionary type type.
2024-03-06 20:53:50 -03:00
registered_algorithms . set ( algorithm , RegisteredAlgorithm { & Methods : : create , & Param : : from_value } ) ;
2023-12-13 20:38:14 -03:00
internal_object . set ( op , registered_algorithms ) ;
}
2021-12-13 19:09:55 -03:00
}