2021-12-13 22:09:55 +00:00
/*
2022-08-22 18:31:08 +01:00
* Copyright ( c ) 2021 - 2022 , Linus Groh < linusg @ serenityos . org >
2024-10-26 20:12:09 +02:00
* Copyright ( c ) 2023 - 2024 , stelar7 < dudedbz @ gmail . com >
2024-11-15 15:53:39 +01:00
* Copyright ( c ) 2024 , Jelle Raaijmakers < jelle @ ladybird . org >
2021-12-13 22:09:55 +00:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
2024-12-14 12:23:52 +01:00
# include <AK/ByteBuffer.h>
2024-03-06 19:11:08 -07:00
# include <AK/QuickSort.h>
2021-12-13 22:09:55 +00:00
# include <LibCrypto/Hash/HashManager.h>
# include <LibJS/Runtime/ArrayBuffer.h>
2024-12-14 12:23:52 +01:00
# include <LibJS/Runtime/JSONObject.h>
2024-01-23 11:52:15 -07: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 18:11:21 -06:00
# include <LibWeb/Bindings/Intrinsics.h>
2024-04-27 12:09:58 +12:00
# include <LibWeb/Bindings/SubtleCryptoPrototype.h>
2024-03-13 21:19:57 -06:00
# include <LibWeb/Crypto/KeyAlgorithms.h>
2021-12-13 22:09:55 +00:00
# include <LibWeb/Crypto/SubtleCrypto.h>
2024-01-23 11:52:15 -07:00
# include <LibWeb/HTML/Scripting/TemporaryExecutionContext.h>
# include <LibWeb/Platform/EventLoopPlugin.h>
2022-09-24 16:14:37 +01:00
# include <LibWeb/WebIDL/AbstractOperations.h>
2023-11-23 20:07:25 +13:00
# include <LibWeb/WebIDL/Buffers.h>
2023-02-12 21:25:57 +01:00
# include <LibWeb/WebIDL/ExceptionOr.h>
2024-01-23 11:52:15 -07:00
# include <LibWeb/WebIDL/Promise.h>
2021-12-13 22:09:55 +00:00
namespace Web : : Crypto {
2024-03-06 19:11:08 -07:00
static void normalize_key_usages ( Vector < Bindings : : KeyUsage > & key_usages )
{
quick_sort ( key_usages ) ;
}
2024-03-14 21:52:17 -06: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 20:53:41 +01:00
static SupportedAlgorithmsMap const & supported_algorithms ( ) ;
2024-03-14 21:52:17 -06:00
template < typename Methods , typename Param = AlgorithmParams >
static void define_an_algorithm ( String op , String algorithm ) ;
2024-03-06 19:11:08 -07:00
2024-11-15 04:01:23 +13:00
GC_DEFINE_ALLOCATOR ( SubtleCrypto ) ;
2023-11-19 19:47:52 +01:00
2024-11-15 04:01:23 +13:00
GC : : Ref < SubtleCrypto > SubtleCrypto : : create ( JS : : Realm & realm )
2022-09-03 19:59:53 +02:00
{
2024-11-14 05:50:17 +13:00
return realm . create < SubtleCrypto > ( realm ) ;
2022-09-03 19:59:53 +02: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 18:11:21 -06:00
SubtleCrypto : : SubtleCrypto ( JS : : Realm & realm )
: PlatformObject ( realm )
2022-09-03 19:59:53 +02:00
{
}
SubtleCrypto : : ~ SubtleCrypto ( ) = default ;
2023-08-07 08:41:28 +02:00
void SubtleCrypto : : initialize ( JS : : Realm & realm )
2023-01-10 06:28:20 -05:00
{
2023-08-07 08:41:28 +02:00
Base : : initialize ( realm ) ;
2024-03-16 13:13:08 +01:00
WEB_SET_PROTOTYPE_FOR_INTERFACE ( SubtleCrypto ) ;
2023-01-10 06:28:20 -05:00
}
2023-12-14 00:38:14 +01:00
// https://w3c.github.io/webcrypto/#dfn-normalize-an-algorithm
2024-03-14 21:52:17 -06:00
WebIDL : : ExceptionOr < NormalizedAlgorithmAndParameter > normalize_an_algorithm ( JS : : Realm & realm , AlgorithmIdentifier const & algorithm , String operation )
2023-12-14 00:38:14 +01:00
{
2024-03-14 21:52:17 -06:00
auto & vm = realm . vm ( ) ;
2023-12-14 00:38:14 +01: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.
2024-11-15 04:01:23 +13:00
auto dictionary = GC : : make_root ( JS : : Object : : create ( realm , realm . intrinsics ( ) . object_prototype ( ) ) ) ;
2025-03-16 21:25:29 -05:00
TRY ( dictionary - > create_data_property ( " name " _fly_string , JS : : PrimitiveString : : create ( vm , algorithm . get < String > ( ) ) ) ) ;
2023-12-14 00:38:14 +01:00
2024-03-14 21:52:17 -06:00
return normalize_an_algorithm ( realm , dictionary , operation ) ;
2023-12-14 00:38:14 +01: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 20:53:41 +01:00
auto const & internal_object = supported_algorithms ( ) ;
2023-12-14 00:38:14 +01: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 16:53:50 -07: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.
2025-03-16 21:25:29 -05:00
auto initial_algorithm = TRY ( algorithm . get < GC : : Root < JS : : Object > > ( ) - > get ( " name " _fly_string ) ) ;
2023-12-14 00:38:14 +01:00
2024-11-24 22:06:59 +01:00
if ( initial_algorithm . is_undefined ( ) ) {
return vm . throw_completion < JS : : TypeError > ( JS : : ErrorType : : NotAnObjectOfType , " Algorithm " ) ;
}
2023-12-14 00:38:14 +01:00
// 4. Let algName be the value of the name attribute of initialAlg.
2024-03-06 16:53:50 -07:00
auto algorithm_name = TRY ( initial_algorithm . to_string ( vm ) ) ;
2023-12-14 00:38:14 +01:00
2024-03-06 16:53:50 -07:00
RegisteredAlgorithm desired_type ;
2023-12-14 00:38:14 +01:00
// 5. If registeredAlgorithms contains a key that is a case-insensitive string match for algName:
2024-03-06 16:53:50 -07:00
if ( auto it = registered_algorithms . find ( algorithm_name ) ; it ! = registered_algorithms . end ( ) ) {
2023-12-14 00:38:14 +01:00
// 1. Set algName to the value of the matching key.
2024-11-27 21:17:07 +01:00
algorithm_name = it - > key ;
2023-12-14 00:38:14 +01:00
// 2. Let desiredType be the IDL dictionary type stored at algName in registeredAlgorithms.
2024-03-06 16:53:50 -07:00
desired_type = it - > value ;
2023-12-14 00:38:14 +01:00
} else {
// Otherwise:
// Return a new NotSupportedError and terminate this algorithm.
2024-03-27 19:24:33 +01:00
return WebIDL : : NotSupportedError : : create ( realm , MUST ( String : : formatted ( " Algorithm '{}' is not supported for operation '{}' " , algorithm_name , operation ) ) ) ;
2023-12-14 00:38:14 +01: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 16:53:50 -07:00
// 11. Let dictionaries be a list consisting of the IDL dictionary type desiredType
2023-12-14 00:38:14 +01:00
// and all of desiredType's inherited dictionaries, in order from least to most derived.
2024-03-06 16:53:50 -07: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 ) ;
2024-11-15 04:01:23 +13:00
auto parameter = TRY ( desired_type . parameter_from_value ( vm , algorithm . get < GC : : Root < JS : : Object > > ( ) ) ) ;
2024-11-27 21:17:07 +01:00
// 9. Set the name attribute of normalizedAlgorithm to algName.
VERIFY ( parameter - > name . is_empty ( ) ) ;
parameter - > name = algorithm_name ;
2024-03-06 16:53:50 -07:00
auto normalized_algorithm = NormalizedAlgorithmAndParameter { move ( methods ) , move ( parameter ) } ;
2023-12-14 00:38:14 +01:00
// 13. Return normalizedAlgorithm.
return normalized_algorithm ;
}
2024-03-14 22:39:48 -06:00
// https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-encrypt
2024-11-15 04:01:23 +13:00
GC : : Ref < WebIDL : : Promise > SubtleCrypto : : encrypt ( AlgorithmIdentifier const & algorithm , GC : : Ref < CryptoKey > key , GC : : Root < WebIDL : : BufferSource > const & data_parameter )
2024-03-14 22:39:48 -06:00
{
auto & realm = this - > realm ( ) ;
auto & vm = this - > vm ( ) ;
// 1. Let algorithm and key be the algorithm and key parameters passed to the encrypt() method, respectively.
// 2. Let data be the result of getting a copy of the bytes held by the data parameter passed to the encrypt() method.
auto data_or_error = WebIDL : : get_buffer_source_copy ( * data_parameter - > raw_object ( ) ) ;
if ( data_or_error . is_error ( ) ) {
VERIFY ( data_or_error . error ( ) . code ( ) = = ENOMEM ) ;
return WebIDL : : create_rejected_promise_from_exception ( realm , vm . throw_completion < JS : : InternalError > ( vm . error_message ( JS : : VM : : ErrorMessage : : OutOfMemory ) ) ) ;
}
auto data = data_or_error . release_value ( ) ;
// 3. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set to algorithm and op set to "encrypt".
auto normalized_algorithm = normalize_an_algorithm ( realm , algorithm , " encrypt " _string ) ;
// 4. If an error occurred, return a Promise rejected with normalizedAlgorithm.
if ( normalized_algorithm . is_error ( ) )
return WebIDL : : create_rejected_promise_from_exception ( realm , normalized_algorithm . release_error ( ) ) ;
// 5. Let promise be a new Promise.
auto promise = WebIDL : : create_promise ( realm ) ;
// 6. Return promise and perform the remaining steps in parallel.
2024-11-15 04:01:23 +13:00
Platform : : EventLoopPlugin : : the ( ) . deferred_invoke ( GC : : create_function ( realm . heap ( ) , [ & realm , normalized_algorithm = normalized_algorithm . release_value ( ) , promise , key , data = move ( data ) ] ( ) - > void {
2024-10-24 20:39:18 +13:00
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
2024-03-14 22:39:48 -06:00
// 7. If the following steps or referenced procedures say to throw an error, reject promise with the returned error and then terminate the algorithm.
// 8. If the name member of normalizedAlgorithm is not equal to the name attribute of the [[algorithm]] internal slot of key then throw an InvalidAccessError.
if ( normalized_algorithm . parameter - > name ! = key - > algorithm_name ( ) ) {
2024-10-12 20:56:21 +02:00
WebIDL : : reject_promise ( realm , promise , WebIDL : : InvalidAccessError : : create ( realm , " Algorithm mismatch " _string ) ) ;
2024-03-14 22:39:48 -06:00
return ;
}
// 9. If the [[usages]] internal slot of key does not contain an entry that is "encrypt", then throw an InvalidAccessError.
if ( ! key - > internal_usages ( ) . contains_slow ( Bindings : : KeyUsage : : Encrypt ) ) {
2024-10-12 20:56:21 +02:00
WebIDL : : reject_promise ( realm , promise , WebIDL : : InvalidAccessError : : create ( realm , " Key does not support encryption " _string ) ) ;
2024-03-14 22:39:48 -06:00
return ;
}
// 10. Let ciphertext be the result of performing the encrypt operation specified by normalizedAlgorithm using algorithm and key and with data as plaintext.
auto cipher_text = normalized_algorithm . methods - > encrypt ( * normalized_algorithm . parameter , key , data ) ;
if ( cipher_text . is_error ( ) ) {
2024-11-04 14:37:27 +01:00
WebIDL : : reject_promise ( realm , promise , Bindings : : exception_to_throw_completion ( realm . vm ( ) , cipher_text . release_error ( ) ) . release_value ( ) . value ( ) ) ;
2024-03-14 22:39:48 -06:00
return ;
}
// 9. Resolve promise with ciphertext.
WebIDL : : resolve_promise ( realm , promise , cipher_text . release_value ( ) ) ;
2024-10-31 02:39:29 +13:00
} ) ) ;
2024-03-14 22:39:48 -06:00
2024-10-25 12:38:19 -06:00
return promise ;
2024-03-14 22:39:48 -06:00
}
2024-03-14 22:47:06 -06:00
// https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-decrypt
2024-11-15 04:01:23 +13:00
GC : : Ref < WebIDL : : Promise > SubtleCrypto : : decrypt ( AlgorithmIdentifier const & algorithm , GC : : Ref < CryptoKey > key , GC : : Root < WebIDL : : BufferSource > const & data_parameter )
2024-03-14 22:47:06 -06:00
{
auto & realm = this - > realm ( ) ;
auto & vm = this - > vm ( ) ;
// 1. Let algorithm and key be the algorithm and key parameters passed to the decrypt() method, respectively.
// 2. Let data be the result of getting a copy of the bytes held by the data parameter passed to the decrypt() method.
auto data_or_error = WebIDL : : get_buffer_source_copy ( * data_parameter - > raw_object ( ) ) ;
if ( data_or_error . is_error ( ) ) {
VERIFY ( data_or_error . error ( ) . code ( ) = = ENOMEM ) ;
return WebIDL : : create_rejected_promise_from_exception ( realm , vm . throw_completion < JS : : InternalError > ( vm . error_message ( JS : : VM : : ErrorMessage : : OutOfMemory ) ) ) ;
}
auto data = data_or_error . release_value ( ) ;
// 3. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set to algorithm and op set to "decrypt".
auto normalized_algorithm = normalize_an_algorithm ( realm , algorithm , " decrypt " _string ) ;
// 4. If an error occurred, return a Promise rejected with normalizedAlgorithm.
if ( normalized_algorithm . is_error ( ) )
return WebIDL : : create_rejected_promise_from_exception ( realm , normalized_algorithm . release_error ( ) ) ;
// 5. Let promise be a new Promise.
auto promise = WebIDL : : create_promise ( realm ) ;
// 6. Return promise and perform the remaining steps in parallel.
2024-11-15 04:01:23 +13:00
Platform : : EventLoopPlugin : : the ( ) . deferred_invoke ( GC : : create_function ( realm . heap ( ) , [ & realm , normalized_algorithm = normalized_algorithm . release_value ( ) , promise , key , data = move ( data ) ] ( ) - > void {
2024-10-24 20:39:18 +13:00
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
2024-03-14 22:47:06 -06:00
// 7. If the following steps or referenced procedures say to throw an error, reject promise with the returned error and then terminate the algorithm.
// 8. If the name member of normalizedAlgorithm is not equal to the name attribute of the [[algorithm]] internal slot of key then throw an InvalidAccessError.
if ( normalized_algorithm . parameter - > name ! = key - > algorithm_name ( ) ) {
2024-10-12 20:56:21 +02:00
WebIDL : : reject_promise ( realm , promise , WebIDL : : InvalidAccessError : : create ( realm , " Algorithm mismatch " _string ) ) ;
2024-03-14 22:47:06 -06:00
return ;
}
// 9. If the [[usages]] internal slot of key does not contain an entry that is "decrypt", then throw an InvalidAccessError.
if ( ! key - > internal_usages ( ) . contains_slow ( Bindings : : KeyUsage : : Decrypt ) ) {
2024-10-12 20:56:21 +02:00
WebIDL : : reject_promise ( realm , promise , WebIDL : : InvalidAccessError : : create ( realm , " Key does not support encryption " _string ) ) ;
2024-03-14 22:47:06 -06:00
return ;
}
// 10. Let plaintext be the result of performing the decrypt operation specified by normalizedAlgorithm using algorithm and key and with data as ciphertext.
auto plain_text = normalized_algorithm . methods - > decrypt ( * normalized_algorithm . parameter , key , data ) ;
if ( plain_text . is_error ( ) ) {
2024-11-04 14:37:27 +01:00
WebIDL : : reject_promise ( realm , promise , Bindings : : exception_to_throw_completion ( realm . vm ( ) , plain_text . release_error ( ) ) . release_value ( ) . value ( ) ) ;
2024-03-14 22:47:06 -06:00
return ;
}
// 9. Resolve promise with plaintext.
WebIDL : : resolve_promise ( realm , promise , plain_text . release_value ( ) ) ;
2024-10-31 02:39:29 +13:00
} ) ) ;
2024-03-14 22:47:06 -06:00
2024-10-25 12:38:19 -06:00
return promise ;
2024-03-14 22:47:06 -06: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 18:11:21 -06:00
// https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-digest
2024-11-15 04:01:23 +13:00
GC : : Ref < WebIDL : : Promise > SubtleCrypto : : digest ( AlgorithmIdentifier const & algorithm , GC : : Root < WebIDL : : BufferSource > const & data )
2021-12-13 22:09:55 +00: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 18:11:21 -06:00
auto & realm = this - > realm ( ) ;
2024-03-14 22:38:09 -06:00
auto & vm = this - > vm ( ) ;
2021-12-13 22:09:55 +00:00
// 1. Let algorithm be the algorithm parameter passed to the digest() method.
// 2. Let data be the result of getting a copy of the bytes held by the data parameter passed to the digest() method.
2023-11-23 20:07:25 +13:00
auto data_buffer_or_error = WebIDL : : get_buffer_source_copy ( * data - > raw_object ( ) ) ;
2024-03-14 22:38:09 -06: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 11:52:15 -07:00
auto data_buffer = data_buffer_or_error . release_value ( ) ;
2021-12-13 22:09:55 +00:00
// 3. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set to algorithm and op set to "digest".
2024-03-14 21:52:17 -06:00
auto normalized_algorithm = normalize_an_algorithm ( realm , algorithm , " digest " _string ) ;
2023-12-14 20:56:30 +01:00
2021-12-13 22:09:55 +00:00
// 4. If an error occurred, return a Promise rejected with normalizedAlgorithm.
2024-01-23 11:52:15 -07:00
// FIXME: Spec bug: link to https://webidl.spec.whatwg.org/#a-promise-rejected-with
2024-03-08 15:37:28 +00:00
if ( normalized_algorithm . is_error ( ) )
return WebIDL : : create_rejected_promise_from_exception ( realm , normalized_algorithm . release_error ( ) ) ;
2021-12-13 22:09:55 +00:00
// 5. Let promise be a new Promise.
2024-01-23 11:52:15 -07:00
auto promise = WebIDL : : create_promise ( realm ) ;
2021-12-13 22:09:55 +00:00
// 6. Return promise and perform the remaining steps in parallel.
2024-11-15 04:01:23 +13:00
Platform : : EventLoopPlugin : : the ( ) . deferred_invoke ( GC : : create_function ( realm . heap ( ) , [ & realm , algorithm_object = normalized_algorithm . release_value ( ) , promise , data_buffer = move ( data_buffer ) ] ( ) - > void {
2024-10-24 20:39:18 +13:00
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
2024-01-23 11:52:15 -07:00
// 7. If the following steps or referenced procedures say to throw an error, reject promise with the returned error and then terminate the algorithm.
// FIXME: Need spec reference to https://webidl.spec.whatwg.org/#reject
// 8. Let result be the result of performing the digest operation specified by normalizedAlgorithm using algorithm, with data as message.
2024-03-06 16:53:50 -07:00
auto result = algorithm_object . methods - > digest ( * algorithm_object . parameter , data_buffer ) ;
2024-01-23 11:52:15 -07:00
2024-03-06 16:53:50 -07:00
if ( result . is_exception ( ) ) {
2024-11-04 14:37:27 +01:00
WebIDL : : reject_promise ( realm , promise , Bindings : : exception_to_throw_completion ( realm . vm ( ) , result . release_error ( ) ) . release_value ( ) . value ( ) ) ;
2024-01-23 11:52:15 -07:00
return ;
}
// 9. Resolve promise with result.
2024-03-06 16:53:50 -07:00
WebIDL : : resolve_promise ( realm , promise , result . release_value ( ) ) ;
2024-10-31 02:39:29 +13:00
} ) ) ;
2024-01-23 11:52:15 -07:00
2024-10-25 12:38:19 -06:00
return promise ;
2021-12-13 22:09:55 +00:00
}
2024-03-06 19:15:03 -07:00
// https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-generateKey
2025-01-31 11:18:03 +01:00
GC : : Ref < WebIDL : : Promise > SubtleCrypto : : generate_key ( AlgorithmIdentifier algorithm , bool extractable , Vector < Bindings : : KeyUsage > key_usages )
2024-03-06 19:15:03 -07: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-14 21:52:17 -06:00
auto normalized_algorithm = normalize_an_algorithm ( realm , algorithm , " generateKey " _string ) ;
2024-03-06 19:15:03 -07: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-15 04:01:23 +13: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 20:39:18 +13:00
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
2024-03-06 19:15:03 -07: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 ( ) ) {
2024-11-04 14:37:27 +01:00
WebIDL : : reject_promise ( realm , promise , Bindings : : exception_to_throw_completion ( realm . vm ( ) , result_or_error . release_error ( ) ) . release_value ( ) . value ( ) ) ;
2024-03-06 19:15:03 -07: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-15 04:01:23 +13:00
[ & ] ( GC : : Ref < CryptoKey > & key ) {
2024-03-06 19:15:03 -07:00
if ( ( key - > type ( ) = = Bindings : : KeyType : : Secret | | key - > type ( ) = = Bindings : : KeyType : : Private ) & & key_usages . is_empty ( ) ) {
2024-10-12 20:56:21 +02:00
WebIDL : : reject_promise ( realm , promise , WebIDL : : SyntaxError : : create ( realm , " usages must not be empty " _string ) ) ;
2024-03-06 19:15:03 -07:00
return ;
}
WebIDL : : resolve_promise ( realm , promise , key ) ;
} ,
2024-11-15 04:01:23 +13:00
[ & ] ( GC : : Ref < CryptoKeyPair > & key_pair ) {
2024-03-06 19:15:03 -07:00
if ( key_pair - > private_key ( ) - > internal_usages ( ) . is_empty ( ) ) {
2024-10-12 20:56:21 +02:00
WebIDL : : reject_promise ( realm , promise , WebIDL : : SyntaxError : : create ( realm , " usages must not be empty " _string ) ) ;
2024-03-06 19:15:03 -07:00
return ;
}
WebIDL : : resolve_promise ( realm , promise , key_pair ) ;
} ) ;
2024-10-31 02:39:29 +13:00
} ) ) ;
2024-03-06 19:15:03 -07:00
2024-10-25 12:38:19 -06:00
return promise ;
2024-03-06 19:15:03 -07:00
}
2023-12-15 22:03:04 +01:00
// https://w3c.github.io/webcrypto/#SubtleCrypto-method-importKey
2024-11-15 04:01:23 +13:00
JS : : ThrowCompletionOr < GC : : Ref < WebIDL : : Promise > > SubtleCrypto : : import_key ( Bindings : : KeyFormat format , KeyDataType key_data , AlgorithmIdentifier algorithm , bool extractable , Vector < Bindings : : KeyUsage > key_usages )
2023-12-15 22:03:04 +01: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.
Variant < ByteBuffer , Bindings : : JsonWebKey , Empty > real_key_data ;
// 2. If format is equal to the string "raw", "pkcs8", or "spki":
if ( format = = Bindings : : KeyFormat : : Raw | | format = = Bindings : : KeyFormat : : Pkcs8 | | format = = Bindings : : KeyFormat : : Spki ) {
// 1. If the keyData parameter passed to the importKey() method is a JsonWebKey dictionary, throw a TypeError.
if ( key_data . has < Bindings : : JsonWebKey > ( ) ) {
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.
2024-11-15 04:01:23 +13:00
real_key_data = MUST ( WebIDL : : get_buffer_source_copy ( * key_data . get < GC : : Root < WebIDL : : BufferSource > > ( ) - > raw_object ( ) ) ) ;
2023-12-15 22:03:04 +01:00
}
if ( format = = Bindings : : KeyFormat : : Jwk ) {
// 1. If the keyData parameter passed to the importKey() method is not a JsonWebKey dictionary, throw a TypeError.
if ( ! key_data . has < Bindings : : JsonWebKey > ( ) ) {
return realm . vm ( ) . throw_completion < JS : : TypeError > ( JS : : ErrorType : : NotAnObjectOfType , " JsonWebKey " ) ;
}
// 2. Let keyData be the keyData parameter passed to the importKey() method.
real_key_data = key_data . get < Bindings : : JsonWebKey > ( ) ;
}
// 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-14 21:52:17 -06:00
auto normalized_algorithm = normalize_an_algorithm ( realm , algorithm , " importKey " _string ) ;
2023-12-15 22:03:04 +01:00
// 6. If an error occurred, return a Promise rejected with normalizedAlgorithm.
2024-03-08 15:37:28 +00:00
if ( normalized_algorithm . is_error ( ) )
return WebIDL : : create_rejected_promise_from_exception ( realm , normalized_algorithm . release_error ( ) ) ;
2023-12-15 22:03:04 +01: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-15 04:01:23 +13: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 20:39:18 +13:00
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
2023-12-15 22:03:04 +01: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 16:53:50 -07: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 22:03:04 +01:00
if ( maybe_result . is_error ( ) ) {
2024-11-04 14:37:27 +01:00
WebIDL : : reject_promise ( realm , promise , Bindings : : exception_to_throw_completion ( realm . vm ( ) , maybe_result . release_error ( ) ) . release_value ( ) . value ( ) ) ;
2023-12-15 22:03:04 +01: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 ( ) ) {
2024-10-12 20:56:21 +02:00
WebIDL : : reject_promise ( realm , promise , WebIDL : : SyntaxError : : create ( realm , " usages must not be empty " _string ) ) ;
2023-12-15 22:03:04 +01: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 19:11:08 -07:00
normalize_key_usages ( key_usages ) ;
result - > set_usages ( key_usages ) ;
2023-12-15 22:03:04 +01:00
// 14. Resolve promise with result.
WebIDL : : resolve_promise ( realm , promise , result ) ;
2024-10-31 02:39:29 +13:00
} ) ) ;
2023-12-15 22:03:04 +01:00
2024-10-25 12:38:19 -06:00
return promise ;
2023-12-15 22:03:04 +01:00
}
2024-03-13 21:19:57 -06:00
// https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-exportKey
2025-01-31 11:18:03 +01:00
GC : : Ref < WebIDL : : Promise > SubtleCrypto : : export_key ( Bindings : : KeyFormat format , GC : : Ref < CryptoKey > key )
2024-03-13 21:19:57 -06: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-15 04:01:23 +13:00
Platform : : EventLoopPlugin : : the ( ) . deferred_invoke ( GC : : create_function ( heap ( ) , [ & realm , key , promise , format ] ( ) - > void {
2024-10-24 20:39:18 +13:00
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
2024-03-13 21:19:57 -06: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 09:12:05 -05:00
auto & algorithm = as < KeyAlgorithm > ( * key - > algorithm ( ) ) ;
2024-03-13 21:19:57 -06:00
// FIXME: Stash the AlgorithmMethods on the KeyAlgorithm
2024-03-14 21:52:17 -06:00
auto normalized_algorithm_or_error = normalize_an_algorithm ( realm , algorithm . name ( ) , " exportKey " _string ) ;
2024-03-13 21:19:57 -06:00
if ( normalized_algorithm_or_error . is_error ( ) ) {
2024-11-04 14:37:27 +01:00
WebIDL : : reject_promise ( realm , promise , Bindings : : exception_to_throw_completion ( realm . vm ( ) , normalized_algorithm_or_error . release_error ( ) ) . release_value ( ) . value ( ) ) ;
2024-03-13 21:19:57 -06: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 ( ) ) {
2024-10-12 20:56:21 +02:00
WebIDL : : reject_promise ( realm , promise , WebIDL : : InvalidAccessError : : create ( realm , " Key is not extractable " _string ) ) ;
2024-03-13 21:19:57 -06: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 ( ) ) {
2024-11-04 14:37:27 +01:00
WebIDL : : reject_promise ( realm , promise , Bindings : : exception_to_throw_completion ( realm . vm ( ) , result_or_error . release_error ( ) ) . release_value ( ) . value ( ) ) ;
2024-03-13 21:19:57 -06:00
return ;
}
// 8. Resolve promise with result.
WebIDL : : resolve_promise ( realm , promise , result_or_error . release_value ( ) ) ;
2024-10-31 02:39:29 +13:00
} ) ) ;
2024-03-13 21:19:57 -06:00
2024-10-25 12:38:19 -06:00
return promise ;
2024-03-26 23:53:35 +01:00
}
// https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-sign
2025-01-31 11:18:03 +01:00
GC : : Ref < WebIDL : : Promise > SubtleCrypto : : sign ( AlgorithmIdentifier const & algorithm , GC : : Ref < CryptoKey > key , GC : : Root < WebIDL : : BufferSource > const & data_parameter )
2024-03-26 23:53:35 +01:00
{
auto & realm = this - > realm ( ) ;
auto & vm = this - > vm ( ) ;
// 1. Let algorithm and key be the algorithm and key parameters passed to the sign() method, respectively.
// 2. Let data be the result of getting a copy of the bytes held by the data parameter passed to the sign() method.
auto data_or_error = WebIDL : : get_buffer_source_copy ( * data_parameter - > raw_object ( ) ) ;
if ( data_or_error . is_error ( ) ) {
VERIFY ( data_or_error . error ( ) . code ( ) = = ENOMEM ) ;
return WebIDL : : create_rejected_promise_from_exception ( realm , vm . throw_completion < JS : : InternalError > ( vm . error_message ( JS : : VM : : ErrorMessage : : OutOfMemory ) ) ) ;
}
auto data = data_or_error . release_value ( ) ;
// 3. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set to algorithm and op set to "sign".
auto normalized_algorithm = normalize_an_algorithm ( realm , algorithm , " sign " _string ) ;
// 4. If an error occurred, return a Promise rejected with normalizedAlgorithm.
if ( normalized_algorithm . is_error ( ) )
return WebIDL : : create_rejected_promise_from_exception ( realm , normalized_algorithm . release_error ( ) ) ;
// 5. Let promise be a new Promise.
auto promise = WebIDL : : create_promise ( realm ) ;
// 6. Return promise and perform the remaining steps in parallel.
2024-11-15 04:01:23 +13:00
Platform : : EventLoopPlugin : : the ( ) . deferred_invoke ( GC : : create_function ( realm . heap ( ) , [ & realm , normalized_algorithm = normalized_algorithm . release_value ( ) , promise , key , data = move ( data ) ] ( ) - > void {
2024-10-24 20:39:18 +13:00
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
2024-03-26 23:53:35 +01:00
// 7. If the following steps or referenced procedures say to throw an error, reject promise with the returned error and then terminate the algorithm.
// 8. If the name member of normalizedAlgorithm is not equal to the name attribute of the [[algorithm]] internal slot of key then throw an InvalidAccessError.
if ( normalized_algorithm . parameter - > name ! = key - > algorithm_name ( ) ) {
2024-10-12 20:56:21 +02:00
WebIDL : : reject_promise ( realm , promise , WebIDL : : InvalidAccessError : : create ( realm , " Algorithm mismatch " _string ) ) ;
2024-03-26 23:53:35 +01:00
return ;
}
// 9. If the [[usages]] internal slot of key does not contain an entry that is "sign", then throw an InvalidAccessError.
if ( ! key - > internal_usages ( ) . contains_slow ( Bindings : : KeyUsage : : Sign ) ) {
2024-10-12 20:56:21 +02:00
WebIDL : : reject_promise ( realm , promise , WebIDL : : InvalidAccessError : : create ( realm , " Key does not support signing " _string ) ) ;
2024-03-26 23:53:35 +01:00
return ;
}
// 10. Let result be the result of performing the sign operation specified by normalizedAlgorithm using key and algorithm and with data as message.
auto result = normalized_algorithm . methods - > sign ( * normalized_algorithm . parameter , key , data ) ;
if ( result . is_error ( ) ) {
2024-11-04 14:37:27 +01:00
WebIDL : : reject_promise ( realm , promise , Bindings : : exception_to_throw_completion ( realm . vm ( ) , result . release_error ( ) ) . release_value ( ) . value ( ) ) ;
2024-03-26 23:53:35 +01:00
return ;
}
// 9. Resolve promise with result.
WebIDL : : resolve_promise ( realm , promise , result . release_value ( ) ) ;
2024-10-31 02:39:29 +13:00
} ) ) ;
2024-03-26 23:53:35 +01:00
2024-10-25 12:38:19 -06:00
return promise ;
2024-03-13 21:19:57 -06:00
}
2024-03-27 01:50:25 +01:00
// https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-verify
2025-01-31 11:18:03 +01:00
GC : : Ref < WebIDL : : Promise > SubtleCrypto : : verify ( AlgorithmIdentifier const & algorithm , GC : : Ref < CryptoKey > key , GC : : Root < WebIDL : : BufferSource > const & signature_data , GC : : Root < WebIDL : : BufferSource > const & data_parameter )
2024-03-27 01:50:25 +01:00
{
auto & realm = this - > realm ( ) ;
auto & vm = this - > vm ( ) ;
// 1. Let algorithm and key be the algorithm and key parameters passed to the verify() method, respectively.
// 2. Let signature be the result of getting a copy of the bytes held by the signature parameter passed to the verify() method.
auto signature_or_error = WebIDL : : get_buffer_source_copy ( * signature_data - > raw_object ( ) ) ;
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 ( ) ;
// 3. Let data be the result of getting a copy of the bytes held by the data parameter passed to the verify() method.
auto data_or_error = WebIDL : : get_buffer_source_copy ( * data_parameter - > raw_object ( ) ) ;
if ( data_or_error . is_error ( ) ) {
VERIFY ( data_or_error . error ( ) . code ( ) = = ENOMEM ) ;
return WebIDL : : create_rejected_promise_from_exception ( realm , vm . throw_completion < JS : : InternalError > ( vm . error_message ( JS : : VM : : ErrorMessage : : OutOfMemory ) ) ) ;
}
auto data = data_or_error . release_value ( ) ;
// 3. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set to algorithm and op set to "verify".
auto normalized_algorithm = normalize_an_algorithm ( realm , algorithm , " verify " _string ) ;
// 5. 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 ( ) ) ;
// 6. Let promise be a new Promise.
auto promise = WebIDL : : create_promise ( realm ) ;
// 7. Return promise and perform the remaining steps in parallel.
2024-11-15 04:01:23 +13:00
Platform : : EventLoopPlugin : : the ( ) . deferred_invoke ( GC : : create_function ( realm . heap ( ) , [ & realm , normalized_algorithm = normalized_algorithm . release_value ( ) , promise , key , signature = move ( signature ) , data = move ( data ) ] ( ) - > void {
2024-10-24 20:39:18 +13:00
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
2024-03-27 01:50:25 +01:00
// 8. If the following steps or referenced procedures say to throw an error, reject promise with the returned error and then terminate the algorithm.
// 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.
if ( normalized_algorithm . parameter - > name ! = key - > algorithm_name ( ) ) {
2024-10-12 20:56:21 +02:00
WebIDL : : reject_promise ( realm , promise , WebIDL : : InvalidAccessError : : create ( realm , " Algorithm mismatch " _string ) ) ;
2024-03-27 01:50:25 +01:00
return ;
}
// 10. If the [[usages]] internal slot of key does not contain an entry that is "verify", then throw an InvalidAccessError.
if ( ! key - > internal_usages ( ) . contains_slow ( Bindings : : KeyUsage : : Verify ) ) {
2024-10-12 20:56:21 +02:00
WebIDL : : reject_promise ( realm , promise , WebIDL : : InvalidAccessError : : create ( realm , " Key does not support verification " _string ) ) ;
2024-03-27 01:50:25 +01:00
return ;
}
// 11. Let result be the result of performing the verify operation specified by normalizedAlgorithm using key, algorithm and signature and with data as message.
auto result = normalized_algorithm . methods - > verify ( * normalized_algorithm . parameter , key , signature , data ) ;
if ( result . is_error ( ) ) {
2024-11-04 14:37:27 +01:00
WebIDL : : reject_promise ( realm , promise , Bindings : : exception_to_throw_completion ( realm . vm ( ) , result . release_error ( ) ) . release_value ( ) . value ( ) ) ;
2024-03-27 01:50:25 +01:00
return ;
}
// 12. Resolve promise with result.
WebIDL : : resolve_promise ( realm , promise , result . release_value ( ) ) ;
2024-10-31 02:39:29 +13:00
} ) ) ;
2024-03-27 01:50:25 +01:00
2024-10-25 12:38:19 -06:00
return promise ;
2024-03-27 01:50:25 +01:00
}
2024-03-27 19:15:49 +01:00
// https://w3c.github.io/webcrypto/#SubtleCrypto-method-deriveBits
2025-01-31 11:18:03 +01:00
GC : : Ref < WebIDL : : Promise > SubtleCrypto : : derive_bits ( AlgorithmIdentifier algorithm , GC : : Ref < CryptoKey > base_key , Optional < u32 > length_optional )
2024-03-27 19:15:49 +01: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 16:13:20 +01: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 20:39:18 +13:00
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
2024-03-27 19:15:49 +01: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 ( ) ) {
2024-10-12 20:56:21 +02:00
WebIDL : : reject_promise ( realm , promise , WebIDL : : InvalidAccessError : : create ( realm , " Algorithm mismatch " _string ) ) ;
2024-03-27 19:15:49 +01: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 ) ) {
2024-10-12 20:56:21 +02:00
WebIDL : : reject_promise ( realm , promise , WebIDL : : InvalidAccessError : : create ( realm , " Key does not support deriving bits " _string ) ) ;
2024-03-27 19:15:49 +01: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 16:13:20 +01:00
auto result = normalized_algorithm . methods - > derive_bits ( * normalized_algorithm . parameter , base_key , length_optional ) ;
2024-03-27 19:15:49 +01:00
if ( result . is_error ( ) ) {
2024-11-04 14:37:27 +01:00
WebIDL : : reject_promise ( realm , promise , Bindings : : exception_to_throw_completion ( realm . vm ( ) , result . release_error ( ) ) . release_value ( ) . value ( ) ) ;
2024-03-27 19:15:49 +01:00
return ;
}
// 10. Resolve promise with result.
WebIDL : : resolve_promise ( realm , promise , result . release_value ( ) ) ;
2024-10-31 02:39:29 +13:00
} ) ) ;
2024-03-27 19:15:49 +01:00
2024-10-25 12:38:19 -06:00
return promise ;
2024-03-27 19:15:49 +01:00
}
2024-11-15 10:10:13 +01:00
// https://w3c.github.io/webcrypto/#SubtleCrypto-method-deriveKey
2025-01-31 11:18:03 +01: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 20:51:18 +01: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 15:53:39 +01: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 20:39:18 +13:00
HTML : : TemporaryExecutionContext context ( realm , HTML : : TemporaryExecutionContext : : CallbacksEnabled : : Yes ) ;
2024-03-27 20:51:18 +01: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 ( ) ) {
2024-10-12 20:56:21 +02:00
WebIDL : : reject_promise ( realm , promise , WebIDL : : InvalidAccessError : : create ( realm , " Algorithm mismatch " _string ) ) ;
2024-03-27 20:51:18 +01: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 ) ) {
2024-10-12 20:56:21 +02:00
WebIDL : : reject_promise ( realm , promise , WebIDL : : InvalidAccessError : : create ( realm , " Key does not support deriving keys " _string ) ) ;
2024-03-27 20:51:18 +01: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 ( ) ) {
2024-11-04 14:37:27 +01:00
WebIDL : : reject_promise ( realm , promise , Bindings : : exception_to_throw_completion ( realm . vm ( ) , length_result . release_error ( ) ) . release_value ( ) . value ( ) ) ;
2024-03-27 20:51:18 +01: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 ( ) ) {
WebIDL : : reject_promise ( realm , promise , maybe_length . release_error ( ) . release_value ( ) . value ( ) ) ;
return ;
}
length = maybe_length . value ( ) ;
}
// 14. Let secret be the result of performing the derive bits operation specified by normalizedAlgorithm using key, algorithm and length.
auto secret = normalized_algorithm . methods - > derive_bits ( * normalized_algorithm . parameter , base_key , length ) ;
if ( secret . is_error ( ) ) {
2024-11-04 14:37:27 +01:00
WebIDL : : reject_promise ( realm , promise , Bindings : : exception_to_throw_completion ( realm . vm ( ) , secret . release_error ( ) ) . release_value ( ) . value ( ) ) ;
2024-03-27 20:51:18 +01: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.
2024-11-15 15:53:39 +01:00
auto result_or_error = normalized_derived_key_algorithm_import . methods - > import_key ( * normalized_derived_key_algorithm_import . parameter , Bindings : : KeyFormat : : Raw , secret . release_value ( ) - > buffer ( ) , extractable , key_usages ) ;
if ( result_or_error . is_error ( ) ) {
2024-11-04 14:37:27 +01:00
WebIDL : : reject_promise ( realm , promise , Bindings : : exception_to_throw_completion ( realm . vm ( ) , result_or_error . release_error ( ) ) . release_value ( ) . value ( ) ) ;
2024-03-27 20:51:18 +01:00
return ;
}
2024-11-15 15:53:39 +01:00
auto result = result_or_error . release_value ( ) ;
2024-03-27 20:51:18 +01:00
// 16. If the [[type]] internal slot of result is "secret" or "private" and usages is empty, then throw a SyntaxError.
2024-11-15 15:53:39 +01:00
if ( ( result - > type ( ) = = Bindings : : KeyType : : Secret | | result - > type ( ) = = Bindings : : KeyType : : Private ) & & key_usages . is_empty ( ) ) {
2024-10-12 20:56:21 +02:00
WebIDL : : reject_promise ( realm , promise , WebIDL : : SyntaxError : : create ( realm , " usages must not be empty " _string ) ) ;
2024-03-27 20:51:18 +01:00
return ;
}
2024-11-15 15:53:39 +01:00
// 17. Set the [[extractable]] internal slot of result to extractable.
result - > set_extractable ( extractable ) ;
2024-11-15 10:36:34 +01:00
2024-11-15 15:53:39 +01: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-31 02:39:29 +13:00
} ) ) ;
2024-03-27 20:51:18 +01:00
2024-10-25 12:38:19 -06:00
return promise ;
2024-03-27 20:51:18 +01:00
}
2024-12-14 12:23:52 +01:00
// https://w3c.github.io/webcrypto/#SubtleCrypto-method-wrapKey
2025-01-31 11:18:03 +01: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 12:23:52 +01: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 ( ) ;
// 5. Let promise be a new Promise.
auto promise = WebIDL : : create_promise ( realm ) ;
// 6. Return promise and perform the remaining steps in parallel.
Platform : : EventLoopPlugin : : the ( ) . deferred_invoke ( 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 ) ;
// 7. If the following steps or referenced procedures say to throw an error, reject promise with the returned error and then terminate the algorithm.
// 8. If the name member of normalizedAlgorithm is not equal to the name attribute
// of the [[algorithm]] internal slot of wrappingKey then throw an InvalidAccessError.
if ( normalized_algorithm . parameter - > name ! = wrapping_key - > algorithm_name ( ) ) {
WebIDL : : reject_promise ( realm , promise , WebIDL : : InvalidAccessError : : create ( realm , " Algorithm mismatch " _string ) ) ;
return ;
}
// 9. If the [[usages]] internal slot of wrappingKey does not contain an entry that is "wrapKey", then throw an InvalidAccessError.
if ( ! wrapping_key - > internal_usages ( ) . contains_slow ( Bindings : : KeyUsage : : Wrapkey ) ) {
WebIDL : : reject_promise ( realm , promise , WebIDL : : InvalidAccessError : : create ( realm , " Key does not support wrapping keys " _string ) ) ;
return ;
}
// 10. If the algorithm identified by the [[algorithm]] internal slot of key does not support the export key operation, then throw a NotSupportedError.
// Note: Handled by the base AlgorithmMethods implementation
// 11. If the [[extractable]] internal slot of key is false, then throw an InvalidAccessError.
if ( ! key - > extractable ( ) ) {
WebIDL : : reject_promise ( realm , promise , WebIDL : : InvalidAccessError : : create ( realm , " Key is not extractable " _string ) ) ;
return ;
}
// 12. Let key be the result of performing the export key operation specified the [[algorithm]] internal slot of key using key and format.
// 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 09:12:05 -05:00
auto & key_algorithm = as < KeyAlgorithm > ( * key - > algorithm ( ) ) ;
2024-12-14 12:23:52 +01:00
auto normalized_key_algorithm = normalize_an_algorithm ( realm , key_algorithm . name ( ) , " exportKey " _string ) ;
if ( normalized_key_algorithm . is_error ( ) ) {
WebIDL : : reject_promise ( realm , promise , Bindings : : exception_to_throw_completion ( realm . vm ( ) , normalized_key_algorithm . release_error ( ) ) . release_value ( ) . value ( ) ) ;
return ;
}
auto key_data_or_error = normalized_key_algorithm . release_value ( ) . methods - > export_key ( format , key ) ;
if ( key_data_or_error . is_error ( ) ) {
WebIDL : : reject_promise ( realm , promise , Bindings : : exception_to_throw_completion ( realm . vm ( ) , key_data_or_error . release_error ( ) ) . release_value ( ) . value ( ) ) ;
return ;
}
auto key_data = key_data_or_error . release_value ( ) ;
ByteBuffer bytes ;
// 13. If format is equal to the strings "raw", "pkcs8", or "spki":
if ( format = = Bindings : : KeyFormat : : Raw | | format = = Bindings : : KeyFormat : : Pkcs8 | | format = = Bindings : : KeyFormat : : Spki ) {
// Set bytes be set to key.
2025-01-21 09:12:05 -05:00
bytes = as < JS : : ArrayBuffer > ( * key_data ) . buffer ( ) ;
2024-12-14 12:23:52 +01:00
}
// If format is equal to the string "jwk":
else if ( format = = Bindings : : KeyFormat : : Jwk ) {
// 1. Convert key to an ECMAScript Object, as specified in [WEBIDL],
// performing the conversion in the context of a new global object.
// 2. Let json be the result of representing key as a UTF-16 string conforming to the JSON grammar;
// for example, by executing the JSON.stringify algorithm specified in [ECMA-262] in the context of a new global object.
auto maybe_json = JS : : JSONObject : : stringify_impl ( realm . vm ( ) , key_data , JS : : Value { } , JS : : Value { } ) ;
if ( maybe_json . is_error ( ) ) {
WebIDL : : reject_promise ( realm , promise , maybe_json . release_error ( ) . release_value ( ) . value ( ) ) ;
return ;
}
// 3. Let bytes be the result of UTF-8 encoding json.
2025-03-16 20:45:02 -05:00
bytes = MUST ( ByteBuffer : : copy ( maybe_json . value ( ) - > bytes ( ) ) ) ;
2024-12-14 12:23:52 +01:00
} else {
VERIFY_NOT_REACHED ( ) ;
}
JS : : Value result ;
// 14. If normalizedAlgorithm supports the wrap key operation:
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 ( ) ) {
WebIDL : : reject_promise ( realm , promise , Bindings : : exception_to_throw_completion ( realm . vm ( ) , result_or_error . release_error ( ) ) . release_value ( ) . value ( ) ) ;
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 ( ) ) {
WebIDL : : reject_promise ( realm , promise , Bindings : : exception_to_throw_completion ( realm . vm ( ) , result_or_error . release_error ( ) ) . release_value ( ) . value ( ) ) ;
return ;
}
result = result_or_error . release_value ( ) ;
}
// Otherwise:
else {
// throw a NotSupportedError.
WebIDL : : reject_promise ( realm , promise , WebIDL : : NotSupportedError : : create ( realm , " Algorithm does not support wrapping " _string ) ) ;
return ;
}
// 15. Resolve promise with result.
WebIDL : : resolve_promise ( realm , promise , result ) ;
} ) ) ;
return promise ;
}
// https://w3c.github.io/webcrypto/#SubtleCrypto-method-unwrapKey
2025-01-31 11:18:03 +01:00
GC : : Ref < WebIDL : : Promise > SubtleCrypto : : unwrap_key ( Bindings : : KeyFormat format , KeyDataType wrapped_key , GC : : Ref < CryptoKey > unwrapping_key , AlgorithmIdentifier algorithm , AlgorithmIdentifier unwrapped_key_algorithm , bool extractable , Vector < Bindings : : KeyUsage > key_usages )
2024-12-14 12:23:52 +01: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.
// 2. Let wrappedKey be the result of getting a copy of the bytes held by the wrappedKey parameter passed to the unwrapKey() method.
auto real_wrapped_key = MUST ( WebIDL : : get_buffer_source_copy ( * wrapped_key . get < GC : : Root < WebIDL : : BufferSource > > ( ) - > raw_object ( ) ) ) ;
StringView operation ;
auto normalized_algorithm_or_error = [ & ] ( ) - > WebIDL : : ExceptionOr < NormalizedAlgorithmAndParameter > {
// 3. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set to algorithm and op set to "unwrapKey".
auto normalized_algorithm_unwrap_key_or_error = normalize_an_algorithm ( realm , algorithm , " unwrapKey " _string ) ;
// 4. If an error occurred, let normalizedAlgorithm be the result of normalizing an algorithm, with alg set to algorithm and op set to "decrypt".
// 5. If an error occurred, return a Promise rejected with normalizedAlgorithm.
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 ( ) ;
// 6. Let normalizedKeyAlgorithm be the result of normalizing an algorithm, with alg set to unwrappedKeyAlgorithm and op set to "importKey".
auto normalized_key_algorithm_or_error = normalize_an_algorithm ( realm , unwrapped_key_algorithm , " importKey " _string ) ;
if ( normalized_key_algorithm_or_error . is_error ( ) ) {
// 7. If an error occurred, return a Promise rejected with normalizedKeyAlgorithm.
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 ( ) ;
// 8. Let promise be a new Promise.
auto promise = WebIDL : : create_promise ( realm ) ;
// 9. Return promise and perform the remaining steps in parallel.
Platform : : EventLoopPlugin : : the ( ) . deferred_invoke ( 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 ) ;
// 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 unwrappingKey then throw an InvalidAccessError.
if ( normalized_algorithm . parameter - > name ! = unwrapping_key - > algorithm_name ( ) ) {
WebIDL : : reject_promise ( realm , promise , WebIDL : : InvalidAccessError : : create ( realm , " Algorithm mismatch " _string ) ) ;
return ;
}
// 12. If the [[usages]] internal slot of unwrappingKey does not contain an entry that is "unwrapKey", then throw an InvalidAccessError.
if ( ! unwrapping_key - > internal_usages ( ) . contains_slow ( Bindings : : KeyUsage : : Unwrapkey ) ) {
WebIDL : : reject_promise ( realm , promise , WebIDL : : InvalidAccessError : : create ( realm , " Key does not support unwrapping keys " _string ) ) ;
return ;
}
auto key_or_error = [ & ] ( ) - > WebIDL : : ExceptionOr < GC : : Ref < JS : : ArrayBuffer > > {
// 13. If normalizedAlgorithm supports an unwrap key operation:
if ( operation = = " unwrapKey " ) {
// Let key be the result of performing the unwrap key operation specified by normalizedAlgorithm
// 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 " ) {
// Let key be the result of performing the decrypt operation specified by normalizedAlgorithm
// 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.
return WebIDL : : NotSupportedError : : create ( realm , " Algorithm does not support wrapping " _string ) ;
}
} ( ) ;
if ( key_or_error . is_error ( ) ) {
WebIDL : : reject_promise ( realm , promise , Bindings : : exception_to_throw_completion ( realm . vm ( ) , key_or_error . release_error ( ) ) . release_value ( ) . value ( ) ) ;
return ;
}
auto key = key_or_error . release_value ( ) ;
Variant < ByteBuffer , Bindings : : JsonWebKey , Empty > bytes ;
// 14. If format is equal to the strings "raw", "pkcs8", or "spki":
if ( format = = Bindings : : KeyFormat : : Raw | | format = = Bindings : : KeyFormat : : Pkcs8 | | format = = Bindings : : KeyFormat : : Spki ) {
// Set bytes be set to key.
bytes = key - > buffer ( ) ;
}
// If format is equal to the string "jwk":
else if ( format = = Bindings : : KeyFormat : : Jwk ) {
// Let bytes be the result of executing the parse a JWK algorithm, with key as the data to be parsed.
auto maybe_parsed = Bindings : : JsonWebKey : : parse ( realm , key - > buffer ( ) ) ;
if ( maybe_parsed . is_error ( ) ) {
WebIDL : : reject_promise ( realm , promise , maybe_parsed . release_error ( ) . release_value ( ) . value ( ) ) ;
return ;
}
bytes = maybe_parsed . release_value ( ) ;
} else {
VERIFY_NOT_REACHED ( ) ;
}
// 15. Let result be the result of performing the import key operation specified by normalizedKeyAlgorithm
// using unwrappedKeyAlgorithm as algorithm, format, usages and extractable and with bytes as keyData.
auto result_or_error = normalized_key_algorithm . methods - > import_key ( * normalized_key_algorithm . parameter , format , bytes . downcast < CryptoKey : : InternalKeyData > ( ) , extractable , key_usages ) ;
if ( result_or_error . is_error ( ) ) {
WebIDL : : reject_promise ( realm , promise , Bindings : : exception_to_throw_completion ( realm . vm ( ) , result_or_error . release_error ( ) ) . release_value ( ) . value ( ) ) ;
return ;
}
auto result = result_or_error . release_value ( ) ;
// 16. 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 ( ) ) {
WebIDL : : reject_promise ( realm , promise , WebIDL : : SyntaxError : : create ( realm , " Usages must not be empty " _string ) ) ;
return ;
}
// 17. Set the [[extractable]] internal slot of result to extractable.
result - > set_extractable ( extractable ) ;
// 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 ) ;
} ) ) ;
return promise ;
}
2024-03-14 21:52:17 -06:00
SupportedAlgorithmsMap & supported_algorithms_internal ( )
2023-12-14 00:38:14 +01:00
{
2024-03-14 21:52:17 -06:00
static SupportedAlgorithmsMap s_supported_algorithms ;
2023-12-14 00:38:14 +01:00
return s_supported_algorithms ;
}
2023-12-15 23:40:52 +01:00
// https://w3c.github.io/webcrypto/#algorithm-normalization-internalS
2024-11-24 20:53:41 +01:00
SupportedAlgorithmsMap const & supported_algorithms ( )
2023-12-14 00:38:14 +01: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 ,
} ;
for ( auto & operation : supported_operations ) {
internal_object . set ( operation , { } ) ;
}
// https://w3c.github.io/webcrypto/#algorithm-conventions
2024-11-01 16:35:30 +01:00
// https://w3c.github.io/webcrypto/#rsassa-pkcs1-registration
2024-12-26 18:55:31 +01: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 16:35:30 +01:00
// https://w3c.github.io/webcrypto/#rsa-pss-registration
2024-12-25 23:47:06 +01: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 16:35:30 +01: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 17:36:21 +01:00
define_an_algorithm < ECDSA , EcKeyImportParams > ( " importKey " _string , " ECDSA " _string ) ;
define_an_algorithm < ECDSA > ( " exportKey " _string , " ECDSA " _string ) ;
2024-11-01 16:35:30 +01:00
// https://w3c.github.io/webcrypto/#ecdh-registration
2024-11-26 19:46:04 +01:00
define_an_algorithm < ECDH , EcKeyImportParams > ( " importKey " _string , " ECDH " _string ) ;
2024-11-26 20:26:48 +01:00
define_an_algorithm < ECDH > ( " exportKey " _string , " ECDH " _string ) ;
2024-11-27 20:31:37 +01:00
define_an_algorithm < ECDH , EcdhKeyDeriveParams > ( " deriveBits " _string , " ECDH " _string ) ;
2024-11-17 18:14:13 +01:00
define_an_algorithm < ECDH , EcKeyGenParams > ( " generateKey " _string , " ECDH " _string ) ;
2024-10-25 05:58:30 +02:00
2024-10-30 22:44:20 +01:00
// https://w3c.github.io/webcrypto/#aes-ctr-registration
2024-10-30 23:53:48 +01:00
define_an_algorithm < AesCtr , AesCtrParams > ( " encrypt " _string , " AES-CTR " _string ) ;
2024-10-31 00:28:41 +01:00
define_an_algorithm < AesCtr , AesCtrParams > ( " decrypt " _string , " AES-CTR " _string ) ;
2024-11-01 16:35:30 +01:00
define_an_algorithm < AesCtr , AesKeyGenParams > ( " generateKey " _string , " AES-CTR " _string ) ;
2024-10-30 22:44:20 +01:00
define_an_algorithm < AesCtr > ( " importKey " _string , " AES-CTR " _string ) ;
2024-10-30 23:06:13 +01:00
define_an_algorithm < AesCtr > ( " exportKey " _string , " AES-CTR " _string ) ;
2024-10-30 22:53:47 +01:00
define_an_algorithm < AesCtr , AesDerivedKeyParams > ( " get key length " _string , " AES-CTR " _string ) ;
2024-11-01 16:35:30 +01: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 22:44:20 +01:00
2024-10-31 15:57:19 +01:00
// https://w3c.github.io/webcrypto/#aes-gcm-registration
2024-10-31 16:29:39 +01:00
define_an_algorithm < AesGcm , AesGcmParams > ( " encrypt " _string , " AES-GCM " _string ) ;
2024-10-31 16:37:51 +01:00
define_an_algorithm < AesGcm , AesGcmParams > ( " decrypt " _string , " AES-GCM " _string ) ;
2024-11-01 16:35:30 +01: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 15:57:19 +01:00
2024-11-01 16:35:30 +01:00
// https://w3c.github.io/webcrypto/#aes-kw-registration
2024-12-16 19:38:10 +01: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 16:35:30 +01:00
// https://w3c.github.io/webcrypto/#hmac-registration
2024-11-13 15:23:50 +01: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 16:35:30 +01: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 ) ;
// https://w3c.github.io/webcrypto/#hkdf-registration
2024-10-20 06:10:36 +02:00
define_an_algorithm < HKDF , HKDFParams > ( " deriveBits " _string , " HKDF " _string ) ;
2024-11-01 16:35:30 +01:00
define_an_algorithm < HKDF > ( " importKey " _string , " HKDF " _string ) ;
2024-10-20 06:10:36 +02:00
define_an_algorithm < HKDF > ( " get key length " _string , " HKDF " _string ) ;
2024-11-01 16:35:30 +01:00
// https://w3c.github.io/webcrypto/#pbkdf2-registration
2024-03-27 19:53:08 +01:00
define_an_algorithm < PBKDF2 , PBKDF2Params > ( " deriveBits " _string , " PBKDF2 " _string ) ;
2024-11-01 16:35:30 +01:00
define_an_algorithm < PBKDF2 > ( " importKey " _string , " PBKDF2 " _string ) ;
2024-03-27 20:30:11 +01:00
define_an_algorithm < PBKDF2 > ( " get key length " _string , " PBKDF2 " _string ) ;
2023-12-15 22:03:04 +01:00
2024-11-01 16:35:30 +01:00
// https://wicg.github.io/webcrypto-secure-curves/#x25519-registration
2024-11-27 20:31:37 +01:00
define_an_algorithm < X25519 , EcdhKeyDeriveParams > ( " deriveBits " _string , " X25519 " _string ) ;
2024-11-01 16:35:30 +01: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 16:30:17 -07:00
2024-11-01 16:35:30 +01:00
// https://wicg.github.io/webcrypto-secure-curves/#x448-registration
2024-11-27 20:31:37 +01:00
define_an_algorithm < X448 , EcdhKeyDeriveParams > ( " deriveBits " _string , " X448 " _string ) ;
2024-11-25 11:18:05 +01:00
define_an_algorithm < X448 > ( " generateKey " _string , " X448 " _string ) ;
2024-11-25 15:46:21 +01:00
define_an_algorithm < X448 > ( " importKey " _string , " X448 " _string ) ;
2024-11-25 11:35:09 +01:00
define_an_algorithm < X448 > ( " exportKey " _string , " X448 " _string ) ;
2024-03-27 01:27:42 +01:00
2024-11-01 16:35:30 +01:00
// https://wicg.github.io/webcrypto-secure-curves/#ed25519-registration
2024-03-31 23:04:58 +02:00
define_an_algorithm < ED25519 > ( " sign " _string , " Ed25519 " _string ) ;
2024-03-31 23:05:05 +02:00
define_an_algorithm < ED25519 > ( " verify " _string , " Ed25519 " _string ) ;
2024-03-31 23:04:12 +02:00
define_an_algorithm < ED25519 > ( " generateKey " _string , " Ed25519 " _string ) ;
2024-11-24 20:21:51 +01:00
define_an_algorithm < ED25519 > ( " importKey " _string , " Ed25519 " _string ) ;
2024-11-24 20:48:46 +01:00
define_an_algorithm < ED25519 > ( " exportKey " _string , " Ed25519 " _string ) ;
2024-11-01 16:35:30 +01:00
// https://wicg.github.io/webcrypto-secure-curves/#ed448-registration
2024-12-21 14:45:29 +01: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 19:57:59 +02:00
2023-12-14 00:38:14 +01:00
return internal_object ;
}
// https://w3c.github.io/webcrypto/#concept-define-an-algorithm
2024-03-06 16:53:50 -07:00
template < typename Methods , typename Param >
2024-03-14 21:52:17 -06:00
void define_an_algorithm ( AK : : String op , AK : : String algorithm )
2023-12-14 00:38:14 +01: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 16:53:50 -07:00
registered_algorithms . set ( algorithm , RegisteredAlgorithm { & Methods : : create , & Param : : from_value } ) ;
2023-12-14 00:38:14 +01:00
internal_object . set ( op , registered_algorithms ) ;
}
2021-12-13 22:09:55 +00:00
}