1 /*
2 * Copyright (c) 2022-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 "tls_connect_context.h"
17
18 #include <cstdint>
19 #include <string>
20 #include <string_view>
21 #include <vector>
22
23 #include "constant.h"
24 #include "napi_utils.h"
25 #include "netstack_log.h"
26 #include "socket_constant.h"
27
28 namespace OHOS {
29 namespace NetStack {
30 namespace TlsSocket {
31 namespace {
32 constexpr const char *ALPN_PROTOCOLS = "ALPNProtocols";
33 constexpr const char *SECURE_OPTIONS = "secureOptions";
34 constexpr const char *CA_NAME = "ca";
35 constexpr const char *CERT_NAME = "cert";
36 constexpr const char *KEY_NAME = "key";
37 constexpr const char *PASSWD_NAME = "passwd";
38 constexpr const char *PROTOCOLS_NAME = "protocols";
39 constexpr const char *SIGNATURE_ALGORITHMS = "signatureAlgorithms";
40 constexpr const char *USE_REMOTE_CIPHER_PREFER = "useRemoteCipherPrefer";
41 constexpr const char *CIPHER_SUITE = "cipherSuite";
42 constexpr const char *ADDRESS_NAME = "address";
43 constexpr const char *FAMILY_NAME = "family";
44 constexpr const char *PORT_NAME = "port";
45 constexpr const char *VERIFY_MODE_NAME = "isBidirectionalAuthentication";
46 constexpr const char *SKIP_REMOTE_VALIDATION = "skipRemoteValidation";
47 constexpr const char *KEY_PROXY = "proxy";
48 constexpr uint32_t CA_CHAIN_LENGTH = 1000;
49 constexpr uint32_t PROTOCOLS_SIZE = 10;
50 constexpr std::string_view PARSE_ERROR = "options is not type of TLSConnectOptions";
51
ReadNecessaryOptions(napi_env env,napi_value secureOptions,TLSSecureOptions & secureOption)52 bool ReadNecessaryOptions(napi_env env, napi_value secureOptions, TLSSecureOptions &secureOption)
53 {
54 if (!NapiUtils::HasNamedProperty(env, secureOptions, CA_NAME)) {
55 NETSTACK_LOGD("use default ca certification");
56 }
57 napi_value caCert = NapiUtils::GetNamedProperty(env, secureOptions, CA_NAME);
58 std::vector<std::string> caVec;
59 if (NapiUtils::GetValueType(env, caCert) == napi_string) {
60 std::string ca = NapiUtils::GetStringPropertyUtf8(env, secureOptions, CA_NAME);
61 caVec.push_back(ca);
62 }
63 if (NapiUtils::GetValueType(env, caCert) == napi_object) {
64 uint32_t arrayLong = NapiUtils::GetArrayLength(env, caCert);
65 if (arrayLong > CA_CHAIN_LENGTH) {
66 return false;
67 }
68 napi_value element = nullptr;
69 for (uint32_t i = 0; i < arrayLong; i++) {
70 element = NapiUtils::GetArrayElement(env, caCert, i);
71 std::string ca = NapiUtils::GetStringFromValueUtf8(env, element);
72 caVec.push_back(ca);
73 }
74 }
75 secureOption.SetCaChain(caVec);
76
77 if (NapiUtils::HasNamedProperty(env, secureOptions, KEY_NAME)) {
78 secureOption.SetKey(SecureData(NapiUtils::GetStringPropertyUtf8(env, secureOptions, KEY_NAME)));
79 }
80 if (NapiUtils::HasNamedProperty(env, secureOptions, CERT_NAME)) {
81 secureOption.SetCert(NapiUtils::GetStringPropertyUtf8(env, secureOptions, CERT_NAME));
82 }
83 if (NapiUtils::HasNamedProperty(env, secureOptions, VERIFY_MODE_NAME)) {
84 VerifyMode tempVerifyMode = !NapiUtils::GetBooleanProperty(env, secureOptions, VERIFY_MODE_NAME)
85 ? VerifyMode::ONE_WAY_MODE
86 : VerifyMode::TWO_WAY_MODE;
87 secureOption.SetVerifyMode(tempVerifyMode);
88 } else {
89 secureOption.SetVerifyMode(VerifyMode::ONE_WAY_MODE);
90 }
91 return true;
92 }
93 } // namespace
94
TLSConnectContext(napi_env env,const std::shared_ptr<EventManager> & manager)95 TLSConnectContext::TLSConnectContext(napi_env env, const std::shared_ptr<EventManager> &manager)
96 : BaseContext(env, manager) {}
97
ParseParams(napi_value * params,size_t paramsCount)98 void TLSConnectContext::ParseParams(napi_value *params, size_t paramsCount)
99 {
100 if (!CheckParamsType(params, paramsCount)) {
101 return;
102 }
103 connectOptions_ = ReadTLSConnectOptions(GetEnv(), params);
104
105 if (paramsCount == PARAM_OPTIONS_AND_CALLBACK) {
106 SetParseOK(SetCallback(params[ARG_INDEX_1]) == napi_ok);
107 return;
108 }
109 SetParseOK(true);
110 }
111
GetErrorCode() const112 int32_t TLSConnectContext::GetErrorCode() const
113 {
114 auto err = BaseContext::GetErrorCode();
115 if (proxyOptions_ != nullptr) {
116 err += Socket::SOCKET_ERROR_CODE_BASE;
117 }
118 return err;
119 }
120
ReadTLSProxyOptions(napi_env env,napi_value * params)121 std::shared_ptr<Socket::ProxyOptions> TLSConnectContext::ReadTLSProxyOptions(napi_env env, napi_value *params)
122 {
123 if (NapiUtils::HasNamedProperty(GetEnv(), params[0], KEY_PROXY)) {
124 NETSTACK_LOGD("handle proxy options");
125 auto opts = std::make_shared<Socket::ProxyOptions>();
126 if (opts->ParseOptions(GetEnv(), params[0]) != 0) {
127 NETSTACK_LOGE("parse proxy options failed");
128 return nullptr;
129 }
130 if (opts->type_ != Socket::ProxyType::NONE) {
131 proxyOptions_ = opts;
132 }
133 }
134 return proxyOptions_;
135 }
136
CheckParamsType(napi_value * params,size_t paramsCount)137 bool TLSConnectContext::CheckParamsType(napi_value *params, size_t paramsCount)
138 {
139 if (paramsCount == PARAM_JUST_OPTIONS) {
140 if (NapiUtils::GetValueType(GetEnv(), params[ARG_INDEX_0]) != napi_object) {
141 NETSTACK_LOGE("tlsConnectContext first param is not object");
142 SetNeedThrowException(true);
143 SetError(PARSE_ERROR_CODE, PARSE_ERROR.data());
144 return false;
145 }
146 return true;
147 }
148
149 if (paramsCount == PARAM_OPTIONS_AND_CALLBACK) {
150 if (NapiUtils::GetValueType(GetEnv(), params[ARG_INDEX_0]) != napi_object) {
151 NETSTACK_LOGE("tls ConnectContext first param is not object");
152 SetNeedThrowException(true);
153 SetError(PARSE_ERROR_CODE, PARSE_ERROR.data());
154 return false;
155 }
156 if (NapiUtils::GetValueType(GetEnv(), params[ARG_INDEX_1]) != napi_function) {
157 NETSTACK_LOGE("tls ConnectContext second param is not function");
158 return false;
159 }
160 return true;
161 }
162 return false;
163 }
164
ReadTLSConnectOptions(napi_env env,napi_value * params)165 TLSConnectOptions TLSConnectContext::ReadTLSConnectOptions(napi_env env, napi_value *params)
166 {
167 TLSConnectOptions options;
168 Socket::NetAddress address = ReadNetAddress(GetEnv(), params);
169 TLSSecureOptions secureOption = ReadTLSSecureOptions(GetEnv(), params);
170 options.SetHostName(address.GetAddress());
171 options.SetNetAddress(address);
172 options.SetTlsSecureOptions(secureOption);
173 options.proxyOptions_ = ReadTLSProxyOptions(GetEnv(), params);
174 if (NapiUtils::HasNamedProperty(GetEnv(), params[0], ALPN_PROTOCOLS)) {
175 napi_value alpnProtocols = NapiUtils::GetNamedProperty(GetEnv(), params[0], ALPN_PROTOCOLS);
176 uint32_t arrayLength = NapiUtils::GetArrayLength(GetEnv(), alpnProtocols);
177 arrayLength = arrayLength > PROTOCOLS_SIZE ? PROTOCOLS_SIZE : arrayLength;
178 napi_value elementValue = nullptr;
179 std::vector<std::string> alpnProtocolVec;
180 for (uint32_t i = 0; i < arrayLength; i++) {
181 elementValue = NapiUtils::GetArrayElement(GetEnv(), alpnProtocols, i);
182 std::string alpnProtocol = NapiUtils::GetStringFromValueUtf8(GetEnv(), elementValue);
183 alpnProtocolVec.push_back(alpnProtocol);
184 }
185 options.SetAlpnProtocols(alpnProtocolVec);
186 }
187
188 if (NapiUtils::HasNamedProperty(GetEnv(), params[0], SKIP_REMOTE_VALIDATION)) {
189 bool whetherToSkip = NapiUtils::GetBooleanProperty(GetEnv(), params[0], SKIP_REMOTE_VALIDATION);
190 options.SetSkipRemoteValidation(whetherToSkip);
191 }
192
193 return options;
194 }
195
ReadTLSSecureOptions(napi_env env,napi_value * params)196 TLSSecureOptions TLSConnectContext::ReadTLSSecureOptions(napi_env env, napi_value *params)
197 {
198 TLSSecureOptions secureOption;
199
200 if (!NapiUtils::HasNamedProperty(GetEnv(), params[ARG_INDEX_0], SECURE_OPTIONS)) {
201 return secureOption;
202 }
203 napi_value secureOptions = NapiUtils::GetNamedProperty(GetEnv(), params[ARG_INDEX_0], SECURE_OPTIONS);
204 if (!ReadNecessaryOptions(env, secureOptions, secureOption)) {
205 return secureOption;
206 }
207
208 if (NapiUtils::HasNamedProperty(GetEnv(), secureOptions, PASSWD_NAME)) {
209 secureOption.SetKeyPass(SecureData(NapiUtils::GetStringPropertyUtf8(env, secureOptions, PASSWD_NAME)));
210 }
211
212 if (NapiUtils::HasNamedProperty(GetEnv(), secureOptions, PROTOCOLS_NAME)) {
213 napi_value protocolValue = NapiUtils::GetNamedProperty(env, secureOptions, PROTOCOLS_NAME);
214 std::vector<std::string> protocolVec;
215 if (NapiUtils::GetValueType(env, protocolValue) == napi_string) {
216 std::string protocolStr = NapiUtils::GetStringFromValueUtf8(env, protocolValue);
217 protocolVec.push_back(std::move(protocolStr));
218 } else if (NapiUtils::IsArray(env, protocolValue)) {
219 uint32_t num = NapiUtils::GetArrayLength(GetEnv(), protocolValue);
220 num = num > PROTOCOLS_SIZE ? PROTOCOLS_SIZE : num;
221 protocolVec.reserve(num);
222 napi_value element = nullptr;
223 for (uint32_t i = 0; i < num; i++) {
224 element = NapiUtils::GetArrayElement(GetEnv(), protocolValue, i);
225 std::string protocol = NapiUtils::GetStringFromValueUtf8(GetEnv(), element);
226 protocolVec.push_back(std::move(protocol));
227 }
228 }
229 secureOption.SetProtocolChain(protocolVec);
230 }
231
232 if (NapiUtils::HasNamedProperty(GetEnv(), secureOptions, SIGNATURE_ALGORITHMS)) {
233 std::string signatureAlgorithms = NapiUtils::GetStringPropertyUtf8(env, secureOptions, SIGNATURE_ALGORITHMS);
234 secureOption.SetSignatureAlgorithms(signatureAlgorithms);
235 }
236
237 if (NapiUtils::HasNamedProperty(GetEnv(), secureOptions, USE_REMOTE_CIPHER_PREFER)) {
238 bool useRemoteCipherPrefer = NapiUtils::GetBooleanProperty(env, secureOptions, USE_REMOTE_CIPHER_PREFER);
239 secureOption.SetUseRemoteCipherPrefer(useRemoteCipherPrefer);
240 }
241
242 if (NapiUtils::HasNamedProperty(GetEnv(), secureOptions, CIPHER_SUITE)) {
243 std::string cipherSuite = NapiUtils::GetStringPropertyUtf8(env, secureOptions, CIPHER_SUITE);
244 secureOption.SetCipherSuite(cipherSuite);
245 }
246
247 return secureOption;
248 }
249
ReadNetAddress(napi_env env,napi_value * params)250 Socket::NetAddress TLSConnectContext::ReadNetAddress(napi_env env, napi_value *params)
251 {
252 Socket::NetAddress address;
253 napi_value netAddress = NapiUtils::GetNamedProperty(GetEnv(), params[0], ADDRESS_NAME);
254 if (NapiUtils::HasNamedProperty(GetEnv(), netAddress, FAMILY_NAME)) {
255 uint32_t family = NapiUtils::GetUint32Property(GetEnv(), netAddress, FAMILY_NAME);
256 address.SetFamilyByJsValue(family);
257 }
258 if (NapiUtils::HasNamedProperty(GetEnv(), netAddress, ADDRESS_NAME)) {
259 std::string addr = NapiUtils::GetStringPropertyUtf8(GetEnv(), netAddress, ADDRESS_NAME);
260 address.SetRawAddress(addr);
261 }
262 if (NapiUtils::HasNamedProperty(GetEnv(), netAddress, PORT_NAME)) {
263 uint16_t port = static_cast<uint16_t>(NapiUtils::GetUint32Property(GetEnv(), netAddress, PORT_NAME));
264 address.SetPort(port);
265 }
266 return address;
267 }
268 } // namespace TlsSocket
269 } // namespace NetStack
270 } // namespace OHOS
271