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