!1737 证书需求

Merge pull request !1737 from liuleimin_hw/master
This commit is contained in:
openharmony_ci 2025-01-24 02:01:17 +00:00 committed by Gitee
commit b6aa842ee7
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
19 changed files with 633 additions and 10 deletions

View File

@ -103,6 +103,7 @@ ohos_shared_library("http") {
"cache/lru_cache/src/lru_cache_disk_handler.cpp",
"constant/src/constant.cpp",
"http_exec/src/http_exec.cpp",
"http_exec/src/http_tls_config.cpp",
"http_module/src/http_module.cpp",
"options/src/http_request_options.cpp",
"options/src/http_response.cpp",

View File

@ -104,6 +104,12 @@ public:
void ParseClientCert(napi_value optionsValue);
void ParseRemoteValidationMode(napi_value optionsValue);
void ParseTlsOption(napi_value optionsValue);
void ParseServerAuthentication(napi_value optionsValue);
void CachePerformanceTimingItem(const std::string &key, double value);
void StopAndCacheNapiPerformanceTiming(const char *key);

View File

@ -24,6 +24,7 @@
#include "constant.h"
#include "http_exec.h"
#include "http_tls_config.h"
#include "napi_utils.h"
#include "netstack_common_utils.h"
#include "netstack_log.h"
@ -234,6 +235,97 @@ void RequestContext::ParseNumberOptions(napi_value optionsValue)
}
}
void RequestContext::ParseRemoteValidationMode(napi_value optionsValue)
{
if (!NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_REMOTE_VALIDATION)) {
NETSTACK_LOGD("no remote validation mode config");
return;
}
napi_value value = NapiUtils::GetNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_REMOTE_VALIDATION);
if (NapiUtils::GetValueType(GetEnv(), value) == napi_string) {
auto remoteValidationMode = NapiUtils::GetStringFromValueUtf8(GetEnv(), value);
if (remoteValidationMode == "skip") {
NETSTACK_LOGI("ParseRemoteValidationMode remoteValidationMode skip");
options.SetCanSkipCertVerifyFlag(true);
} else if (remoteValidationMode != "system") {
NETSTACK_LOGE("RemoteValidationMode config error");
}
}
}
void RequestContext::ParseTlsOption(napi_value optionsValue)
{
if (!NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_TLS_OPTION)) {
NETSTACK_LOGD("no tls config");
return;
}
napi_value tlsVersionValue = NapiUtils::GetNamedProperty(
GetEnv(), optionsValue, HttpConstant::PARAM_KEY_TLS_OPTION);
napi_valuetype type = NapiUtils::GetValueType(GetEnv(), tlsVersionValue);
if (type != napi_object && type != napi_string) {
NETSTACK_LOGE("tlsVersionValue type error");
return;
}
uint32_t tlsVersionMin = NapiUtils::GetUint32Property(GetEnv(), tlsVersionValue, "tlsVersionMin");
uint32_t tlsVersionMax = NapiUtils::GetUint32Property(GetEnv(), tlsVersionValue, "tlsVersionMax");
NETSTACK_LOGD("tlsVersionMin = %{public}d, tlsVersionMax = %{public}d", tlsVersionMin, tlsVersionMax);
TlsOption tlsOption;
tlsOption.tlsVersionMin = static_cast<TlsVersion>(tlsVersionMin);
tlsOption.tlsVersionMax = static_cast<TlsVersion>(tlsVersionMax);
if (!NapiUtils::HasNamedProperty(GetEnv(), tlsVersionValue, "cipherSuites")) {
NETSTACK_LOGD("no cipherSuites");
options.SetTlsOption(tlsOption);
return;
}
auto cipherSuiteNapi = NapiUtils::GetNamedProperty(GetEnv(), tlsVersionValue, "cipherSuites");
if (!NapiUtils::IsArray(GetEnv(), cipherSuiteNapi)) {
options.SetTlsOption(tlsOption);
return;
}
auto length = NapiUtils::GetArrayLength(GetEnv(), cipherSuiteNapi);
for (uint32_t i = 0; i < length; ++i) {
auto standardNameNapi = NapiUtils::GetArrayElement(GetEnv(), cipherSuiteNapi, i);
auto cipherSuite = GetTlsCipherSuiteFromStandardName(
NapiUtils::GetStringFromValueUtf8(GetEnv(), standardNameNapi));
if (cipherSuite != CipherSuite::INVALID) {
tlsOption.cipherSuite.emplace(cipherSuite);
}
}
options.SetTlsOption(tlsOption);
}
void RequestContext::ParseServerAuthentication(napi_value optionsValue)
{
if (!NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_SERVER_AUTH)) {
NETSTACK_LOGD("no server authentication config");
return;
}
napi_value serverAuthenticationValue = NapiUtils::GetNamedProperty(
GetEnv(), optionsValue, HttpConstant::PARAM_KEY_SERVER_AUTH);
napi_valuetype type = NapiUtils::GetValueType(GetEnv(), serverAuthenticationValue);
if (type != napi_object) {
NETSTACK_LOGE("server authentication type error");
return;
}
ServerAuthentication serverAuthentication;
auto credentialNapi = NapiUtils::GetNamedProperty(GetEnv(), serverAuthenticationValue, "credential");
NapiUtils::GetSecureDataPropertyUtf8(GetEnv(),
credentialNapi, "username", serverAuthentication.credential.username);
NapiUtils::GetSecureDataPropertyUtf8(GetEnv(),
credentialNapi, "password", serverAuthentication.credential.password);
auto authenticationType = NapiUtils::GetStringPropertyUtf8(GetEnv(),
serverAuthenticationValue, "authenticationType");
if (authenticationType == "basic") {
serverAuthentication.authenticationType = AuthenticationType::BASIC;
} else if (authenticationType == "ntlm") {
serverAuthentication.authenticationType = AuthenticationType::NTLM;
} else if (authenticationType == "digest") {
serverAuthentication.authenticationType = AuthenticationType::DIGEST;
}
options.SetServerAuthentication(serverAuthentication);
}
void RequestContext::ParseHeader(napi_value optionsValue)
{
if (!NapiUtils::HasNamedProperty(GetEnv(), optionsValue, HttpConstant::PARAM_KEY_HEADER)) {
@ -449,6 +541,9 @@ void RequestContext::UrlAndOptions(napi_value urlValue, napi_value optionsValue)
ParseDnsServers(optionsValue);
ParseMultiFormData(optionsValue);
ParseCertificatePinning(optionsValue);
ParseRemoteValidationMode(optionsValue);
ParseTlsOption(optionsValue);
ParseServerAuthentication(optionsValue);
SetParseOK(true);
}

View File

@ -156,6 +156,9 @@ public:
static const char *const PARAM_KEY_CLIENT_CERT;
static const char *const PARAM_KEY_MULTI_FORM_DATA_LIST;
static const char *const PARAM_KEY_CERTIFICATE_PINNING;
static const char *const PARAM_KEY_REMOTE_VALIDATION;
static const char *const PARAM_KEY_TLS_OPTION;
static const char *const PARAM_KEY_SERVER_AUTH;
static const char *const HTTP_PROXY_KEY_HOST;
static const char *const HTTP_PROXY_KEY_PORT;
@ -174,6 +177,11 @@ public:
static const char *const HTTP_CERT_TYPE_DER;
static const char *const HTTP_CERT_TYPE_P12;
static const char *const TLS_VERSION_1_0;
static const char *const TLS_VERSION_1_1;
static const char *const TLS_VERSION_1_2;
static const char *const TLS_VERSION_1_3;
static const char *const HTTP_MULTI_FORM_DATA_NAME;
static const char *const HTTP_MULTI_FORM_DATA_CONTENT_TYPE;
static const char *const HTTP_MULTI_FORM_DATA_REMOTE_FILE_NAME;

View File

@ -54,6 +54,10 @@ const char *const HttpConstant::PARAM_KEY_MULTI_FORM_DATA_LIST = "multiFormDataL
const char *const HttpConstant::PARAM_KEY_CERTIFICATE_PINNING = "certificatePinning";
const char *const HttpConstant::PARAM_KEY_REMOTE_VALIDATION = "remoteValidation";
const char *const HttpConstant::PARAM_KEY_TLS_OPTION = "tlsOptions";
const char *const HttpConstant::PARAM_KEY_SERVER_AUTH = "serverAuthentication";
const char *const HttpConstant::HTTP_PROXY_KEY_HOST = "host";
const char *const HttpConstant::HTTP_PROXY_KEY_PORT = "port";
const char *const HttpConstant::HTTP_PROXY_KEY_EXCLUSION_LIST = "exclusionList";
@ -70,6 +74,11 @@ const char *const HttpConstant::HTTP_CERT_TYPE_PEM = "PEM";
const char *const HttpConstant::HTTP_CERT_TYPE_DER = "DER";
const char *const HttpConstant::HTTP_CERT_TYPE_P12 = "P12";
const char *const HttpConstant::TLS_VERSION_1_0 = "TLS_V_1_0";
const char *const HttpConstant::TLS_VERSION_1_1 = "TLS_V_1_1";
const char *const HttpConstant::TLS_VERSION_1_2 = "TLS_V_1_2";
const char *const HttpConstant::TLS_VERSION_1_3 = "TLS_V_1_3";
const char *const HttpConstant::HTTP_PROXY_EXCLUSIONS_SEPARATOR = ",";
const char *const HttpConstant::RESPONSE_KEY_RESULT = "result";

View File

@ -92,6 +92,8 @@ private:
static bool SetOtherOption(CURL *curl, RequestContext *context);
static bool SetAuthOptions(CURL *curl, OHOS::NetStack::Http::RequestContext *context);
static bool SetRequestOption(void *curl, RequestContext *context);
static bool SetSSLCertOption(CURL *curl, RequestContext *context);
@ -158,6 +160,8 @@ private:
static void SetFormDataOption(MultiFormData &multiFormData, curl_mimepart *part,
void *curl, RequestContext *context);
static bool IsBuiltWithOpenSSL();
#if !HAS_NETMANAGER_BASE
static void AddRequestInfo();
#endif

View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef NETSTACK_HTTP_TLS_CONFIG_H
#define NETSTACK_HTTP_TLS_CONFIG_H
#include <functional>
#include <map>
#include <string>
#include <vector>
#include <optional>
#include <memory>
#include <unordered_set>
#include "securec.h"
namespace OHOS::NetStack::Http {
enum class CipherSuite {
INVALID = -1,
TLS_AES_128_GCM_SHA256 = 0x1301,
TLS_AES_256_GCM_SHA384 = 0x1302,
TLS_CHACHA20_POLY1305_SHA256 = 0x1303,
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = 0xc02b,
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = 0xc02f,
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = 0xc02c,
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = 0xc030,
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = 0xcca9,
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 0xcca8,
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = 0x009c,
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = 0x009d,
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = 0xc009,
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = 0xc013,
TLS_RSA_WITH_AES_128_GCM_SHA256 = 0xc00a,
TLS_RSA_WITH_AES_256_GCM_SHA384 = 0xc014,
TLS_RSA_WITH_AES_128_CBC_SHA = 0x002f,
TLS_RSA_WITH_AES_256_CBC_SHA = 0x0035,
TLS_RSA_WITH_3DES_EDE_CBC_SHA = 0x000a,
};
enum class TlsVersion {
DEFAULT = 0,
TLSv1_0 = 4,
TLSv1_1 = 5,
TLSv1_2 = 6,
TLSv1_3 = 7,
};
struct TlsCipherString {
std::string ciperSuiteString;
std::string tlsV13CiperSuiteString;
};
[[nodiscard]] CipherSuite GetTlsCipherSuiteFromStandardName(const std::string &standardName);
[[nodiscard]] std::string GetInnerNameFromCipherSuite(CipherSuite cipherSuite);
[[nodiscard]] TlsCipherString ConvertCipherSuiteToCipherString(const std::unordered_set<CipherSuite> &cipherSuite);
} // namespace OHOS::NetStack::Http
#endif // NETSTACK_HTTP_TLS_CONFIG_H

View File

@ -891,6 +891,49 @@ bool HttpExec::Initialize()
}
#endif
bool HttpExec::IsBuiltWithOpenSSL()
{
const auto data = curl_version_info(CURLVERSION_NOW);
if (!data || !data->ssl_version) {
return false;
}
const auto sslVersion = CommonUtils::ToLower(data->ssl_version);
return sslVersion.find("openssl") != std::string::npos;
}
unsigned long GetTlsVersion(TlsVersion tlsVersionMin, TlsVersion tlsVersionMax)
{
unsigned long tlsVersion = CURL_SSLVERSION_DEFAULT;
if (tlsVersionMin == TlsVersion::DEFAULT || tlsVersionMax == TlsVersion::DEFAULT) {
return tlsVersion;
}
if (tlsVersionMin > tlsVersionMax) {
return tlsVersion;
}
if (tlsVersionMin == TlsVersion::TLSv1_0) {
tlsVersion |= static_cast<unsigned long>(CURL_SSLVERSION_TLSv1_0);
} else if (tlsVersionMin == TlsVersion::TLSv1_1) {
tlsVersion |= static_cast<unsigned long>(CURL_SSLVERSION_TLSv1_1);
} else if (tlsVersionMin == TlsVersion::TLSv1_2) {
tlsVersion |= static_cast<unsigned long>(CURL_SSLVERSION_TLSv1_2);
} else if (tlsVersionMin == TlsVersion::TLSv1_3) {
tlsVersion |= static_cast<unsigned long>(CURL_SSLVERSION_TLSv1_3);
}
if (tlsVersionMax == TlsVersion::TLSv1_0) {
tlsVersion |= static_cast<unsigned long>(CURL_SSLVERSION_MAX_TLSv1_0);
} else if (tlsVersionMax == TlsVersion::TLSv1_1) {
tlsVersion |= static_cast<unsigned long>(CURL_SSLVERSION_MAX_TLSv1_1);
} else if (tlsVersionMax == TlsVersion::TLSv1_2) {
tlsVersion |= static_cast<unsigned long>(CURL_SSLVERSION_MAX_TLSv1_2);
} else if (tlsVersionMax == TlsVersion::TLSv1_3) {
tlsVersion |= static_cast<unsigned long>(CURL_SSLVERSION_MAX_TLSv1_3);
}
return tlsVersion;
}
bool HttpExec::SetOtherOption(CURL *curl, OHOS::NetStack::Http::RequestContext *context)
{
std::string url = context->options.GetUrl();
@ -905,8 +948,29 @@ bool HttpExec::SetOtherOption(CURL *curl, OHOS::NetStack::Http::RequestContext *
auto proxyType = (host.find("https://") != std::string::npos) ? CURLPROXY_HTTPS : CURLPROXY_HTTP;
NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_PROXYTYPE, proxyType, context);
}
NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2, context);
NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_SSL_CIPHER_LIST, TLS12_SECURITY_CIPHER_SUITE, context);
const auto &tlsOption = context->options.GetTlsOption();
unsigned long tlsVersion = GetTlsVersion(tlsOption.tlsVersionMin, tlsOption.tlsVersionMax);
NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_SSLVERSION, static_cast<long>(tlsVersion), context);
const auto &cipherSuite = tlsOption.cipherSuite;
const auto &cipherSuiteString = ConvertCipherSuiteToCipherString(cipherSuite);
const auto &normalString = cipherSuiteString.ciperSuiteString;
const auto &tlsV13String = cipherSuiteString.tlsV13CiperSuiteString;
if (tlsVersion == CURL_SSLVERSION_DEFAULT) {
NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2, context);
NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_SSL_CIPHER_LIST, TLS12_SECURITY_CIPHER_SUITE, context);
} else if (normalString.empty() && tlsV13String.empty()) {
NETSTACK_LOGD("no cipherSuite config");
} else if (!normalString.empty()) {
NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_SSL_CIPHER_LIST, normalString.c_str(), context);
if (!tlsV13String.empty() && IsBuiltWithOpenSSL()) {
NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_TLS13_CIPHERS, tlsV13String.c_str(), context);
}
} else if (!tlsV13String.empty() && IsBuiltWithOpenSSL()) {
NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_TLS13_CIPHERS, tlsV13String.c_str(), context);
} else {
NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2, context);
NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_SSL_CIPHER_LIST, TLS12_SECURITY_CIPHER_SUITE, context);
}
#ifdef NETSTACK_PROXY_PASS
NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_PROXYUSERPWD, NETSTACK_PROXY_PASS, context);
@ -922,6 +986,37 @@ bool HttpExec::SetOtherOption(CURL *curl, OHOS::NetStack::Http::RequestContext *
return true;
}
bool HttpExec::SetAuthOptions(CURL *curl, OHOS::NetStack::Http::RequestContext *context)
{
long authType = CURLAUTH_ANY;
auto authentication = context->options.GetServerAuthentication();;
switch (authentication.authenticationType) {
case AuthenticationType::BASIC:
authType = CURLAUTH_BASIC;
break;
case AuthenticationType::NTLM:
authType = CURLAUTH_NTLM;
break;
case AuthenticationType::DIGEST:
authType = CURLAUTH_DIGEST;
break;
case AuthenticationType::AUTO:
default:
break;
}
auto username = authentication.credential.username;
auto password = authentication.credential.password;
if (!username.empty()) {
NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_HTTPAUTH, authType, context);
NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_USERNAME, username.c_str(), context);
}
if (!password.empty()) {
NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_PASSWORD, password.c_str(), context);
}
return true;
}
bool HttpExec::SetSSLCertOption(CURL *curl, OHOS::NetStack::Http::RequestContext *context)
{
std::string cert;
@ -1092,13 +1187,18 @@ bool HttpExec::SetServerSSLCertOption(CURL *curl, OHOS::NetStack::Http::RequestC
NETSTACK_LOGE("GetTrustAnchorsForHostName error. ret [%{public}d]", ret);
}
#ifdef HTTP_MULTIPATH_CERT_ENABLE
// add user cert path
TrustUser0AndUserCa(certs);
// add system cert path
certs.emplace_back(HttpConstant::HTTP_PREPARE_CA_PATH);
context->SetCertsPath(std::move(certs), context->options.GetCaPath());
NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_SSL_VERIFYPEER, 1L, context);
NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_SSL_VERIFYHOST, 2L, context);
if (context->options.GetCanSkipCertVerifyFlag()) {
NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_SSL_VERIFYPEER, 0L, context);
NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_SSL_VERIFYHOST, 0L, context);
} else {
// add user cert path
TrustUser0AndUserCa(certs);
// add system cert path
certs.emplace_back(HttpConstant::HTTP_PREPARE_CA_PATH);
context->SetCertsPath(std::move(certs), context->options.GetCaPath());
NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_SSL_VERIFYPEER, 1L, context);
NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_SSL_VERIFYHOST, 2L, context);
}
NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_CAINFO, nullptr, context);
#else
NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_CAINFO, nullptr, context);
@ -1325,6 +1425,10 @@ bool HttpExec::SetOption(CURL *curl, RequestContext *context, struct curl_slist
if (!SetOtherOption(curl, context)) {
return false;
}
if (!SetAuthOptions(curl, context)) {
return false;
}
return true;
}

View File

@ -0,0 +1,167 @@
/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "http_tls_config.h"
namespace OHOS::NetStack::Http {
struct CipherSuiteConvertor {
CipherSuite cipherSuite = CipherSuite::INVALID;
const char *innerName = nullptr;
const char *standardName = nullptr;
};
static constexpr const CipherSuiteConvertor CIPHER_SUITE_CONVERTOR[] = {
{
.cipherSuite = CipherSuite::TLS_AES_128_GCM_SHA256,
.innerName = "TLS_AES_128_GCM_SHA256",
.standardName = "TLS_AES_128_GCM_SHA256",
},
{
.cipherSuite = CipherSuite::TLS_AES_256_GCM_SHA384,
.innerName = "TLS_AES_256_GCM_SHA384",
.standardName = "TLS_AES_256_GCM_SHA384",
},
{
.cipherSuite = CipherSuite::TLS_CHACHA20_POLY1305_SHA256,
.innerName = "TLS_CHACHA20_POLY1305_SHA256",
.standardName = "TLS_CHACHA20_POLY1305_SHA256",
},
{
.cipherSuite = CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
.innerName = "ECDHE-ECDSA-AES128-GCM-SHA256",
.standardName = "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
},
{
.cipherSuite = CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
.innerName = "ECDHE-RSA-AES128-GCM-SHA256",
.standardName = "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
},
{
.cipherSuite = CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
.innerName = "ECDHE-ECDSA-AES256-GCM-SHA384",
.standardName = "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
},
{
.cipherSuite = CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
.innerName = "ECDHE-RSA-AES256-GCM-SHA384",
.standardName = "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
},
{
.cipherSuite = CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
.innerName = "ECDHE-ECDSA-CHACHA20-POLY1305",
.standardName = "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
},
{
.cipherSuite = CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
.innerName = "ECDHE-RSA-CHACHA20-POLY1305",
.standardName = "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
},
{
.cipherSuite = CipherSuite::TLS_RSA_WITH_AES_128_GCM_SHA256,
.innerName = "AES128-GCM-SHA256",
.standardName = "TLS_RSA_WITH_AES_128_GCM_SHA256",
},
{
.cipherSuite = CipherSuite::TLS_RSA_WITH_AES_256_GCM_SHA384,
.innerName = "AES256-GCM-SHA384",
.standardName = "TLS_RSA_WITH_AES_256_GCM_SHA384",
},
{
.cipherSuite = CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
.innerName = "ECDHE-ECDSA-AES128-SHA",
.standardName = "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
},
{
.cipherSuite = CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
.innerName = "ECDHE-RSA-AES128-SHA",
.standardName = "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
},
{
.cipherSuite = CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
.innerName = "ECDHE-ECDSA-AES256-SHA",
.standardName = "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
},
{
.cipherSuite = CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
.innerName = "ECDHE-RSA-AES256-SHA",
.standardName = "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
},
{
.cipherSuite = CipherSuite::TLS_RSA_WITH_AES_128_CBC_SHA,
.innerName = "AES128-SHA",
.standardName = "TLS_RSA_WITH_AES_128_CBC_SHA",
},
{
.cipherSuite = CipherSuite::TLS_RSA_WITH_AES_256_CBC_SHA,
.innerName = "AES256-SHA",
.standardName = "TLS_RSA_WITH_AES_256_CBC_SHA",
},
{
.cipherSuite = CipherSuite::TLS_RSA_WITH_3DES_EDE_CBC_SHA,
.innerName = "DES-CBC3-SHA",
.standardName = "TLS_RSA_WITH_3DES_EDE_CBC_SHA",
},
};
CipherSuite GetTlsCipherSuiteFromStandardName(const std::string &standardName)
{
for (const auto &suite : CIPHER_SUITE_CONVERTOR) {
if (suite.standardName == standardName) {
return suite.cipherSuite;
}
}
return CipherSuite::INVALID;
}
std::string GetInnerNameFromCipherSuite(CipherSuite cipherSuite)
{
for (const auto &suite : CIPHER_SUITE_CONVERTOR) {
if (suite.cipherSuite == cipherSuite) {
return suite.innerName;
}
}
return {};
}
static bool IsTlsV13Cipher(const std::string &innerName)
{
return innerName == "TLS_AES_128_GCM_SHA256" || innerName == "TLS_AES_256_GCM_SHA384" ||
innerName == "TLS_CHACHA20_POLY1305_SHA256";
}
TlsCipherString ConvertCipherSuiteToCipherString(const std::unordered_set<CipherSuite> &cipherSuite)
{
TlsCipherString cipherString;
for (const auto &cipher : cipherSuite) {
auto innerName = GetInnerNameFromCipherSuite(cipher);
if (innerName.empty()) {
continue;
}
if (IsTlsV13Cipher(innerName)) {
cipherString.tlsV13CiperSuiteString.append(innerName).append(":");
} else {
cipherString.ciperSuiteString.append(innerName).append(":");
}
}
if (!cipherString.tlsV13CiperSuiteString.empty()) {
cipherString.tlsV13CiperSuiteString.pop_back();
}
if (!cipherString.ciperSuiteString.empty()) {
cipherString.ciperSuiteString.pop_back();
}
return cipherString;
}
} // namespace OHOS::NetStack::Http

View File

@ -56,6 +56,7 @@ public:
static constexpr const char *INTERFACE_CERT_TYPE = "CertType";
static constexpr const char *INTERFACE_HTTP_RESPONSE_CACHE = "OHOS_NET_HTTP_HttpResponseCache";
static constexpr const char *INTERFACE_HTTP_DATA_TYPE = "HttpDataType";
static constexpr const char *INTERFACE_TLS_VERSION = "TlsVersion";
static napi_value InitHttpModule(napi_env env, napi_value exports);
@ -74,6 +75,8 @@ private:
static void InitResponseCode(napi_env env, napi_value exports);
static void InitTlsVersion(napi_env env, napi_value exports);
static void InitHttpProtocol(napi_env env, napi_value exports);
static void InitCertType(napi_env env, napi_value exports);

View File

@ -134,6 +134,7 @@ void HttpModuleExports::InitHttpProperties(napi_env env, napi_value exports)
InitCertType(env, exports);
InitHttpProtocol(env, exports);
InitHttpDataType(env, exports);
InitTlsVersion(env, exports);
}
void HttpModuleExports::InitRequestMethod(napi_env env, napi_value exports)
@ -198,6 +199,25 @@ void HttpModuleExports::InitResponseCode(napi_env env, napi_value exports)
NapiUtils::SetNamedProperty(env, exports, INTERFACE_RESPONSE_CODE, responseCode);
}
void HttpModuleExports::InitTlsVersion(napi_env env, napi_value exports)
{
std::initializer_list<napi_property_descriptor> properties = {
DECLARE_NAPI_STATIC_PROPERTY(HttpConstant::TLS_VERSION_1_0,
NapiUtils::CreateUint32(env, static_cast<uint32_t>(TlsVersion::TLSv1_0))),
DECLARE_NAPI_STATIC_PROPERTY(HttpConstant::TLS_VERSION_1_1,
NapiUtils::CreateUint32(env, static_cast<uint32_t>(TlsVersion::TLSv1_1))),
DECLARE_NAPI_STATIC_PROPERTY(HttpConstant::TLS_VERSION_1_2,
NapiUtils::CreateUint32(env, static_cast<uint32_t>(TlsVersion::TLSv1_2))),
DECLARE_NAPI_STATIC_PROPERTY(HttpConstant::TLS_VERSION_1_3,
NapiUtils::CreateUint32(env, static_cast<uint32_t>(TlsVersion::TLSv1_3))),
};
napi_value tlsVersion = NapiUtils::CreateObject(env);
NapiUtils::DefineProperties(env, tlsVersion, properties);
NapiUtils::SetNamedProperty(env, exports, INTERFACE_TLS_VERSION, tlsVersion);
}
void HttpModuleExports::InitHttpProtocol(napi_env env, napi_value exports)
{
std::initializer_list<napi_property_descriptor> properties = {

View File

@ -22,6 +22,8 @@
#include "constant.h"
#include "secure_char.h"
#include "http_tls_config.h"
#include "napi_utils.h"
namespace OHOS::NetStack::Http {
enum class HttpProtocol {
@ -52,6 +54,29 @@ enum class HashAlgorithm {
INVALID,
};
enum class AuthenticationType {
AUTO,
BASIC,
NTLM,
DIGEST,
};
struct Credential {
NapiUtils::SecureData username;
NapiUtils::SecureData password;
};
struct ServerAuthentication {
Credential credential;
AuthenticationType authenticationType = AuthenticationType::AUTO;
};
struct TlsOption {
std::unordered_set<CipherSuite> cipherSuite;
TlsVersion tlsVersionMin = TlsVersion::DEFAULT;
TlsVersion tlsVersionMax = TlsVersion::DEFAULT;
};
struct CertificatePinning {
HashAlgorithm hashAlgorithm = HashAlgorithm::SHA256;
std::string publicKeyHash;
@ -95,8 +120,14 @@ public:
void AddMultiFormData(const MultiFormData &multiFormData);
void SetTlsOption(const TlsOption &tlsOption);
void SetServerAuthentication(const ServerAuthentication &serverAuthentication);
void SetCertificatePinning(std::string certPIN);
void SetCanSkipCertVerifyFlag(bool canCertVerify);
[[nodiscard]] std::string GetCertificatePinning() const;
[[nodiscard]] const std::string &GetUrl() const;
@ -137,9 +168,15 @@ public:
[[nodiscard]] const std::vector<std::string> &GetDnsServers() const;
[[nodiscard]] bool GetCanSkipCertVerifyFlag() const;
void GetClientCert(std::string &cert, std::string &certType, std::string &key, Secure::SecureChar &keyPasswd);
std::vector<MultiFormData> GetMultiPartDataList();
[[nodiscard]] const TlsOption GetTlsOption() const;
[[nodiscard]] const ServerAuthentication GetServerAuthentication() const;
private:
std::string url_;
@ -189,9 +226,15 @@ private:
Secure::SecureChar keyPasswd_;
bool canSkipCertVerify_ = false;
std::vector<MultiFormData> multiFormDataList_;
std::string certificatePinning_;
TlsOption tlsOption_;
ServerAuthentication serverAuthentication_;
};
} // namespace OHOS::NetStack::Http

View File

@ -177,6 +177,15 @@ uint32_t HttpRequestOptions::GetPriority() const
return priority_;
}
void HttpRequestOptions::SetCanSkipCertVerifyFlag(bool canCertVerify)
{
canSkipCertVerify_ = canCertVerify;
}
bool HttpRequestOptions::GetCanSkipCertVerifyFlag() const
{
return canSkipCertVerify_;
}
void HttpRequestOptions::SetUsingHttpProxyType(UsingHttpProxyType type)
{
usingHttpProxyType_ = type;
@ -238,6 +247,30 @@ const std::string &HttpRequestOptions::GetCaPath() const
return caPath_;
}
void HttpRequestOptions::SetTlsOption(const TlsOption &tlsOption)
{
tlsOption_.tlsVersionMax = tlsOption.tlsVersionMax;
tlsOption_.tlsVersionMin = tlsOption.tlsVersionMin;
tlsOption_.cipherSuite = tlsOption.cipherSuite;
}
const TlsOption HttpRequestOptions::GetTlsOption() const
{
return tlsOption_;
}
void HttpRequestOptions::SetServerAuthentication(const ServerAuthentication &serverAuthentication)
{
serverAuthentication_.authenticationType = serverAuthentication.authenticationType;
serverAuthentication_.credential.password = serverAuthentication.credential.password;
serverAuthentication_.credential.username = serverAuthentication.credential.username;
}
const ServerAuthentication HttpRequestOptions::GetServerAuthentication() const
{
return serverAuthentication_;
}
void HttpRequestOptions::SetDohUrl(const std::string &dohUrl)
{
if (dohUrl.empty()) {

View File

@ -39,6 +39,7 @@ ohos_fuzztest("HttpFuzzTest") {
"$NETSTACK_DIR/utils/napi_utils/include",
"$NETSTACK_NAPI_ROOT/http/constant/include",
"$NETSTACK_NAPI_ROOT/http/options/include",
"$NETSTACK_NAPI_ROOT/http/http_exec/include",
]
include_dirs += utils_include
@ -72,6 +73,7 @@ ohos_fuzztest("HttpFuzzTest") {
]
external_deps = common_external_deps
external_deps += [ "napi:ace_napi" ]
}
###############################################################################

View File

@ -67,11 +67,13 @@ ohos_unittest("http_unittest") {
}
external_deps = common_external_deps
external_deps += [ "napi:ace_napi" ]
sources = [
"$NETSTACK_NAPI_ROOT/http/async_context/src/request_context.cpp",
"$NETSTACK_NAPI_ROOT/http/constant/src/constant.cpp",
"$NETSTACK_NAPI_ROOT/http/http_exec/src/http_exec.cpp",
"$NETSTACK_NAPI_ROOT/http/http_exec/src/http_tls_config.cpp",
"$NETSTACK_NAPI_ROOT/http/options/src/http_request_options.cpp",
"$NETSTACK_NAPI_ROOT/http/options/src/http_response.cpp",
"$SUBSYSTEM_DIR/netstack/utils/common_utils/src/netstack_common_utils.cpp",

View File

@ -45,10 +45,12 @@ ohos_unittest("http_cache_unittest") {
"$NETSTACK_NAPI_ROOT/http/constant/include",
"$NETSTACK_NAPI_ROOT/http/options/include",
"$NETSTACK_NAPI_ROOT/http/cache/base64/include",
"$NETSTACK_NAPI_ROOT/http/http_exec/include",
]
include_dirs += utils_include
external_deps = common_external_deps
external_deps += [ "napi:ace_napi" ]
deps = [ "$SUBSYSTEM_DIR/netstack/utils/napi_utils:napi_utils" ]

View File

@ -44,6 +44,7 @@ ohos_unittest("netstack_network_profiler_utils_test") {
"$NETSTACK_UTILS_ROOT/profiler_utils/include",
"$NETSTACK_UTILS_ROOT/tlv_utils/include",
"$NETSTACK_DIR/utils/common_utils/include",
"$NETSTACK_NAPI_ROOT/http/http_exec/include",
]
include_dirs += utils_include
@ -53,6 +54,7 @@ ohos_unittest("netstack_network_profiler_utils_test") {
"curl:curl_shared",
"hiprofiler:libnetwork_profiler",
"init:libbegetutil",
"napi:ace_napi",
"time_service:time_client",
]

View File

@ -28,6 +28,8 @@
#include "napi/native_api.h"
#include "uv.h"
#include "securec.h"
namespace OHOS::NetStack::NapiUtils {
static constexpr int NETSTACK_NAPI_INTERNAL_ERROR = 2300002;
using UvHandler = std::function<void()>;
@ -38,6 +40,14 @@ private:
std::mutex mutex;
};
struct SecureData : public std::string {
~SecureData()
{
// Clear Data, to keep the memory safe
(void)memset_s(data(), size(), 0, size());
}
};
napi_valuetype GetValueType(napi_env env, napi_value value);
bool IsInstanceOf(napi_env env, napi_value object, const std::string &name);
@ -86,6 +96,11 @@ std::string GetStringFromValueUtf8(napi_env env, napi_value value);
std::string GetStringPropertyUtf8(napi_env env, napi_value object, const std::string &propertyName);
void GetSecureDataFromValueUtf8(napi_env env, napi_value value, SecureData &data);
void GetSecureDataPropertyUtf8(
napi_env env, napi_value object, const std::string &propertyName, SecureData &data);
std::string NapiValueToString(napi_env env, napi_value value);
void SetStringPropertyUtf8(napi_env env, napi_value object, const std::string &name, const std::string &value);

View File

@ -32,7 +32,6 @@
#include "napi/native_common.h"
#include "netstack_log.h"
#include "node_api.h"
#include "securec.h"
namespace OHOS::NetStack::NapiUtils {
static constexpr const char *GLOBAL_JSON = "JSON";
@ -291,6 +290,44 @@ napi_value CreateStringUtf8(napi_env env, const std::string &str)
return value;
}
void GetSecureDataPropertyUtf8(napi_env env, napi_value object, const std::string &propertyName,
SecureData &data)
{
if (!HasNamedProperty(env, object, propertyName)) {
return;
}
napi_value value = GetNamedProperty(env, object, propertyName);
GetSecureDataFromValueUtf8(env, value, data);
}
void GetSecureDataFromValueUtf8(napi_env env, napi_value value, SecureData &data)
{
if (GetValueType(env, value) != napi_string) {
return;
}
size_t stringLength = 0;
NAPI_CALL_RETURN_VOID(env, napi_get_value_string_utf8(env, value, nullptr, 0, &stringLength));
if (stringLength == 0 || stringLength > SIZE_MAX - 1) {
return;
}
auto deleter = [](char *s) { free(reinterpret_cast<void *>(s)); };
auto mem = malloc(stringLength + 1);
if (mem == nullptr) {
return;
}
std::unique_ptr<char, decltype(deleter)> str(static_cast<char *>(mem), deleter);
if (memset_s(str.get(), stringLength + 1, 0, stringLength + 1) != EOK) {
return;
}
size_t length = 0;
NAPI_CALL_RETURN_VOID(env, napi_get_value_string_utf8(env, value, str.get(), stringLength + 1, &length));
if (length > 0) {
data.append(str.get(), length);
}
}
std::string GetStringFromValueUtf8(napi_env env, napi_value value)
{
if (GetValueType(env, value) != napi_string) {