• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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