!1738 http明文开关

Merge pull request !1738 from jxw/master
This commit is contained in:
openharmony_ci 2025-01-24 03:57:43 +00:00 committed by Gitee
commit 88a950d716
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
21 changed files with 314 additions and 7 deletions

View File

@ -75,6 +75,7 @@ static const std::map<int32_t, const char *> HTTP_ERR_MAP = {
{HTTP_REMOTE_FILE_NOT_FOUND, "Remote file not found"},
{HTTP_AUTH_ERROR, "An authentication function returned an error"},
{HTTP_SSL_PINNEDPUBKEYNOTMATCH, "Specified pinned public key did not match"},
{HTTP_CLEARTEXT_NOT_PERMITTED, "Cleartext traffic is not permitted"},
{HTTP_NOT_ALLOWED_HOST, "It is not allowed to access this domain"},
{HTTP_UNKNOWN_OTHER_ERROR, "Unknown Other Error"},
};
@ -612,6 +613,10 @@ int32_t RequestContext::GetErrorCode() const
return HTTP_NOT_ALLOWED_HOST;
}
if (BaseContext::IsCleartextNotPermitted()) {
return HTTP_CLEARTEXT_NOT_PERMITTED;
}
if (HTTP_ERR_MAP.find(err + HTTP_ERROR_CODE_BASE) != HTTP_ERR_MAP.end()) {
return err + HTTP_ERROR_CODE_BASE;
}
@ -633,6 +638,10 @@ std::string RequestContext::GetErrorMessage() const
return HTTP_ERR_MAP.at(HTTP_NOT_ALLOWED_HOST);
}
if (BaseContext::IsCleartextNotPermitted()) {
return HTTP_ERR_MAP.at(HTTP_CLEARTEXT_NOT_PERMITTED);
}
auto pos = HTTP_ERR_MAP.find(err + HTTP_ERROR_CODE_BASE);
if (pos != HTTP_ERR_MAP.end()) {
return pos->second;

View File

@ -92,6 +92,7 @@ enum HttpErrorCode {
HTTP_REMOTE_FILE_NOT_FOUND = HTTP_ERROR_CODE_BASE + CURLE_REMOTE_FILE_NOT_FOUND,
HTTP_AUTH_ERROR = HTTP_ERROR_CODE_BASE + CURLE_AUTH_ERROR,
HTTP_SSL_PINNEDPUBKEYNOTMATCH = HTTP_ERROR_CODE_BASE + CURLE_SSL_PINNEDPUBKEYNOTMATCH,
HTTP_CLEARTEXT_NOT_PERMITTED = 2300997,
HTTP_NOT_ALLOWED_HOST = 2300998,
HTTP_UNKNOWN_OTHER_ERROR = 2300999
};

View File

@ -570,6 +570,10 @@ bool HttpExec::ExecRequest(RequestContext *context)
context->SetNoAllowedHost(true);
return false;
}
if (!CommonUtils::IsCleartextPermitted(context->options.GetUrl(), "http://")) {
context->SetCleartextNotPermitted(true);
return false;
}
if (context->GetSharedManager()->IsEventDestroy()) {
return false;
}
@ -589,7 +593,6 @@ bool HttpExec::ExecRequest(RequestContext *context)
}
return true;
}
if (!RequestWithoutCache(context)) {
context->SetErrorCode(NapiUtils::NETSTACK_NAPI_INTERNAL_ERROR);
if (context->GetSharedManager()) {
@ -605,7 +608,6 @@ bool HttpExec::ExecRequest(RequestContext *context)
}
return false;
}
return true;
}

View File

@ -50,6 +50,7 @@ ohos_shared_library("networksecurity_napi") {
sources = [
"async_context/src/cert_context.cpp",
"async_context/src/cleartext_context.cpp",
"async_work/src/net_ssl_async_work.cpp",
"net_ssl_exec/src/net_ssl_exec.cpp",
"net_ssl_module/src/net_ssl_module.cpp",

View File

@ -0,0 +1,55 @@
/*
* Copyright (c) 2025 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 COMMUNICATIONNETSTACK_CLEARTEXT_CONTEXT_H
#define COMMUNICATIONNETSTACK_CLEARTEXT_CONTEXT_H
#include "base_context.h"
#include "net_ssl.h"
#define PARAM_NONE 0
#define PARAM_JUST_OPTIONS 1
namespace OHOS::NetStack::Ssl {
static constexpr const size_t MAX_ERR_NUM = 256;
class CleartextContext final : public BaseContext {
public:
CleartextContext() = delete;
explicit CleartextContext(napi_env env, EventManager *manager);
void ParseParams(napi_value *params, size_t paramsCount) override;
[[nodiscard]] std::string GetErrorMessage() const override;
public:
bool isCleartextPermitted_ = true;
};
class CleartextForHostContext final : public BaseContext {
public:
CleartextForHostContext() = delete;
explicit CleartextForHostContext(napi_env env, EventManager *manager);
void ParseParams(napi_value *params, size_t paramsCount) override;
[[nodiscard]] std::string GetErrorMessage() const override;
public:
std::string hostname_ = "";
bool isCleartextPermitted_ = true;
private:
bool CheckParamsType(napi_value *params, size_t paramsCount);
};
} // namespace OHOS::NetStack::Ssl
#endif // COMMUNICATIONNETSTACK_CLEARTEXT_CONTEXT_H

View File

@ -0,0 +1,89 @@
/*
* Copyright (c) 2025 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 "cleartext_context.h"
#include "netstack_log.h"
#include "napi_utils.h"
#if HAS_NETMANAGER_BASE
#include "net_conn_client.h"
#endif // HAS_NETMANAGER_BASE
namespace OHOS::NetStack::Ssl {
CleartextContext::CleartextContext(napi_env env, EventManager *manager) : BaseContext(env, manager) {}
void CleartextContext::ParseParams(napi_value *params, size_t paramsCount)
{
if (paramsCount != PARAM_NONE) {
NETSTACK_LOGE("check params type failed");
SetNeedThrowException(true);
SetErrorCode(PARSE_ERROR_CODE);
return;
}
SetParseOK(true);
}
std::string CleartextContext::GetErrorMessage() const
{
auto errCode = BaseContext::GetErrorCode();
if (errCode == PARSE_ERROR_CODE) {
return PARSE_ERROR_MSG;
}
if (errCode == PERMISSION_DENIED_CODE) {
return PERMISSION_DENIED_MSG;
}
char err[MAX_ERR_NUM] = {0};
(void)strerror_r(errCode, err, MAX_ERR_NUM);
return err;
}
CleartextForHostContext::CleartextForHostContext(napi_env env,
EventManager *manager) : BaseContext(env, manager) {}
void CleartextForHostContext::ParseParams(napi_value *params, size_t paramsCount)
{
if (!CheckParamsType(params, paramsCount)) {
NETSTACK_LOGE("check params type failed");
SetNeedThrowException(true);
SetErrorCode(PARSE_ERROR_CODE);
return;
}
hostname_ = NapiUtils::GetStringFromValueUtf8(GetEnv(), params[0]);
SetParseOK(true);
}
bool CleartextForHostContext::CheckParamsType(napi_value *params, size_t paramsCount)
{
if (paramsCount == PARAM_JUST_OPTIONS) {
return NapiUtils::GetValueType(GetEnv(), params[0]) == napi_string;
}
return false;
}
std::string CleartextForHostContext::GetErrorMessage() const
{
auto errCode = BaseContext::GetErrorCode();
if (errCode == PARSE_ERROR_CODE) {
return PARSE_ERROR_MSG;
}
if (errCode == PERMISSION_DENIED_CODE) {
return PERMISSION_DENIED_MSG;
}
char err[MAX_ERR_NUM] = {0};
(void)strerror_r(errCode, err, MAX_ERR_NUM);
return err;
}
} // namespace OHOS::NetManagerStandard

View File

@ -25,6 +25,10 @@ public:
static napi_value VerifyCertificationSync(napi_env env, napi_callback_info info);
static napi_value IsCleartextPermitted(napi_env env, napi_callback_info info);
static napi_value IsCleartextPermittedByHostName(napi_env env, napi_callback_info info);
static napi_value InitNetSslModule(napi_env env, napi_value exports);
static void InitSslProperties(napi_env env, napi_value exports);

View File

@ -16,6 +16,7 @@
#include <string>
#include "cert_context.h"
#include "cleartext_context.h"
#include "net_ssl_async_work.h"
#include "net_ssl_exec.h"
#include "net_ssl_module.h"
@ -23,6 +24,9 @@
#include "js_native_api.h"
#include "module_template.h"
#include "netstack_log.h"
#if HAS_NETMANAGER_BASE
#include "net_conn_client.h"
#endif // HAS_NETMANAGER_BASE
namespace OHOS::NetStack::Ssl {
static constexpr const char *NET_SSL_MODULE_NAME = "net.networkSecurity";
@ -54,7 +58,9 @@ void NetSslModuleExports::InitSslProperties(napi_env env, napi_value exports)
{
std::initializer_list<napi_property_descriptor> properties = {
DECLARE_NAPI_FUNCTION("certVerification", VerifyCertification),
DECLARE_NAPI_FUNCTION("certVerificationSync", VerifyCertificationSync)};
DECLARE_NAPI_FUNCTION("certVerificationSync", VerifyCertificationSync),
DECLARE_NAPI_FUNCTION("isCleartextPermitted", IsCleartextPermitted),
DECLARE_NAPI_FUNCTION("isCleartextPermittedByHostName", IsCleartextPermittedByHostName)};
NapiUtils::DefineProperties(env, exports, properties);
InitCertType(env, exports);
@ -123,4 +129,70 @@ extern "C" __attribute__((constructor)) void RegisterSslModule(void)
{
napi_module_register(&g_sslModule);
}
napi_value NetSslModuleExports::IsCleartextPermitted(napi_env env, napi_callback_info info)
{
napi_value thisVal = nullptr;
size_t paramsCount = MAX_PARAM_NUM;
napi_value params[MAX_PARAM_NUM] = {nullptr};
NAPI_CALL(env, napi_get_cb_info(env, info, &paramsCount, params, &thisVal, nullptr));
EventManager *manager = nullptr;
auto context = std::make_unique<CleartextContext>(env, manager);
if (!context) {
return NapiUtils::GetUndefined(env);
}
context->ParseParams(params, paramsCount);
if (context->IsParseOK()) {
#if HAS_NETMANAGER_BASE
using namespace OHOS::NetManagerStandard;
int32_t ret = NetConnClient::GetInstance().IsCleartextPermitted(context->isCleartextPermitted_);
if (ret != NETMANAGER_SUCCESS) {
context->SetErrorCode(ret);
napi_throw_error(env, std::to_string(context->GetErrorCode()).c_str(), context->GetErrorMessage().c_str());
return NapiUtils::GetUndefined(env);
}
#else
context->isCleartextPermitted_ = true;
#endif
NETSTACK_LOGD("isCleartextPermitted is %{public}d\n", context->isCleartextPermitted_);
} else {
napi_throw_error(env, std::to_string(context->GetErrorCode()).c_str(), context->GetErrorMessage().c_str());
return NapiUtils::GetUndefined(env);
}
return NapiUtils::GetBoolean(context->GetEnv(), context->isCleartextPermitted_);
}
napi_value NetSslModuleExports::IsCleartextPermittedByHostName(napi_env env, napi_callback_info info)
{
napi_value thisVal = nullptr;
size_t paramsCount = MAX_PARAM_NUM;
napi_value params[MAX_PARAM_NUM] = {nullptr};
NAPI_CALL(env, napi_get_cb_info(env, info, &paramsCount, params, &thisVal, nullptr));
EventManager *manager = nullptr;
auto context = std::make_unique<CleartextForHostContext>(env, manager);
if (!context) {
return NapiUtils::GetUndefined(env);
}
context->ParseParams(params, paramsCount);
if (context->IsParseOK()) {
#if HAS_NETMANAGER_BASE
using namespace OHOS::NetManagerStandard;
int32_t ret = NetConnClient::GetInstance().IsCleartextPermitted(context->hostname_,
context->isCleartextPermitted_);
if (ret != NETMANAGER_SUCCESS) {
context->SetErrorCode(ret);
napi_throw_error(env, std::to_string(context->GetErrorCode()).c_str(), context->GetErrorMessage().c_str());
return NapiUtils::GetUndefined(env);
}
#else
context->isCleartextPermitted_ = true;
#endif
NETSTACK_LOGD("isCleartextPermitted is %{public}d\n", context->isCleartextPermitted_);
} else {
napi_throw_error(env, std::to_string(context->GetErrorCode()).c_str(), context->GetErrorMessage().c_str());
return NapiUtils::GetUndefined(env);
}
return NapiUtils::GetBoolean(context->GetEnv(), context->isCleartextPermitted_);
}
} // namespace OHOS::NetStack::Ssl

View File

@ -58,6 +58,7 @@ static const std::map<int32_t, const std::string> HTTP_ERR_MAP = {
{HTTP_REMOTE_FILE_NOT_FOUND, "Remote file not found"},
{HTTP_AUTH_ERROR, "An authentication function returned an error"},
{HTTP_SSL_PINNEDPUBKEYNOTMATCH, "Specified pinned public key did not match"},
{HTTP_CLEARTEXT_NOT_PERMITTED, "Cleartext traffic is not permitted"},
{HTTP_UNKNOWN_OTHER_ERROR, "Unknown Other Error"},
};

View File

@ -437,6 +437,12 @@ bool HttpClientTask::Start()
return false;
}
if (!CommonUtils::IsCleartextPermitted(request_.GetURL(), "http://")) {
NETSTACK_LOGE("Cleartext not permitted");
error_.SetErrorCode(HttpErrorCode::HTTP_CLEARTEXT_NOT_PERMITTED);
return false;
}
if (error_.GetErrorCode() != HttpErrorCode::HTTP_NONE_ERR) {
NETSTACK_LOGE("error_.GetErrorCode()=%{public}d", error_.GetErrorCode());
return false;

View File

@ -60,6 +60,7 @@ enum HttpErrorCode {
HTTP_REMOTE_FILE_NOT_FOUND = HTTP_ERROR_CODE_BASE + CURLE_REMOTE_FILE_NOT_FOUND,
HTTP_AUTH_ERROR = HTTP_ERROR_CODE_BASE + CURLE_AUTH_ERROR,
HTTP_SSL_PINNEDPUBKEYNOTMATCH = HTTP_ERROR_CODE_BASE + CURLE_SSL_PINNEDPUBKEYNOTMATCH,
HTTP_CLEARTEXT_NOT_PERMITTED = 2300997,
HTTP_UNKNOWN_OTHER_ERROR = 2300999
};

View File

@ -76,6 +76,10 @@ int32_t OH_NetStack_GetCertificatesForHostName(const char *hostname, NetStack_Ce
void OH_Netstack_DestroyCertificatesContent(NetStack_Certificates *certs);
int32_t OH_Netstack_IsCleartextPermitted(bool *isCleartextPermitted);
int32_t OH_Netstack_IsCleartextPermittedByHostName(const char *hostname, bool *isCleartextPermitted);
#ifdef __cplusplus
}
#endif

View File

@ -14,5 +14,13 @@
{
"first_introduced":"11",
"name": "OH_Netstack_DestroyCertificatesContent"
},
{
"first_introduced":"16",
"name": "OH_Netstack_IsCleartextPermitted"
},
{
"first_introduced":"16",
"name": "OH_Netstack_IsCleartextPermittedByHostName"
}
]

View File

@ -187,3 +187,22 @@ void OH_Netstack_DestroyCertificatesContent(NetStack_Certificates *certs)
certs->content = nullptr;
certs->length = 0;
}
int32_t OH_Netstack_IsCleartextPermitted(bool *isCleartextPermitted)
{
if (isCleartextPermitted == nullptr) {
NETSTACK_LOGE("OH_Netstack_IsCleartextPermitted received invalid parameters");
return OHOS::NetManagerStandard::NETMANAGER_ERR_PARAMETER_ERROR;
}
return OHOS::NetManagerStandard::NetConnClient::GetInstance().IsCleartextPermitted(*isCleartextPermitted);
}
int32_t OH_Netstack_IsCleartextPermittedByHostName(const char *hostname, bool *isCleartextPermitted)
{
if (hostname == nullptr || isCleartextPermitted == nullptr) {
NETSTACK_LOGE("OH_Netstack_IsCleartextPermittedByHostName received invalid parameters");
return OHOS::NetManagerStandard::NETMANAGER_ERR_PARAMETER_ERROR;
}
return OHOS::NetManagerStandard::NetConnClient::GetInstance()
.IsCleartextPermitted(std::string(hostname), *isCleartextPermitted);
}

View File

@ -57,6 +57,7 @@ ohos_fuzztest("NetsslExecFuzzTest") {
sources = [
"$NETSTACK_DIR/utils/common_utils/src/netstack_common_utils.cpp",
"$NETSTACK_NAPI_ROOT/net_ssl/async_context/src/cert_context.cpp",
"$NETSTACK_NAPI_ROOT/net_ssl/async_context/src/cleartext_context.cpp",
"$NETSTACK_NAPI_ROOT/net_ssl/async_work/src/net_ssl_async_work.cpp",
"$NETSTACK_NAPI_ROOT/net_ssl/net_ssl_exec/src/net_ssl_exec.cpp",
"$NETSTACK_NAPI_ROOT/net_ssl/net_ssl_module/src/net_ssl_module.cpp",

View File

@ -45,6 +45,7 @@ ohos_unittest("netssl_unittest") {
sources = [
"$NETSSL_NAPI/async_context/src/cert_context.cpp",
"$NETSSL_NAPI/async_context/src/cleartext_context.cpp",
"$NETSSL_NAPI/async_work/src/net_ssl_async_work.cpp",
"$NETSSL_NAPI/net_ssl_exec/src/net_ssl_exec.cpp",
"$NETSSL_NAPI/net_ssl_module/src/net_ssl_module.cpp",

View File

@ -98,5 +98,7 @@ bool GetFileDataFromFilePath(const std::string& filePath, std::string& fileData)
bool Sha256sum(unsigned char *buf, size_t buflen, std::string &digestStr);
bool IsCertPubKeyInPinned(const std::string &certPubKeyDigest, const std::string &pinnedPubkey);
bool IsCleartextPermitted(const std::string &url, const std::string &protocol);
} // namespace OHOS::NetStack::CommonUtils
#endif /* COMMUNICATIONNETSTACK_COMMON_UTILS_H */

View File

@ -587,4 +587,17 @@ bool IsCertPubKeyInPinned(const std::string &certPubKeyDigest, const std::string
}
return false;
}
bool IsCleartextPermitted(const std::string &url, const std::string &protocol)
{
bool isCleartextPermitted = true;
#if HAS_NETMANAGER_BASE
using namespace OHOS::NetManagerStandard;
if (url.find(protocol) != std::string::npos) {
std::string hostName = GetHostnameFromURL(url);
NetConnClient::GetInstance().IsCleartextPermitted(hostName, isCleartextPermitted);
}
#endif
return isCleartextPermitted;
}
} // namespace OHOS::NetStack::CommonUtils

View File

@ -101,8 +101,12 @@ public:
void SetNoAllowedHost(bool needThrowException);
void SetCleartextNotPermitted(bool notPermitted);
[[nodiscard]] bool IsNoAllowedHost() const;
[[nodiscard]] bool IsCleartextNotPermitted() const;
[[nodiscard]] EventManager *GetManager() const;
[[nodiscard]] std::shared_ptr<EventManager> GetSharedManager() const;
@ -156,6 +160,8 @@ private:
bool noAllowedHost_;
bool cleartextNotPermitted_;
std::string asyncWorkName_;
std::string errorMessage_;

View File

@ -182,7 +182,7 @@ napi_value InterfaceWithOutAsyncWorkWithManagerWrapper(napi_env env, napi_callba
}
}
if (!context->IsParseOK() || context->IsPermissionDenied() || context->IsNoAllowedHost() ||
context->GetSharedManager()->IsEventDestroy()) {
context->IsCleartextNotPermitted() || context->GetSharedManager()->IsEventDestroy()) {
context->CreateAsyncWork(asyncWorkName, executor, callback);
}
return ret;
@ -231,7 +231,7 @@ napi_value InterfaceWithOutAsyncWorkWithSharedManager(napi_env env, napi_callbac
}
}
if (!context->IsParseOK() || context->IsPermissionDenied() || context->IsNoAllowedHost() ||
context->GetSharedManager()->IsEventDestroy()) {
context->IsCleartextNotPermitted() || context->GetSharedManager()->IsEventDestroy()) {
context->CreateAsyncWork(asyncWorkName, executor, callback);
}
return ret;
@ -323,7 +323,7 @@ napi_value InterfaceWithOutAsyncWork(napi_env env, napi_callback_info info,
}
}
if (!context->IsParseOK() || context->IsPermissionDenied() || context->IsNoAllowedHost() ||
context->GetManager()->IsEventDestroy()) {
context->IsCleartextNotPermitted() || context->GetManager()->IsEventDestroy()) {
context->CreateAsyncWork(asyncWorkName, executor, callback);
}
return ret;

View File

@ -36,7 +36,8 @@ BaseContext::BaseContext(napi_env env, EventManager *manager)
needPromise_(true),
needThrowException_(false),
permissionDenied_(false),
noAllowedHost_(false)
noAllowedHost_(false),
cleartextNotPermitted_(false)
{
}
@ -55,6 +56,7 @@ BaseContext::BaseContext(napi_env env, const std::shared_ptr<EventManager> &shar
needThrowException_(false),
permissionDenied_(false),
noAllowedHost_(false),
cleartextNotPermitted_(false),
sharedManager_(sharedManager)
{
}
@ -291,6 +293,16 @@ bool BaseContext::IsNoAllowedHost() const
return noAllowedHost_;
}
void BaseContext::SetCleartextNotPermitted(bool notPermitted)
{
cleartextNotPermitted_ = notPermitted;
}
bool BaseContext::IsCleartextNotPermitted() const
{
return cleartextNotPermitted_;
}
void BaseContext::CreateReference(napi_value value)
{
if (env_ != nullptr && value != nullptr) {