/src/serenity/Userland/Libraries/LibWeb/Crypto/KeyAlgorithms.cpp
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2023, stelar7 <dudedbz@gmail.com> |
3 | | * Copyright (c) 2024, Andrew Kaster <akaster@serenityos.org> |
4 | | * |
5 | | * SPDX-License-Identifier: BSD-2-Clause |
6 | | */ |
7 | | |
8 | | #include <LibJS/Runtime/GlobalObject.h> |
9 | | #include <LibJS/Runtime/PrimitiveString.h> |
10 | | #include <LibJS/Runtime/TypedArray.h> |
11 | | #include <LibWeb/Bindings/ExceptionOrUtils.h> |
12 | | #include <LibWeb/Crypto/KeyAlgorithms.h> |
13 | | |
14 | | namespace Web::Crypto { |
15 | | |
16 | | JS_DEFINE_ALLOCATOR(KeyAlgorithm); |
17 | | JS_DEFINE_ALLOCATOR(RsaKeyAlgorithm); |
18 | | JS_DEFINE_ALLOCATOR(RsaHashedKeyAlgorithm); |
19 | | JS_DEFINE_ALLOCATOR(EcKeyAlgorithm); |
20 | | |
21 | | template<typename T> |
22 | | static JS::ThrowCompletionOr<T*> impl_from(JS::VM& vm, StringView Name) |
23 | 0 | { |
24 | 0 | auto this_value = vm.this_value(); |
25 | 0 | JS::Object* this_object = nullptr; |
26 | 0 | if (this_value.is_nullish()) |
27 | 0 | this_object = &vm.current_realm()->global_object(); |
28 | 0 | else |
29 | 0 | this_object = TRY(this_value.to_object(vm)); |
30 | |
|
31 | 0 | if (!is<T>(this_object)) |
32 | 0 | return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, Name); |
33 | 0 | return static_cast<T*>(this_object); |
34 | 0 | } Unexecuted instantiation: KeyAlgorithms.cpp:JS::ThrowCompletionOr<Web::Crypto::KeyAlgorithm*> Web::Crypto::impl_from<Web::Crypto::KeyAlgorithm>(JS::VM&, AK::StringView) Unexecuted instantiation: KeyAlgorithms.cpp:JS::ThrowCompletionOr<Web::Crypto::RsaKeyAlgorithm*> Web::Crypto::impl_from<Web::Crypto::RsaKeyAlgorithm>(JS::VM&, AK::StringView) Unexecuted instantiation: KeyAlgorithms.cpp:JS::ThrowCompletionOr<Web::Crypto::EcKeyAlgorithm*> Web::Crypto::impl_from<Web::Crypto::EcKeyAlgorithm>(JS::VM&, AK::StringView) Unexecuted instantiation: KeyAlgorithms.cpp:JS::ThrowCompletionOr<Web::Crypto::RsaHashedKeyAlgorithm*> Web::Crypto::impl_from<Web::Crypto::RsaHashedKeyAlgorithm>(JS::VM&, AK::StringView) |
35 | | |
36 | | JS::NonnullGCPtr<KeyAlgorithm> KeyAlgorithm::create(JS::Realm& realm) |
37 | 0 | { |
38 | 0 | return realm.heap().allocate<KeyAlgorithm>(realm, realm); |
39 | 0 | } |
40 | | |
41 | | KeyAlgorithm::KeyAlgorithm(JS::Realm& realm) |
42 | 0 | : Object(ConstructWithPrototypeTag::Tag, realm.intrinsics().object_prototype()) |
43 | 0 | , m_realm(realm) |
44 | 0 | { |
45 | 0 | } |
46 | | |
47 | | void KeyAlgorithm::initialize(JS::Realm& realm) |
48 | 0 | { |
49 | 0 | define_native_accessor(realm, "name", name_getter, {}, JS::Attribute::Enumerable | JS::Attribute::Configurable); |
50 | 0 | Base::initialize(realm); |
51 | 0 | } |
52 | | |
53 | | JS_DEFINE_NATIVE_FUNCTION(KeyAlgorithm::name_getter) |
54 | 0 | { |
55 | 0 | auto* impl = TRY(impl_from<KeyAlgorithm>(vm, "KeyAlgorithm"sv)); |
56 | 0 | auto name = TRY(Bindings::throw_dom_exception_if_needed(vm, [&] { return impl->name(); })); |
57 | 0 | return JS::PrimitiveString::create(vm, name); |
58 | 0 | } |
59 | | |
60 | | void KeyAlgorithm::visit_edges(Visitor& visitor) |
61 | 0 | { |
62 | 0 | Base::visit_edges(visitor); |
63 | 0 | visitor.visit(m_realm); |
64 | 0 | } |
65 | | |
66 | | JS::NonnullGCPtr<RsaKeyAlgorithm> RsaKeyAlgorithm::create(JS::Realm& realm) |
67 | 0 | { |
68 | 0 | return realm.heap().allocate<RsaKeyAlgorithm>(realm, realm); |
69 | 0 | } |
70 | | |
71 | | RsaKeyAlgorithm::RsaKeyAlgorithm(JS::Realm& realm) |
72 | 0 | : KeyAlgorithm(realm) |
73 | 0 | , m_public_exponent(MUST(JS::Uint8Array::create(realm, 0))) |
74 | 0 | { |
75 | 0 | } |
76 | | |
77 | | void RsaKeyAlgorithm::initialize(JS::Realm& realm) |
78 | 0 | { |
79 | 0 | Base::initialize(realm); |
80 | |
|
81 | 0 | define_native_accessor(realm, "modulusLength", modulus_length_getter, {}, JS::Attribute::Enumerable | JS::Attribute::Configurable); |
82 | 0 | define_native_accessor(realm, "publicExponent", public_exponent_getter, {}, JS::Attribute::Enumerable | JS::Attribute::Configurable); |
83 | 0 | } |
84 | | |
85 | | void RsaKeyAlgorithm::visit_edges(Visitor& visitor) |
86 | 0 | { |
87 | 0 | Base::visit_edges(visitor); |
88 | 0 | visitor.visit(m_public_exponent); |
89 | 0 | } |
90 | | |
91 | | WebIDL::ExceptionOr<void> RsaKeyAlgorithm::set_public_exponent(::Crypto::UnsignedBigInteger exponent) |
92 | 0 | { |
93 | 0 | static_assert(AK::HostIsLittleEndian, "This code assumes a little endian host"); |
94 | |
|
95 | 0 | auto& realm = this->realm(); |
96 | 0 | auto& vm = this->vm(); |
97 | |
|
98 | 0 | auto bytes = TRY_OR_THROW_OOM(vm, ByteBuffer::create_uninitialized(exponent.trimmed_byte_length())); |
99 | |
|
100 | 0 | bool const remove_leading_zeroes = true; |
101 | 0 | auto data_size = exponent.export_data(bytes.span(), remove_leading_zeroes); |
102 | 0 | auto data_slice = bytes.bytes().slice(bytes.size() - data_size, data_size); |
103 | | |
104 | | // The BigInteger typedef from the WebCrypto spec requires the bytes in the Uint8Array be ordered in Big Endian |
105 | |
|
106 | 0 | Vector<u8, 32> byte_swapped_data; |
107 | 0 | byte_swapped_data.ensure_capacity(data_size); |
108 | 0 | for (size_t i = 0; i < data_size; ++i) |
109 | 0 | byte_swapped_data.append(data_slice[data_size - i - 1]); |
110 | |
|
111 | 0 | m_public_exponent = TRY(JS::Uint8Array::create(realm, byte_swapped_data.size())); |
112 | 0 | m_public_exponent->viewed_array_buffer()->buffer().overwrite(0, byte_swapped_data.data(), byte_swapped_data.size()); |
113 | |
|
114 | 0 | return {}; |
115 | 0 | } |
116 | | |
117 | | JS_DEFINE_NATIVE_FUNCTION(RsaKeyAlgorithm::modulus_length_getter) |
118 | 0 | { |
119 | 0 | auto* impl = TRY(impl_from<RsaKeyAlgorithm>(vm, "RsaKeyAlgorithm"sv)); |
120 | 0 | return JS::Value(impl->modulus_length()); |
121 | 0 | } |
122 | | |
123 | | JS_DEFINE_NATIVE_FUNCTION(RsaKeyAlgorithm::public_exponent_getter) |
124 | 0 | { |
125 | 0 | auto* impl = TRY(impl_from<RsaKeyAlgorithm>(vm, "RsaKeyAlgorithm"sv)); |
126 | 0 | return impl->public_exponent(); |
127 | 0 | } |
128 | | |
129 | | JS::NonnullGCPtr<EcKeyAlgorithm> EcKeyAlgorithm::create(JS::Realm& realm) |
130 | 0 | { |
131 | 0 | return realm.heap().allocate<EcKeyAlgorithm>(realm, realm); |
132 | 0 | } |
133 | | |
134 | | EcKeyAlgorithm::EcKeyAlgorithm(JS::Realm& realm) |
135 | 0 | : KeyAlgorithm(realm) |
136 | 0 | { |
137 | 0 | } |
138 | | |
139 | | void EcKeyAlgorithm::initialize(JS::Realm& realm) |
140 | 0 | { |
141 | 0 | Base::initialize(realm); |
142 | |
|
143 | 0 | define_native_accessor(realm, "namedCurve", named_curve_getter, {}, JS::Attribute::Enumerable | JS::Attribute::Configurable); |
144 | 0 | } |
145 | | |
146 | | JS_DEFINE_NATIVE_FUNCTION(EcKeyAlgorithm::named_curve_getter) |
147 | 0 | { |
148 | 0 | auto* impl = TRY(impl_from<EcKeyAlgorithm>(vm, "EcKeyAlgorithm"sv)); |
149 | 0 | return JS::PrimitiveString::create(vm, impl->named_curve()); |
150 | 0 | } |
151 | | |
152 | | JS::NonnullGCPtr<RsaHashedKeyAlgorithm> RsaHashedKeyAlgorithm::create(JS::Realm& realm) |
153 | 0 | { |
154 | 0 | return realm.heap().allocate<RsaHashedKeyAlgorithm>(realm, realm); |
155 | 0 | } |
156 | | |
157 | | RsaHashedKeyAlgorithm::RsaHashedKeyAlgorithm(JS::Realm& realm) |
158 | 0 | : RsaKeyAlgorithm(realm) |
159 | 0 | , m_hash(String {}) |
160 | 0 | { |
161 | 0 | } |
162 | | |
163 | | void RsaHashedKeyAlgorithm::initialize(JS::Realm& realm) |
164 | 0 | { |
165 | 0 | Base::initialize(realm); |
166 | |
|
167 | 0 | define_native_accessor(realm, "hash", hash_getter, {}, JS::Attribute::Enumerable | JS::Attribute::Configurable); |
168 | 0 | } |
169 | | |
170 | | JS_DEFINE_NATIVE_FUNCTION(RsaHashedKeyAlgorithm::hash_getter) |
171 | 0 | { |
172 | 0 | auto* impl = TRY(impl_from<RsaHashedKeyAlgorithm>(vm, "RsaHashedKeyAlgorithm"sv)); |
173 | 0 | auto hash = TRY(Bindings::throw_dom_exception_if_needed(vm, [&] { return impl->hash(); })); |
174 | 0 | return hash.visit( |
175 | 0 | [&](String const& hash_string) -> JS::Value { |
176 | 0 | return JS::PrimitiveString::create(vm, hash_string); |
177 | 0 | }, |
178 | 0 | [&](JS::Handle<JS::Object> const& hash) -> JS::Value { |
179 | 0 | return hash; |
180 | 0 | }); |
181 | 0 | } |
182 | | |
183 | | } |