CryptoKey.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  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. #include <AK/Memory.h>
  8. #include <LibJS/Runtime/Array.h>
  9. #include <LibWeb/Bindings/CryptoKeyPrototype.h>
  10. #include <LibWeb/Bindings/ExceptionOrUtils.h>
  11. #include <LibWeb/Crypto/CryptoKey.h>
  12. namespace Web::Crypto {
  13. JS_DEFINE_ALLOCATOR(CryptoKey);
  14. JS_DEFINE_ALLOCATOR(CryptoKeyPair);
  15. JS::NonnullGCPtr<CryptoKey> CryptoKey::create(JS::Realm& realm, InternalKeyData key_data)
  16. {
  17. return realm.create<CryptoKey>(realm, move(key_data));
  18. }
  19. JS::NonnullGCPtr<CryptoKey> CryptoKey::create(JS::Realm& realm)
  20. {
  21. return realm.create<CryptoKey>(realm);
  22. }
  23. CryptoKey::CryptoKey(JS::Realm& realm, InternalKeyData key_data)
  24. : PlatformObject(realm)
  25. , m_algorithm(Object::create(realm, nullptr))
  26. , m_usages(Object::create(realm, nullptr))
  27. , m_key_data(move(key_data))
  28. {
  29. }
  30. CryptoKey::CryptoKey(JS::Realm& realm)
  31. : PlatformObject(realm)
  32. , m_algorithm(Object::create(realm, nullptr))
  33. , m_usages(Object::create(realm, nullptr))
  34. , m_key_data(MUST(ByteBuffer::create_uninitialized(0)))
  35. {
  36. }
  37. CryptoKey::~CryptoKey()
  38. {
  39. m_key_data.visit(
  40. [](ByteBuffer& data) { secure_zero(data.data(), data.size()); },
  41. [](auto& data) { secure_zero(reinterpret_cast<u8*>(&data), sizeof(data)); });
  42. }
  43. void CryptoKey::initialize(JS::Realm& realm)
  44. {
  45. Base::initialize(realm);
  46. WEB_SET_PROTOTYPE_FOR_INTERFACE(CryptoKey);
  47. }
  48. void CryptoKey::visit_edges(Visitor& visitor)
  49. {
  50. Base::visit_edges(visitor);
  51. visitor.visit(m_algorithm);
  52. visitor.visit(m_usages);
  53. }
  54. void CryptoKey::set_usages(Vector<Bindings::KeyUsage> usages)
  55. {
  56. m_key_usages = move(usages);
  57. auto& realm = this->realm();
  58. m_usages = JS::Array::create_from<Bindings::KeyUsage>(realm, m_key_usages.span(), [&](auto& key_usage) -> JS::Value {
  59. return JS::PrimitiveString::create(realm.vm(), Bindings::idl_enum_to_string(key_usage));
  60. });
  61. }
  62. String CryptoKey::algorithm_name() const
  63. {
  64. if (m_algorithm_name.is_empty()) {
  65. auto name = MUST(m_algorithm->get("name"));
  66. m_algorithm_name = MUST(name.to_string(vm()));
  67. }
  68. return m_algorithm_name;
  69. }
  70. JS::NonnullGCPtr<CryptoKeyPair> CryptoKeyPair::create(JS::Realm& realm, JS::NonnullGCPtr<CryptoKey> public_key, JS::NonnullGCPtr<CryptoKey> private_key)
  71. {
  72. return realm.create<CryptoKeyPair>(realm, public_key, private_key);
  73. }
  74. CryptoKeyPair::CryptoKeyPair(JS::Realm& realm, JS::NonnullGCPtr<CryptoKey> public_key, JS::NonnullGCPtr<CryptoKey> private_key)
  75. : Object(ConstructWithPrototypeTag::Tag, realm.intrinsics().object_prototype())
  76. , m_public_key(public_key)
  77. , m_private_key(private_key)
  78. {
  79. }
  80. void CryptoKeyPair::initialize(JS::Realm& realm)
  81. {
  82. define_native_accessor(realm, "publicKey", public_key_getter, {}, JS::Attribute::Enumerable | JS::Attribute::Configurable);
  83. define_native_accessor(realm, "privateKey", private_key_getter, {}, JS::Attribute::Enumerable | JS::Attribute::Configurable);
  84. Base::initialize(realm);
  85. }
  86. void CryptoKeyPair::visit_edges(Visitor& visitor)
  87. {
  88. Base::visit_edges(visitor);
  89. visitor.visit(m_public_key);
  90. visitor.visit(m_private_key);
  91. }
  92. static JS::ThrowCompletionOr<CryptoKeyPair*> impl_from(JS::VM& vm)
  93. {
  94. auto this_value = vm.this_value();
  95. JS::Object* this_object = nullptr;
  96. if (this_value.is_nullish())
  97. this_object = &vm.current_realm()->global_object();
  98. else
  99. this_object = TRY(this_value.to_object(vm));
  100. if (!is<CryptoKeyPair>(this_object))
  101. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "CryptoKeyPair");
  102. return static_cast<CryptoKeyPair*>(this_object);
  103. }
  104. JS_DEFINE_NATIVE_FUNCTION(CryptoKeyPair::public_key_getter)
  105. {
  106. auto* impl = TRY(impl_from(vm));
  107. return TRY(Bindings::throw_dom_exception_if_needed(vm, [&] { return impl->public_key(); }));
  108. }
  109. JS_DEFINE_NATIVE_FUNCTION(CryptoKeyPair::private_key_getter)
  110. {
  111. auto* impl = TRY(impl_from(vm));
  112. return TRY(Bindings::throw_dom_exception_if_needed(vm, [&] { return impl->private_key(); }));
  113. }
  114. WebIDL::ExceptionOr<void> CryptoKey::serialization_steps(HTML::SerializationRecord& serialized, bool for_storage, HTML::SerializationMemory& memory)
  115. {
  116. auto& vm = this->vm();
  117. // 1. Set serialized.[[Type]] to the [[type]] internal slot of value.
  118. HTML::serialize_primitive_type(serialized, static_cast<u32>(m_type));
  119. // 2. Set serialized.[[Extractable]] to the [[extractable]] internal slot of value.
  120. HTML::serialize_primitive_type(serialized, m_extractable);
  121. // 3. Set serialized.[[Algorithm]] to the sub-serialization of the [[algorithm]] internal slot of value.
  122. auto serialized_algorithm = TRY(HTML::structured_serialize_internal(vm, m_algorithm, for_storage, memory));
  123. serialized.extend(move(serialized_algorithm));
  124. // 4. Set serialized.[[Usages]] to the sub-serialization of the [[usages]] internal slot of value.
  125. auto serialized_usages = TRY(HTML::structured_serialize_internal(vm, m_usages, for_storage, memory));
  126. serialized.extend(move(serialized_usages));
  127. // FIXME: 5. Set serialized.[[Handle]] to the [[handle]] internal slot of value.
  128. return {};
  129. }
  130. WebIDL::ExceptionOr<void> CryptoKey::deserialization_steps(ReadonlySpan<u32> const& serialized, size_t& position, HTML::DeserializationMemory& memory)
  131. {
  132. auto& vm = this->vm();
  133. auto& realm = this->realm();
  134. // 1. Initialize the [[type]] internal slot of value to serialized.[[Type]].
  135. m_type = static_cast<Bindings::KeyType>(HTML::deserialize_primitive_type<u32>(serialized, position));
  136. // 2. Initialize the [[extractable]] internal slot of value to serialized.[[Extractable]].
  137. m_extractable = HTML::deserialize_primitive_type<bool>(serialized, position);
  138. // 3. Initialize the [[algorithm]] internal slot of value to the sub-deserialization of serialized.[[Algorithm]].
  139. auto deserialized_record = TRY(HTML::structured_deserialize_internal(vm, serialized, realm, memory, position));
  140. if (deserialized_record.value.has_value())
  141. m_algorithm = deserialized_record.value.release_value().as_object();
  142. position = deserialized_record.position;
  143. // 4. Initialize the [[usages]] internal slot of value to the sub-deserialization of serialized.[[Usages]].
  144. deserialized_record = TRY(HTML::structured_deserialize_internal(vm, serialized, realm, memory, position));
  145. if (deserialized_record.value.has_value())
  146. m_usages = deserialized_record.value.release_value().as_object();
  147. position = deserialized_record.position;
  148. // FIXME: 5. Initialize the [[handle]] internal slot of value to serialized.[[Handle]].
  149. return {};
  150. }
  151. }