1 /*
2 * Copyright (c) 2022 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 = "bidirectionAuthentication";
45 constexpr uint32_t CA_CHAIN_LENGTH = 10;
46 constexpr uint32_t PROTOCOLS_SIZE = 10;
47 constexpr std::string_view PARSE_ERROR = "options is not type of TLSConnectOptions";
48
ReadNecessaryOptions(napi_env env,napi_value secureOptions,TLSSecureOptions & secureOption)49 bool ReadNecessaryOptions(napi_env env, napi_value secureOptions, TLSSecureOptions &secureOption)
50 {
51 if (!NapiUtils::HasNamedProperty(env, secureOptions, CA_NAME)) {
52 return false;
53 }
54 napi_value caCert = NapiUtils::GetNamedProperty(env, secureOptions, CA_NAME);
55 std::vector<std::string> caVec;
56 if (NapiUtils::GetValueType(env, caCert) == napi_string) {
57 std::string ca = NapiUtils::GetStringPropertyUtf8(env, secureOptions, CA_NAME);
58 caVec.push_back(ca);
59 }
60 if (NapiUtils::GetValueType(env, caCert) == napi_object) {
61 uint32_t arrayLong = NapiUtils::GetArrayLength(env, caCert);
62 if (arrayLong > CA_CHAIN_LENGTH) {
63 return false;
64 }
65 napi_value element = nullptr;
66 for (uint32_t i = 0; i < arrayLong; i++) {
67 element = NapiUtils::GetArrayElement(env, caCert, i);
68 std::string ca = NapiUtils::GetStringFromValueUtf8(env, element);
69 caVec.push_back(ca);
70 }
71 }
72 secureOption.SetCaChain(caVec);
73
74 if (NapiUtils::HasNamedProperty(env, secureOptions, KEY_NAME)) {
75 secureOption.SetKey(SecureData(NapiUtils::GetStringPropertyUtf8(env, secureOptions, KEY_NAME)));
76 }
77 if (NapiUtils::HasNamedProperty(env, secureOptions, CERT_NAME)) {
78 secureOption.SetCert(NapiUtils::GetStringPropertyUtf8(env, secureOptions, CERT_NAME));
79 }
80 if (NapiUtils::HasNamedProperty(env, secureOptions, VERIFY_MODE_NAME)) {
81 VerifyMode tempVerifyMode = VerifyMode::ONE_WAY_MODE;
82 NapiUtils::GetBooleanProperty(env, secureOptions, VERIFY_MODE_NAME) == false
83 ? tempVerifyMode = VerifyMode::ONE_WAY_MODE
84 : tempVerifyMode = 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.SetNetAddress(address);
143 options.SetTlsSecureOptions(secureOption);
144 if (NapiUtils::HasNamedProperty(GetEnv(), params[0], ALPN_PROTOCOLS)) {
145 napi_value alpnProtocols = NapiUtils::GetNamedProperty(GetEnv(), params[0], ALPN_PROTOCOLS);
146 uint32_t arrayLength = NapiUtils::GetArrayLength(GetEnv(), alpnProtocols);
147 arrayLength = arrayLength > PROTOCOLS_SIZE ? PROTOCOLS_SIZE : arrayLength;
148 napi_value elementValue = nullptr;
149 std::vector<std::string> alpnProtocolVec;
150 for (uint32_t i = 0; i < arrayLength; i++) {
151 elementValue = NapiUtils::GetArrayElement(GetEnv(), alpnProtocols, i);
152 std::string alpnProtocol = NapiUtils::GetStringFromValueUtf8(GetEnv(), elementValue);
153 alpnProtocolVec.push_back(alpnProtocol);
154 }
155 options.SetAlpnProtocols(alpnProtocolVec);
156 }
157 return options;
158 }
159
ReadTLSSecureOptions(napi_env env,napi_value * params)160 TLSSecureOptions TLSConnectContext::ReadTLSSecureOptions(napi_env env, napi_value *params)
161 {
162 TLSSecureOptions secureOption;
163
164 if (!NapiUtils::HasNamedProperty(GetEnv(), params[ARG_INDEX_0], SECURE_OPTIONS)) {
165 return secureOption;
166 }
167 napi_value secureOptions = NapiUtils::GetNamedProperty(GetEnv(), params[ARG_INDEX_0], SECURE_OPTIONS);
168 if (!ReadNecessaryOptions(env, secureOptions, secureOption)) {
169 return secureOption;
170 }
171
172 if (NapiUtils::HasNamedProperty(GetEnv(), secureOptions, PASSWD_NAME)) {
173 secureOption.SetKeyPass(SecureData(NapiUtils::GetStringPropertyUtf8(env, secureOptions, PASSWD_NAME)));
174 }
175
176 if (NapiUtils::HasNamedProperty(GetEnv(), secureOptions, PROTOCOLS_NAME)) {
177 napi_value protocolVector = NapiUtils::GetNamedProperty(env, secureOptions, PROTOCOLS_NAME);
178 uint32_t num = NapiUtils::GetArrayLength(GetEnv(), protocolVector);
179 num = num > PROTOCOLS_SIZE ? PROTOCOLS_SIZE : num;
180 napi_value element = nullptr;
181 std::vector<std::string> protocolVec;
182 for (uint32_t i = 0; i < num; i++) {
183 element = NapiUtils::GetArrayElement(GetEnv(), protocolVector, i);
184 std::string protocol = NapiUtils::GetStringFromValueUtf8(GetEnv(), element);
185 protocolVec.push_back(protocol);
186 }
187 secureOption.SetProtocolChain(protocolVec);
188 }
189
190 if (NapiUtils::HasNamedProperty(GetEnv(), secureOptions, SIGNATURE_ALGORITHMS)) {
191 std::string signatureAlgorithms = NapiUtils::GetStringPropertyUtf8(env, secureOptions, SIGNATURE_ALGORITHMS);
192 secureOption.SetSignatureAlgorithms(signatureAlgorithms);
193 }
194
195 if (NapiUtils::HasNamedProperty(GetEnv(), secureOptions, USE_REMOTE_CIPHER_PREFER)) {
196 bool useRemoteCipherPrefer = NapiUtils::GetBooleanProperty(env, secureOptions, USE_REMOTE_CIPHER_PREFER);
197 secureOption.SetUseRemoteCipherPrefer(useRemoteCipherPrefer);
198 }
199
200 if (NapiUtils::HasNamedProperty(GetEnv(), secureOptions, CIPHER_SUITE)) {
201 std::string cipherSuite = NapiUtils::GetStringPropertyUtf8(env, secureOptions, CIPHER_SUITE);
202 secureOption.SetCipherSuite(cipherSuite);
203 }
204
205 return secureOption;
206 }
207
ReadNetAddress(napi_env env,napi_value * params)208 Socket::NetAddress TLSConnectContext::ReadNetAddress(napi_env env, napi_value *params)
209 {
210 Socket::NetAddress address;
211 napi_value netAddress = NapiUtils::GetNamedProperty(GetEnv(), params[0], ADDRESS_NAME);
212
213 std::string addr = NapiUtils::GetStringPropertyUtf8(GetEnv(), netAddress, ADDRESS_NAME);
214
215 if (NapiUtils::HasNamedProperty(GetEnv(), params[0], FAMILY_NAME)) {
216 uint32_t family = NapiUtils::GetUint32Property(GetEnv(), params[0], FAMILY_NAME);
217 address.SetFamilyByJsValue(family);
218 }
219 address.SetAddress(addr);
220
221 if (NapiUtils::HasNamedProperty(GetEnv(), netAddress, PORT_NAME)) {
222 uint16_t port = static_cast<uint16_t>(NapiUtils::GetUint32Property(GetEnv(), netAddress, PORT_NAME));
223 address.SetPort(port);
224 }
225 return address;
226 }
227 } // namespace TlsSocket
228 } // namespace NetStack
229 } // namespace OHOS
230