1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "inspector_utils.h"
17
18 #include "jsvm_dfx.h"
19 #include "unicode/unistr.h"
20
21 #if HAVE_OPENSSL
22 #include "openssl/opensslv.h"
23 #endif
24
25 #if OPENSSL_VERSION_MAJOR >= 3
26 #include "openssl/provider.h"
27 #endif
28
29 #include <openssl/err.h>
30 #include <openssl/rand.h>
31
32 namespace jsvm {
33 namespace inspector {
34 namespace {
Utf8ToUtf16(const char * data,size_t len)35 inline icu::UnicodeString Utf8ToUtf16(const char* data, size_t len)
36 {
37 icu::UnicodeString utf16Str = icu::UnicodeString::fromUTF8(icu::StringPiece(data, len));
38
39 return utf16Str;
40 }
41
Utf16ToUtf8(const char16_t * data,size_t length)42 inline std::string Utf16ToUtf8(const char16_t* data, size_t length)
43 {
44 icu::UnicodeString unicodeStr(data, length);
45 std::string utf8Str;
46 unicodeStr.toUTF8String(utf8Str);
47
48 return utf8Str;
49 }
50 } // namespace
51
Utf8ToStringView(const std::string_view message)52 std::unique_ptr<v8_inspector::StringBuffer> Utf8ToStringView(const std::string_view message)
53 {
54 icu::UnicodeString utf16Str = Utf8ToUtf16(message.data(), message.length());
55 size_t utf16Len = utf16Str.length();
56
57 v8_inspector::StringView view(reinterpret_cast<const uint16_t*>(utf16Str.getBuffer()), utf16Len);
58 return v8_inspector::StringBuffer::create(view);
59 }
60
StringViewToUtf8(v8_inspector::StringView view)61 std::string StringViewToUtf8(v8_inspector::StringView view)
62 {
63 if (view.length() == 0) {
64 return "";
65 }
66 if (view.is8Bit()) {
67 return std::string(reinterpret_cast<const char*>(view.characters8()), view.length());
68 }
69 const char16_t* source = reinterpret_cast<const char16_t*>(view.characters16());
70
71 return Utf16ToUtf8(source, view.length());
72 }
73
74 static constexpr char BASE64_CHAR_SET[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
75
76 // clang-format off
Base64Encode(const char * inputString,size_t slen,char * outputBuffer,size_t dlen)77 size_t Base64Encode(const char* inputString, size_t slen, char* outputBuffer, size_t dlen)
78 {
79 // 1: caluate encode size and check
80 size_t strLen = slen;
81 size_t encodedStrLen = Base64EncodeSize(slen);
82
83 CHECK_GE(dlen, encodedStrLen);
84
85 // 2: the index do not exceed the range of outputBuffer and form a complete four-character block
86 for (size_t i = 0, j = 0; j < strLen - 2; i += TRANSFORMED_CHAR_NUM, j += TO_TRANSFORM_CHAR_NUM) {
87 // convert three 8bit into four 6bit; then add two 0 bit in each 6 bit
88 // former 00 + first 6 bits of the first char
89 outputBuffer[i] = BASE64_CHAR_SET[(static_cast<unsigned int>(inputString[j]) & 0xff) >> ByteOffset::BIT_2];
90 // 00 + the last 2 bits of the first char + the first 4 bits of the second char
91 outputBuffer[i + ByteOffset::BYTE_1] =
92 BASE64_CHAR_SET[(static_cast<unsigned int>(inputString[j]) & 0x03) << ByteOffset::BIT_4 |
93 (static_cast<unsigned int>(inputString[j + ByteOffset::BYTE_1]) & 0xf0) >>
94 ByteOffset::BIT_4];
95 // 00 + last 4 bits of the second char + the first 2 bits of the third char
96 outputBuffer[i + ByteOffset::BYTE_2] =
97 BASE64_CHAR_SET[(static_cast<unsigned int>(inputString[j + ByteOffset::BYTE_1]) & 0x0f) <<
98 ByteOffset::BIT_2 |
99 (static_cast<unsigned int>(inputString[j + ByteOffset::BYTE_2]) & 0xc0) >>
100 ByteOffset::BIT_6];
101 // 00 + the last 6 bits of the third char
102 outputBuffer[i + ByteOffset::BYTE_3] =
103 BASE64_CHAR_SET[static_cast<unsigned int>(inputString[j + ByteOffset::BYTE_2]) & 0x3f];
104 }
105 switch (strLen % TO_TRANSFORM_CHAR_NUM) {
106 // the original string is less than three bytes, and the missing place is filled with '=' to patch four bytes
107 case ByteSize::SIZE_1_BYTES:
108 // 1,2: the original character is one, and two characters are missing after conversion
109 outputBuffer[encodedStrLen - ByteOffset::BYTE_4] =
110 BASE64_CHAR_SET[(static_cast<unsigned int>(inputString[strLen - ByteOffset::BYTE_1]) & 0xff) >>
111 ByteOffset::BIT_2];
112 outputBuffer[encodedStrLen - ByteOffset::BYTE_3] =
113 BASE64_CHAR_SET[(static_cast<unsigned int>(inputString[strLen - ByteOffset::BYTE_1]) & 0x03) <<
114 ByteOffset::BIT_4];
115 outputBuffer[encodedStrLen - ByteOffset::BYTE_2] = '=';
116 outputBuffer[encodedStrLen - ByteOffset::BYTE_1] = '=';
117 break;
118 case ByteSize::SIZE_2_BYTES:
119 // 1: the original character is two, and a character are missing after conversion
120 outputBuffer[encodedStrLen - ByteOffset::BYTE_4] =
121 BASE64_CHAR_SET[(static_cast<unsigned int>(inputString[strLen - ByteOffset::BYTE_2]) & 0xff) >>
122 ByteOffset::BIT_2];
123 outputBuffer[encodedStrLen - ByteOffset::BYTE_3] =
124 BASE64_CHAR_SET[(static_cast<unsigned int>(inputString[strLen - ByteOffset::BYTE_2]) & 0x03) <<
125 ByteOffset::BIT_4 |
126 (static_cast<unsigned int>(inputString[strLen - ByteOffset::BYTE_1]) & 0xf0) >>
127 ByteOffset::BIT_4];
128 outputBuffer[encodedStrLen - ByteOffset::BYTE_2] =
129 BASE64_CHAR_SET[(static_cast<unsigned int>(inputString[strLen - ByteOffset::BYTE_1]) & 0x0f) <<
130 ByteOffset::BIT_2];
131 outputBuffer[encodedStrLen - ByteOffset::BYTE_1] = '=';
132 break;
133 default:
134 break;
135 }
136
137 return encodedStrLen;
138 }
139 // clang-format on
140
GetHumanReadableProcessName()141 std::string GetHumanReadableProcessName()
142 {
143 return "JSVM[" + std::to_string(platform::OS::GetPid()) + "]";
144 }
145
CSPRNG(void * buffer,size_t length)146 MUST_USE_RESULT bool CSPRNG(void* buffer, size_t length)
147 {
148 unsigned char* buf = static_cast<unsigned char*>(buffer);
149 do {
150 if (RAND_status() == 1) {
151 #if OPENSSL_VERSION_MAJOR >= 3
152 if (RAND_bytes_ex(nullptr, buf, length, 0) == 1) {
153 return true;
154 }
155 #else
156 while (length > INT_MAX && RAND_bytes(buf, INT_MAX) == 1) {
157 buf += INT_MAX;
158 length -= INT_MAX;
159 }
160 if (length <= INT_MAX && RAND_bytes(buf, static_cast<int>(length)) == 1) {
161 return true;
162 }
163 #endif
164 }
165 #if OPENSSL_VERSION_MAJOR >= 3
166 const auto code = ERR_peek_last_error();
167 // A misconfigured OpenSSL 3 installation may report 1 from RAND_poll()
168 // and RAND_status() but fail in RAND_bytes() if it cannot look up
169 // a matching algorithm for the CSPRNG.
170 if (ERR_GET_LIB(code) == ERR_LIB_RAND) {
171 const auto reason = ERR_GET_REASON(code);
172 if (reason == RAND_R_ERROR_INSTANTIATING_DRBG || reason == RAND_R_UNABLE_TO_FETCH_DRBG ||
173 reason == RAND_R_UNABLE_TO_CREATE_DRBG) {
174 return false;
175 }
176 }
177 #endif
178 } while (RAND_poll() == 1);
179
180 return false;
181 }
182
CheckedUvLoopClose(uv_loop_t * loop)183 void CheckedUvLoopClose(uv_loop_t* loop)
184 {
185 if (uv_loop_close(loop) == 0) {
186 return;
187 }
188
189 // Finally, abort.
190 UNREACHABLE("uv_loop_close() while having open handles");
191 }
192
193 using v8::Isolate;
194 using v8::Local;
195 using v8::String;
196 using v8::Value;
197
TwoByteValue(Isolate * isolate,Local<Value> value)198 TwoByteValue::TwoByteValue(Isolate* isolate, Local<Value> value)
199 {
200 if (value.IsEmpty()) {
201 return;
202 }
203
204 Local<String> string;
205 if (!value->ToString(isolate->GetCurrentContext()).ToLocal(&string)) {
206 return;
207 }
208
209 // Allocate enough space to include the null terminator
210 const size_t storage = string->Length() + 1;
211 AllocateSufficientStorage(storage);
212
213 const int flags = String::NO_NULL_TERMINATION;
214 const int length = string->Write(isolate, Out(), 0, storage, flags);
215 SetLengthAndZeroTerminate(length);
216 }
217 } // namespace inspector
218 } // namespace jsvm