* Copyright (C) 2021 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 "daemon.h"
#include "connect_validation.h"
#ifndef TEST_HASH
#include "hdc_hash_gen.h"
#endif
#include "serial_struct.h"
#include <openssl/sha.h>
#include <openssl/bio.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <fstream>
#include <unistd.h>
#include <sys/wait.h>
#ifdef HDC_SUPPORT_REPORT_COMMAND_EVENT
#include "command_event_report.h"
#endif
#include "hdc_statistic_reporter.h"
namespace Hdc {
#ifdef USE_CONFIG_UV_THREADS
HdcDaemon::HdcDaemon(bool serverOrDaemonIn, size_t uvThreadSize)
: HdcSessionBase(serverOrDaemonIn, uvThreadSize)
#else
HdcDaemon::HdcDaemon(bool serverOrDaemonIn)
: HdcSessionBase(serverOrDaemonIn, -1)
#endif
{
clsTCPServ = nullptr;
clsUSBServ = nullptr;
#ifdef HDC_EMULATOR
clsBridgeServ = nullptr;
#endif
#ifdef HDC_SUPPORT_UART
clsUARTServ = nullptr;
#endif
clsJdwp = nullptr;
authEnable = false;
}
HdcDaemon::~HdcDaemon()
{
WRITE_LOG(LOG_DEBUG, "~HdcDaemon");
}
void HdcDaemon::ClearInstanceResource()
{
TryStopInstance();
Base::TryCloseLoop(&loopMain, "HdcDaemon::~HdcDaemon");
if (clsTCPServ) {
delete (HdcDaemonTCP *)clsTCPServ;
clsTCPServ = nullptr;
}
if (clsUSBServ) {
delete (HdcDaemonUSB *)clsUSBServ;
clsUSBServ = nullptr;
}
#ifdef HDC_EMULATOR
if (clsBridgeServ) {
delete (HdcDaemonBridge *)clsBridgeServ;
clsBridgeServ = nullptr;
}
#endif
#ifdef HDC_SUPPORT_UART
if (clsUARTServ) {
delete (HdcDaemonUART *)clsUARTServ;
clsUARTServ = nullptr;
}
#endif
if (clsJdwp) {
delete (HdcJdwp *)clsJdwp;
clsJdwp = nullptr;
}
WRITE_LOG(LOG_DEBUG, "~HdcDaemon finish");
}
void HdcDaemon::TryStopInstance()
{
ClearSessions();
if (clsTCPServ) {
WRITE_LOG(LOG_DEBUG, "Stop TCP");
((HdcDaemonTCP *)clsTCPServ)->Stop();
}
if (clsUSBServ) {
WRITE_LOG(LOG_DEBUG, "Stop USB");
((HdcDaemonUSB *)clsUSBServ)->Stop();
}
#ifdef HDC_EMULATOR
if (clsBridgeServ) {
WRITE_LOG(LOG_DEBUG, "Stop Bridge");
((HdcDaemonBridge *)clsBridgeServ)->Stop();
}
#endif
#ifdef HDC_SUPPORT_UART
if (clsUARTServ) {
WRITE_LOG(LOG_DEBUG, "Stop UART");
((HdcDaemonUART *)clsUARTServ)->Stop();
}
#endif
((HdcJdwp *)clsJdwp)->Stop();
ReMainLoopForInstanceClear();
WRITE_LOG(LOG_DEBUG, "Stop loopmain");
}
bool HdcDaemon::GetAuthByPassValue()
{
int connectValidationStatus = HdcValidation::GetConnectValidationParam();
if ((connectValidationStatus == VALIDATION_HDC_DAEMON
|| connectValidationStatus == VALIDATION_HDC_HOST_AND_DAEMON)) {
WRITE_LOG(LOG_INFO, "If the connection verification function is enabled on the device side, "
"authentication is required.");
return true;
}
string secure;
#ifdef CONFIG_HDC_OSPM_AUTH_DISABLE
WRITE_LOG(LOG_INFO, "Get param secure failed caused by hdc ospm auth disable");
return false;
#endif
if (!SystemDepend::GetDevItem("const.hdc.secure", secure)) {
WRITE_LOG(LOG_INFO, "Get param secure failed");
return true;
}
if (Base::Trim(secure) != "1") {
WRITE_LOG(LOG_INFO, "Authentication is not required in root mode");
return false;
}
string oemmode;
if (!SystemDepend::GetDevItem("const.boot.oemmode", oemmode)) {
WRITE_LOG(LOG_INFO, "Get param oemmode failed");
return true;
}
if (Base::Trim(oemmode) != "rd") {
WRITE_LOG(LOG_INFO, "The device is locked, Authentication is required");
return true;
}
string authbypass;
if (!SystemDepend::GetDevItem("persist.hdc.auth_bypass", authbypass)) {
WRITE_LOG(LOG_INFO, "Get param auth_bypass failed");
return true;
}
if (Base::Trim(authbypass) == "1") {
WRITE_LOG(LOG_INFO, "Auth bypass, allow access");
return false;
}
return true;
}
#ifdef HDC_SUPPORT_UART
void HdcDaemon::InitMod(bool bEnableTCP, bool bEnableUSB, [[maybe_unused]] bool bEnableUART)
#else
void HdcDaemon::InitMod(bool bEnableTCP, bool bEnableUSB)
#endif
{
WRITE_LOG(LOG_DEBUG, "HdcDaemon InitMod");
#ifdef HDC_SUPPORT_UART
WRITE_LOG(LOG_DEBUG, "bEnableTCP:%d,bEnableUSB:%d", bEnableTCP, bEnableUSB);
#endif
if (bEnableTCP) {
clsTCPServ = new(std::nothrow) HdcDaemonTCP(false, this);
if (clsTCPServ == nullptr) {
WRITE_LOG(LOG_FATAL, "InitMod new clsTCPServ failed");
return;
}
((HdcDaemonTCP *)clsTCPServ)->Initial();
}
if (bEnableUSB) {
clsUSBServ = new(std::nothrow) HdcDaemonUSB(false, this);
if (clsUSBServ == nullptr) {
WRITE_LOG(LOG_FATAL, "InitMod new clsUSBServ failed");
return;
}
((HdcDaemonUSB *)clsUSBServ)->Initial();
}
#ifdef HDC_SUPPORT_UART
WRITE_LOG(LOG_DEBUG, "bEnableUART:%d", bEnableUART);
if (bEnableUART) {
clsUARTServ = new(std::nothrow) HdcDaemonUART(*this);
if (clsUARTServ == nullptr) {
WRITE_LOG(LOG_FATAL, "InitMod new clsUARTServ failed");
return;
}
((HdcDaemonUART *)clsUARTServ)->Initial();
}
#endif
clsJdwp = new(std::nothrow) HdcJdwp(&loopMain, &loopMainStatus);
if (clsJdwp == nullptr) {
WRITE_LOG(LOG_FATAL, "InitMod new clsJdwp failed");
return;
}
((HdcJdwp *)clsJdwp)->Initial();
#ifndef HDC_EMULATOR
authEnable = GetAuthByPassValue();
#endif
}
#ifdef HDC_EMULATOR
#ifdef HDC_SUPPORT_UART
void HdcDaemon::InitMod(bool bEnableTCP, bool bEnableUSB, bool bEnableBridge, [[maybe_unused]] bool bEnableUART)
{
InitMod(bEnableTCP, bEnableUSB, bEnableUART);
#else
void HdcDaemon::InitMod(bool bEnableTCP, bool bEnableUSB, bool bEnableBridge)
{
InitMod(bEnableTCP, bEnableUSB);
#endif
if (bEnableBridge) {
clsBridgeServ = new(std::nothrow) HdcDaemonBridge(false, this);
if (clsBridgeServ == nullptr) {
WRITE_LOG(LOG_FATAL, "InitMod new clsBridgeServ failed");
return;
}
((HdcDaemonBridge *)clsBridgeServ)->Initial();
}
}
#endif
bool HdcDaemon::RedirectToTask(HTaskInfo hTaskInfo, HSession , const uint32_t ,
const uint16_t command, uint8_t *payload, const int payloadSize)
{
StartTraceScope("HdcDaemon::RedirectToTask");
bool ret = true;
hTaskInfo->ownerSessionClass = this;
switch (command) {
case CMD_UNITY_EXECUTE:
case CMD_UNITY_REMOUNT:
case CMD_UNITY_REBOOT:
case CMD_UNITY_RUNMODE:
case CMD_UNITY_HILOG:
case CMD_UNITY_ROOTRUN:
case CMD_UNITY_BUGREPORT_INIT:
case CMD_JDWP_LIST:
case CMD_JDWP_TRACK:
case CMD_UNITY_EXECUTE_EX:
ret = TaskCommandDispatch<HdcDaemonUnity>(hTaskInfo, TYPE_UNITY, command, payload, payloadSize);
break;
case CMD_SHELL_INIT:
case CMD_SHELL_DATA:
ret = TaskCommandDispatch<HdcShell>(hTaskInfo, TYPE_SHELL, command, payload, payloadSize);
break;
case CMD_FILE_CHECK:
case CMD_FILE_DATA:
case CMD_FILE_FINISH:
case CMD_FILE_INIT:
case CMD_FILE_BEGIN:
case CMD_FILE_MODE:
case CMD_DIR_MODE:
ret = TaskCommandDispatch<HdcFile>(hTaskInfo, TASK_FILE, command, payload, payloadSize);
break;
case CMD_APP_CHECK:
case CMD_APP_DATA:
case CMD_APP_UNINSTALL:
ret = TaskCommandDispatch<HdcDaemonApp>(hTaskInfo, TASK_APP, command, payload, payloadSize);
break;
case CMD_FORWARD_INIT:
case CMD_FORWARD_CHECK:
case CMD_FORWARD_ACTIVE_MASTER:
case CMD_FORWARD_ACTIVE_SLAVE:
case CMD_FORWARD_DATA:
case CMD_FORWARD_FREE_CONTEXT:
case CMD_FORWARD_CHECK_RESULT:
ret = TaskCommandDispatch<HdcDaemonForward>(hTaskInfo, TASK_FORWARD, command, payload, payloadSize);
break;
default:
break;
}
return ret;
}
bool HdcDaemon::ShowPermitDialog()
{
pid_t pid;
int fds[2];
if (pipe(fds) != 0) {
WRITE_LOG(LOG_FATAL, "pipe failed %s", strerror(errno));
return false;
}
if ((pid = fork()) == -1) {
WRITE_LOG(LOG_FATAL, "fork failed %s", strerror(errno));
return false;
}
if (pid == 0) {
Base::DeInitProcess();
close(fds[0]);
dup2(fds[1], STDOUT_FILENO);
dup2(fds[1], STDERR_FILENO);
setsid();
setpgid(pid, pid);
int ret = execl("/system/bin/hdcd_user_permit", "hdcd_user_permit", NULL);
if (ret < 0) {
WRITE_LOG(LOG_FATAL, "start user_permit failed %d: %s", ret, strerror(errno));
_exit(0);
}
} else {
Base::CloseFd(fds[1]);
waitpid(pid, nullptr, 0);
char buf[1024] = { 0 };
int nbytes = read(fds[0], buf, sizeof(buf) - 1);
WRITE_LOG(LOG_FATAL, "user_permit put %d bytes: %s", nbytes, buf);
close(fds[0]);
}
return true;
}
UserPermit HdcDaemon::PostUIConfirm(string hostname, string pubkey)
{
if (!SystemDepend::SetDevItem("persist.hdc.daemon.auth_result", "auth_result_none")) {
WRITE_LOG(LOG_FATAL, "debug auth result failed, so refuse this connect");
return REFUSE;
}
if (!SystemDepend::SetDevItem("persist.hdc.client.hostname", hostname.c_str())) {
WRITE_LOG(LOG_FATAL, "set param(%s) failed", Hdc::MaskString(hostname).c_str());
return REFUSE;
}
uint8_t sha256Result[SHA256_DIGEST_LENGTH] = { 0 };
if (SHA256(reinterpret_cast<const uint8_t *>(pubkey.c_str()), pubkey.length(), sha256Result) == nullptr) {
WRITE_LOG(LOG_FATAL, "sha256 pubkey failed");
return REFUSE;
}
string hex = Base::Convert2HexStr(sha256Result, SHA256_DIGEST_LENGTH);
if (!SystemDepend::SetDevItem("persist.hdc.client.pubkey_sha256", hex.c_str())) {
WRITE_LOG(LOG_DEBUG, "Failed to set pubkey prop.");
return REFUSE;
}
if (!ShowPermitDialog()) {
WRITE_LOG(LOG_FATAL, "show dialog failed, so refuse this connect.");
return REFUSE;
}
string authResult;
if (!SystemDepend::GetDevItem("persist.hdc.daemon.auth_result", authResult)) {
WRITE_LOG(LOG_FATAL, "user refuse [%s] this developer [%s]",
authResult.c_str(), Hdc::MaskString(hostname).c_str());
return REFUSE;
}
WRITE_LOG(LOG_FATAL, "user permit_result [%s] for this developer [%s]",
authResult.c_str(), Hdc::MaskString(hostname).c_str());
string prifix = "auth_result:";
string result = authResult.substr(prifix.length());
if (result == "1") {
return ALLOWONCE;
}
if (result == "2") {
return ALLOWFORVER;
}
return REFUSE;
}
bool HdcDaemon::GetHostPubkeyInfo(const string& buf, string& hostname, string& pubkey)
{
char separator = '\x0C';
size_t tmp = buf.find(separator);
if (tmp == string::npos) {
WRITE_LOG(LOG_FATAL, "get hostname or pubkey failed");
return false;
}
hostname = buf.substr(0, tmp);
pubkey = buf.substr(tmp + 1);
WRITE_LOG(LOG_INFO, "hostname is [%s], pubkey is [%s]", Hdc::MaskString(hostname).c_str(),
Hdc::MaskString(pubkey.substr(0, pubkey.size() / 2)).c_str());
return (!hostname.empty() && !pubkey.empty());
}
void HdcDaemon::ClearKnownHosts()
{
char const *keyfile = "/data/service/el1/public/hdc/hdc_keys";
if (!authEnable || HandDaemonAuthBypass()) {
WRITE_LOG(LOG_INFO, "not enable secure, noneed clear keyfile");
return;
}
string authcancel;
if (!SystemDepend::GetDevItem("persist.hdc.daemon.auth_cancel", authcancel)) {
WRITE_LOG(LOG_FATAL, "get param auth_cancel failed");
return;
}
if (authcancel != "true") {
WRITE_LOG(LOG_FATAL, "param auth_cancel is not true: %s", authcancel.c_str());
return;
}
if (!SystemDepend::SetDevItem("persist.hdc.daemon.auth_cancel", "false")) {
WRITE_LOG(LOG_FATAL, "set param auth_cancel failed");
}
std::ofstream keyofs(keyfile, std::ios::out | std::ios::trunc);
if (!keyofs.is_open()) {
WRITE_LOG(LOG_FATAL, "open keyfile %s error", keyfile);
return;
}
keyofs.flush();
keyofs.close();
WRITE_LOG(LOG_FATAL, "clear keyfile %s over", keyfile);
return;
}
void HdcDaemon::UpdateKnownHosts(const string& key)
{
char const *keyfile = "/data/service/el1/public/hdc/hdc_keys";
std::ofstream keyofs(keyfile, std::ios::app);
if (!keyofs.is_open()) {
WRITE_LOG(LOG_FATAL, "open keyfile %s error", keyfile);
return;
}
string keytmp = key + "\n";
keyofs.write(keytmp.c_str(), keytmp.length());
keyofs.flush();
keyofs.close();
WRITE_LOG(LOG_FATAL, "save new key [%s] into keyfile %s over",
Hdc::MaskString(key.substr(0, key.size() / 2)).c_str(), keyfile);
return;
}
bool HdcDaemon::AlreadyInKnownHosts(const string& key)
{
char const *keyfile = "/data/service/el1/public/hdc/hdc_keys";
std::ifstream keyifs(keyfile);
if (!keyifs.is_open()) {
WRITE_LOG(LOG_FATAL, "open keyfile %s error", keyfile);
return false;
}
std::string keys((std::istreambuf_iterator<char>(keyifs)), std::istreambuf_iterator<char>());
const int keyLength = 625;
if (key.size() == keyLength && keys.find(key) != string::npos) {
keyifs.close();
return true;
}
WRITE_LOG(LOG_FATAL, "key [%s] not in keyfile %s", Hdc::MaskString(key.substr(0, key.size() / 2)).c_str(), keyfile);
keyifs.close();
return false;
}
bool HdcDaemon::HandDaemonAuthInit(HSession hSession, const uint32_t channelId, SessionHandShake &handshake)
{
hSession->tokenRSA = Base::GetSecureRandomString(SHA_DIGEST_LENGTH);
handshake.authType = AUTH_PUBLICKEY;
* If we know client support RSA_3072_SHA512 in AUTH_NONE phase
* Then told client that the server also support RSA_3072_SHA512 auth
* Notice, before here is "handshake.buf = hSession->tokenRSA", but the server not use it
*/
if (hSession->verifyType == AuthVerifyType::RSA_3072_SHA512) {
handshake.buf.clear();
Base::TlvAppend(handshake.buf, TAG_AUTH_TYPE, std::to_string(AuthVerifyType::RSA_3072_SHA512));
WRITE_LOG(LOG_INFO, "client support RSA_3072_SHA512 auth for %s session",
Hdc::MaskSessionIdToString(hSession->sessionId).c_str());
}
string bufString = SerialStruct::SerializeToString(handshake);
Send(hSession->sessionId, channelId, CMD_KERNEL_HANDSHAKE,
reinterpret_cast<uint8_t *>(const_cast<char *>(bufString.c_str())),
bufString.size());
InitSessionAuthInfo(hSession->sessionId, hSession->tokenRSA);
return true;
}
bool HdcDaemon::HandConnectValidationPubkey(HSession hSession, const uint32_t channelId, SessionHandShake &handshake)
{
string hostname, pubkey;
if (!GetHostPubkeyInfo(handshake.buf, hostname, pubkey)) {
WRITE_LOG(LOG_FATAL, "get pubkey failed for %u", hSession->sessionId);
return false;
}
if (HdcValidation::CheckAuthPubKeyIsValid(pubkey)) {
SendAuthMsg(handshake, channelId, hSession, pubkey);
} else {
string notifymsg = "[E000010]:Auth failed, cannt login the device.";
WRITE_LOG(LOG_FATAL, "%s", notifymsg.c_str());
HandleAuthFailed(handshake, channelId, hSession, notifymsg);
}
return true;
}
bool HdcDaemon::HandDaemonAuthPubkey(HSession hSession, const uint32_t channelId, SessionHandShake &handshake)
{
int connectValidationStatus = HdcValidation::GetConnectValidationParam();
if (connectValidationStatus == VALIDATION_HDC_DAEMON
|| connectValidationStatus == VALIDATION_HDC_HOST_AND_DAEMON) {
return HandConnectValidationPubkey(hSession, channelId, handshake);
}
bool ret = false;
string hostname, pubkey;
std::string sessionIdMaskStr = Hdc::MaskSessionIdToString(hSession->sessionId);
do {
if (!GetHostPubkeyInfo(handshake.buf, hostname, pubkey)) {
WRITE_LOG(LOG_FATAL, "get pubkey failed for %s", sessionIdMaskStr.c_str());
break;
}
if (AlreadyInKnownHosts(pubkey)) {
ret = true;
break;
}
std::thread notifymsg([this, &handshake, channelId, &hSession]() {
std::string confirmmsg = "[E000002]:The device unauthorized.\r\n"\
"This server's public key is not set.\r\n"\
"Please check for a confirmation dialog on your device.\r\n"\
"Otherwise try 'hdc kill' if that seems wrong.";
this->HandleAuthFailed(handshake, channelId, hSession, confirmmsg);
});
notifymsg.detach();
UserPermit permit = PostUIConfirm(hostname, pubkey);
if (permit == ALLOWONCE) {
WRITE_LOG(LOG_FATAL, "user allow onece for %s", sessionIdMaskStr.c_str());
ret = true;
} else if (permit == ALLOWFORVER) {
WRITE_LOG(LOG_FATAL, "user allow forever for %s", sessionIdMaskStr.c_str());
UpdateKnownHosts(pubkey);
ret = true;
} else {
WRITE_LOG(LOG_FATAL, "user refuse for %s", sessionIdMaskStr.c_str());
ret = false;
}
} while (0);
if (ret) {
SendAuthMsg(handshake, channelId, hSession, pubkey);
} else {
string notifymsg = "[E000003]:The device unauthorized.\r\n"\
"The user denied the access for the device.\r\n"\
"Please execute 'hdc kill' and redo your command,\r\n"\
"then check for a confirmation dialog on your device.";
HandleAuthFailed(handshake, channelId, hSession, notifymsg);
}
return true;
}
* tokenSignBase64 is Base64 encode of the signing from server
* token is the source data same of server for signing
*/
bool HdcDaemon::RsaSignVerify(HSession hSession, EVP_PKEY_CTX *ctx, const string &tokenSignBase64, const string &token)
{
unsigned char tokenSha512[SHA512_DIGEST_LENGTH];
std::string sessionIdMaskStr = Hdc::MaskSessionIdToString(hSession->sessionId);
try {
const int scaleOfEncrypt = 4;
const int scaleOfDecrypt = 3;
const int base64BlockSize = 4;
if (tokenSignBase64.empty() || tokenSignBase64.length() % base64BlockSize != 0) {
WRITE_LOG(LOG_FATAL, "Invalid base64 format for session %s", sessionIdMaskStr.c_str());
return false;
}
size_t maxDecodedLen = (tokenSignBase64.length() / scaleOfEncrypt * scaleOfDecrypt);
std::unique_ptr<unsigned char[]> tokenRsaSign = std::make_unique<unsigned char[]>(maxDecodedLen);
int tokenRsaSignLen = EVP_DecodeBlock(tokenRsaSign.get(),
reinterpret_cast<const unsigned char *>(tokenSignBase64.c_str()), tokenSignBase64.length());
if (tokenRsaSignLen <= 0) {
WRITE_LOG(LOG_FATAL, "base64 decode token sign failed for session %s", sessionIdMaskStr.c_str());
return false;
}
SHA512(reinterpret_cast<const unsigned char *>(token.c_str()), token.size(), tokenSha512);
if (EVP_PKEY_verify(ctx, tokenRsaSign.get(), tokenRsaSignLen, tokenSha512, sizeof(tokenSha512)) <= 0) {
WRITE_LOG(LOG_FATAL, "verify failed for session %s", sessionIdMaskStr.c_str());
return false;
}
} catch (std::exception &e) {
WRITE_LOG(LOG_FATAL, "sign verify failed for session %s with exception %s",
sessionIdMaskStr.c_str(), e.what());
return false;
}
WRITE_LOG(LOG_FATAL, "sign verify success for session %s", sessionIdMaskStr.c_str());
return true;
}
bool HdcDaemon::AuthVerifyRsaSign(HSession hSession, const string &tokenSign, const string &token, RSA *rsa)
{
EVP_PKEY *signKey = nullptr;
EVP_PKEY_CTX *ctx = nullptr;
bool signRet = false;
signKey = EVP_PKEY_new();
if (signKey == nullptr) {
WRITE_LOG(LOG_FATAL, "EVP_PKEY_new failed");
return false;
}
do {
if (EVP_PKEY_set1_RSA(signKey, rsa) <= 0) {
WRITE_LOG(LOG_FATAL, "EVP_PKEY_new failed");
break;
}
if (tokenSign.size() > ((size_t)EVP_PKEY_size(signKey) * (size_t)2)) {
WRITE_LOG(LOG_FATAL, "invalid base64 sign size %zd for session %s", tokenSign.size(),
Hdc::MaskSessionIdToString(hSession->sessionId).c_str());
break;
}
ctx = EVP_PKEY_CTX_new(signKey, nullptr);
if (ctx == nullptr) {
WRITE_LOG(LOG_FATAL, "EVP_PKEY_CTX_new failed");
break;
}
if (EVP_PKEY_verify_init(ctx) <= 0) {
WRITE_LOG(LOG_FATAL, "EVP_PKEY_CTX_new failed");
break;
}
if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PSS_PADDING) <= 0 ||
EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, RSA_PSS_SALTLEN_AUTO) <= 0) {
WRITE_LOG(LOG_FATAL, "set saltlen or padding failed");
break;
}
if (EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha512()) <= 0) {
WRITE_LOG(LOG_FATAL, "EVP_PKEY_CTX_set_signature_md failed");
break;
}
signRet = RsaSignVerify(hSession, ctx, tokenSign, token);
} while (0);
if (ctx != nullptr) {
EVP_PKEY_CTX_free(ctx);
}
if (signKey != nullptr) {
EVP_PKEY_free(signKey);
}
return signRet;
}
bool HdcDaemon::AuthVerify(HSession hSession, const string &encryptToken, const string &token, const string &pubkey)
{
BIO *bio = nullptr;
RSA *rsa = nullptr;
const unsigned char *pubkeyp = reinterpret_cast<const unsigned char *>(pubkey.c_str());
bool verifyResult = false;
std::string sessionIdMaskStr = Hdc::MaskSessionIdToString(hSession->sessionId);
do {
bio = BIO_new(BIO_s_mem());
if (bio == nullptr) {
WRITE_LOG(LOG_FATAL, "bio failed for session %s", sessionIdMaskStr.c_str());
break;
}
int wbytes = BIO_write(bio, pubkeyp, pubkey.length());
if (wbytes != static_cast<int>(pubkey.length())) {
WRITE_LOG(LOG_FATAL, "bio write failed %d for session %s", wbytes, sessionIdMaskStr.c_str());
break;
}
rsa = PEM_read_bio_RSA_PUBKEY(bio, nullptr, nullptr, nullptr);
if (rsa == nullptr) {
WRITE_LOG(LOG_FATAL, "rsa failed for session %s", sessionIdMaskStr.c_str());
break;
}
if (hSession->verifyType == AuthVerifyType::RSA_3072_SHA512) {
verifyResult = AuthVerifyRsaSign(hSession, encryptToken, token, rsa);
} else {
verifyResult = AuthVerifyRsa(hSession, encryptToken, token, rsa);
}
} while (0);
if (bio) {
BIO_free(bio);
}
if (rsa) {
RSA_free(rsa);
}
return verifyResult;
}
bool HdcDaemon::AuthVerifyRsa(HSession hSession, const string &encryptToken, const string &token, RSA *rsa)
{
const unsigned char *tokenp = reinterpret_cast<const unsigned char *>(encryptToken.c_str());
unsigned char tokenDecode[BUF_SIZE_DEFAULT] = { 0 };
unsigned char decryptToken[BUF_SIZE_DEFAULT] = { 0 };
const int scaleOfEncrypt = 4;
const int scaleOfDecode = 3;
if (encryptToken.length() > BUF_SIZE_DEFAULT / scaleOfDecode * scaleOfEncrypt) {
WRITE_LOG(LOG_FATAL, "invalid encryptToken, length is %zd", encryptToken.length());
return false;
}
int tbytes = EVP_DecodeBlock(tokenDecode, tokenp, encryptToken.length());
if (tbytes <= 0) {
WRITE_LOG(LOG_FATAL, "base64 decode pubkey failed");
return false;
}
int bytes = RSA_public_decrypt(tbytes, tokenDecode, decryptToken, rsa, RSA_PKCS1_PADDING);
if (bytes < 0) {
WRITE_LOG(LOG_FATAL, "decrypt failed(%lu) for session %s", ERR_get_error(),
Hdc::MaskSessionIdToString(hSession->sessionId).c_str());
return false;
}
string sdecryptToken(reinterpret_cast<const char *>(decryptToken), bytes);
if (sdecryptToken != token) {
WRITE_LOG(LOG_FATAL, "auth failed for session %s)",
Hdc::MaskSessionIdToString(hSession->sessionId).c_str());
return false;
}
return true;
}
bool HdcDaemon::HandDaemonAuthSignature(HSession hSession, const uint32_t channelId, SessionHandShake &handshake)
{
string token = GetSessionAuthToken(hSession->sessionId);
string pubkey = GetSessionAuthPubkey(hSession->sessionId);
if (!AuthVerify(hSession, handshake.buf, token, pubkey)) {
WRITE_LOG(LOG_FATAL, "auth failed for session %s",
Hdc::MaskSessionIdToString(hSession->sessionId).c_str());
HandleAuthFailed(handshake, channelId, hSession, "[E000010]:Auth failed, cannt login the device.");
return true;
}
WRITE_LOG(LOG_FATAL, "auth success for session %s",
Hdc::MaskSessionIdToString(hSession->sessionId).c_str());
UpdateSessionAuthOk(hSession->sessionId);
SendAuthOkMsg(handshake, channelId, hSession);
return true;
}
bool HdcDaemon::HandDaemonAuthBypass(void)
{
string authbypass;
SystemDepend::GetDevItem("persist.hdc.auth_bypass", authbypass);
return Base::Trim(authbypass) == "1";
}
bool HdcDaemon::HandDaemonAuth(HSession hSession, const uint32_t channelId, SessionHandShake &handshake)
{
int connectValidationStatus = HdcValidation::GetConnectValidationParam();
bool connectstatus = (connectValidationStatus == VALIDATION_HDC_DAEMON
|| connectValidationStatus == VALIDATION_HDC_HOST_AND_DAEMON);
if (!connectstatus && !authEnable) {
WRITE_LOG(LOG_INFO, "not enable secure, allow access for %s",
Hdc::MaskSessionIdToString(hSession->sessionId).c_str());
UpdateSessionAuthOk(hSession->sessionId);
SendAuthOkMsg(handshake, channelId, hSession);
return true;
} else if (handshake.version < "Ver: 3.0.0b") {
WRITE_LOG(LOG_INFO, "session %s client version %s is too low,authType %d",
Hdc::MaskSessionIdToString(hSession->sessionId).c_str(),
handshake.version.c_str(), handshake.authType);
AuthRejectLowClient(handshake, channelId, hSession);
return true;
} else if (connectstatus && !hSession->supportConnValidation) {
WRITE_LOG(LOG_INFO, "session %s client is not support connect validation",
Hdc::MaskSessionIdToString(hSession->sessionId).c_str());
AuthRejectNotSupportConnValidation(handshake, channelId, hSession);
return true;
} else if (GetSessionAuthStatus(hSession->sessionId) == AUTH_OK) {
WRITE_LOG(LOG_INFO, "session %u already auth ok", hSession->sessionId);
return true;
}
if (handshake.authType == AUTH_NONE) {
return HandDaemonAuthInit(hSession, channelId, handshake);
} else if (GetSessionAuthStatus(hSession->sessionId) == AUTH_NONE
&& GetSessionAuthToken(hSession->sessionId).size() > 0
&& handshake.authType == AUTH_PUBLICKEY) {
return HandDaemonAuthPubkey(hSession, channelId, handshake);
} else if (GetSessionAuthStatus(hSession->sessionId) == AUTH_PUBLICKEY && handshake.authType == AUTH_SIGNATURE) {
return HandDaemonAuthSignature(hSession, channelId, handshake);
#ifdef HDC_SUPPORT_ENCRYPT_TCP
} else if (GetSessionAuthStatus(hSession->sessionId) == AUTH_PUBLICKEY && handshake.authType == AUTH_SSL_TLS_PSK) {
return DaemonSSLHandshake(hSession, channelId, handshake);
#endif
} else {
WRITE_LOG(LOG_FATAL, "invalid auth state %d for session %s", handshake.authType,
Hdc::MaskSessionIdToString(hSession->sessionId).c_str());
return false;
}
}
* For daemon, if server add new capability, we can parse it here
*/
void HdcDaemon::GetServerCapability(HSession &hSession, SessionHandShake &handshake)
{
* Check if server support RSA_3072_SHA512 for auth
* if the value not contain RSA_3072_SHA512, We treat it not support
*/
std::map<string, string> tlvMap;
hSession->verifyType = AuthVerifyType::RSA_ENCRYPT;
if (!Base::TlvToStringMap(handshake.buf, tlvMap)) {
WRITE_LOG(LOG_INFO, "maybe old version client for %s session",
Hdc::MaskSessionIdToString(hSession->sessionId).c_str());
return;
}
auto it = tlvMap.find(TAG_AUTH_TYPE);
if (it != tlvMap.end() && it->second == std::to_string(AuthVerifyType::RSA_3072_SHA512)) {
hSession->verifyType = AuthVerifyType::RSA_3072_SHA512;
}
WRITE_LOG(LOG_INFO, "client auth type is %u for %s session", hSession->verifyType,
Hdc::MaskSessionIdToString(hSession->sessionId).c_str());
ParsePeerSupportFeatures(hSession, tlvMap);
}
void HdcDaemon::DaemonSessionHandshakeInit(HSession &hSession, SessionHandShake &handshake)
{
uint32_t unOld = hSession->sessionId;
hSession->sessionId = handshake.sessionId;
hSession->connectKey = handshake.connectKey;
hSession->handshakeOK = false;
AdminSession(OP_UPDATE, unOld, hSession);
#ifdef HDC_SUPPORT_UART
if (hSession->connType == CONN_SERIAL and clsUARTServ!= nullptr) {
WRITE_LOG(LOG_DEBUG, " HdcDaemon::DaemonSessionHandshake %s",
handshake.ToDebugString().c_str());
if (clsUARTServ != nullptr) {
(static_cast<HdcDaemonUART *>(clsUARTServ))->OnNewHandshakeOK(hSession->sessionId);
}
} else
#endif
if (clsUSBServ != nullptr && hSession->connType == CONN_USB) {
(reinterpret_cast<HdcDaemonUSB *>(clsUSBServ))->OnNewHandshakeOK(hSession->sessionId);
}
handshake.sessionId = 0;
handshake.connectKey = "";
GetServerCapability(hSession, handshake);
}
#ifdef HDC_SUPPORT_ENCRYPT_TCP
bool HdcDaemon::DaemonSSLHandshake(HSession hSession, const uint32_t channelId, SessionHandShake &handshake)
{
uint8_t *payload = reinterpret_cast<uint8_t*>(handshake.buf.data());
int payloadSize = static_cast<int>(handshake.buf.size());
if (!hSession->classSSL) {
WRITE_LOG(LOG_WARN, "DaemonSSLHandshake classSSL is nullptr");
return false;
}
HdcSSLBase *hssl = static_cast<HdcSSLBase *>(hSession->classSSL);
if (!hssl) {
WRITE_LOG(LOG_WARN, "hssl is null");
return false;
}
if (payloadSize > 0) {
int retw = hssl->DoBIOWrite(payload, payloadSize);
if (retw != payloadSize) {
WRITE_LOG(LOG_WARN, "BIO_write failed, payloadsize is %d", payloadSize);
return false;
}
}
vector<uint8_t> buf;
int ret = hssl->PerformHandshake(buf);
if (ret == RET_SUCCESS) {
if (buf.size() == 0) {
WRITE_LOG(LOG_WARN, "SSL PerformHandshake failed, buffer data size is 0");
return false;
}
handshake.buf.assign(buf.begin(), buf.end());
string bufString = SerialStruct::SerializeToString(handshake);
Send(hSession->sessionId, channelId, CMD_KERNEL_HANDSHAKE,
reinterpret_cast<uint8_t *>(const_cast<char *>(bufString.c_str())), bufString.size());
}
if (hssl->SetHandshakeLabel(hSession)) {
std::this_thread::sleep_for(std::chrono::milliseconds(SSL_HANDSHAKE_FINISHED_WAIT_TIME));
UpdateSessionAuthOk(hSession->sessionId);
SendAuthOkMsg(handshake, channelId, hSession);
if (!hssl->ClearPsk()) {
WRITE_LOG(LOG_WARN, "clear Pre Shared Key failed");
ret = ERR_GENERIC;
}
}
fill(buf.begin(), buf.end(), 0);
return ret == RET_SUCCESS;
}
#endif
bool HdcDaemon::DaemonSessionHandshake(HSession hSession, const uint32_t channelId, uint8_t *payload, int payloadSize)
{
StartTraceScope("HdcDaemon::DaemonSessionHandshake");
string s = string(reinterpret_cast<char *>(payload), payloadSize);
SessionHandShake handshake;
std::string sessionIdMaskStr = Hdc::MaskSessionIdToString(hSession->sessionId);
SerialStruct::ParseFromString(handshake, s);
#ifdef HDC_DEBUG
WRITE_LOG(LOG_DEBUG, "session %s try to handshake", hSession->ToDebugString().c_str());
#endif
if (handshake.banner != HANDSHAKE_MESSAGE) {
hSession->availTailIndex = 0;
WRITE_LOG(LOG_FATAL, "Recv server-hello failed");
return false;
}
if (handshake.authType == AUTH_NONE) {
if (GetSessionAuthStatus(handshake.sessionId) != AUTH_NONE) {
WRITE_LOG(LOG_FATAL, "session %s is already, But now session is %s, refused!",
Hdc::MaskSessionIdToString(handshake.sessionId).c_str(), sessionIdMaskStr.c_str());
return false;
}
DaemonSessionHandshakeInit(hSession, handshake);
}
if (!HandDaemonAuth(hSession, channelId, handshake)) {
WRITE_LOG(LOG_FATAL, "auth failed");
return false;
}
string version = Base::GetVersion() + HDC_MSG_HASH;
WRITE_LOG(LOG_DEBUG, "receive hs version = %s", handshake.version.c_str());
if (!handshake.version.empty() && handshake.version != version) {
WRITE_LOG(LOG_FATAL, "DaemonSessionHandshake failed! version not match [%s] vs [%s]",
handshake.version.c_str(), version.c_str());
#ifdef HDC_CHECK_CHECK
hSession->availTailIndex = 0;
handshake.banner = HANDSHAKE_FAILED;
string failedString = SerialStruct::SerializeToString(handshake);
Send(hSession->sessionId, channelId, CMD_KERNEL_HANDSHAKE, (uint8_t *)failedString.c_str(),
failedString.size());
return false;
#endif
}
if (handshake.version.empty()) {
handshake.version = Base::GetVersion();
WRITE_LOG(LOG_FATAL, "set version if check mode = %s", handshake.version.c_str());
}
#ifdef HDC_DEBUG
WRITE_LOG(LOG_INFO, "session %s handshakeOK send back CMD_KERNEL_HANDSHAKE", sessionIdMaskStr.c_str());
#endif
return true;
}
bool HdcDaemon::IsExpectedParam(const string& param, const string& expect)
{
string out;
SystemDepend::GetDevItem(param.c_str(), out);
return (out.empty() || out == expect);
}
bool HdcDaemon::CheckControl(const uint16_t command)
{
bool ret = false;
switch (command) {
case CMD_UNITY_EXECUTE:
case CMD_UNITY_EXECUTE_EX:
case CMD_UNITY_REMOUNT:
case CMD_UNITY_REBOOT:
case CMD_UNITY_RUNMODE:
case CMD_UNITY_HILOG:
case CMD_UNITY_ROOTRUN:
case CMD_UNITY_BUGREPORT_INIT:
case CMD_JDWP_LIST:
case CMD_JDWP_TRACK:
case CMD_SHELL_INIT:
case CMD_SHELL_DATA: {
ret = IsExpectedParam("persist.hdc.control.shell", "true");
break;
}
case CMD_FILE_CHECK:
case CMD_FILE_DATA:
case CMD_FILE_FINISH:
case CMD_FILE_INIT:
case CMD_FILE_BEGIN:
case CMD_FILE_MODE:
case CMD_DIR_MODE:
case CMD_APP_CHECK:
case CMD_APP_DATA:
case CMD_APP_UNINSTALL: {
ret = IsExpectedParam("persist.hdc.control.file", "true");
break;
}
case CMD_FORWARD_INIT:
case CMD_FORWARD_CHECK:
case CMD_FORWARD_ACTIVE_MASTER:
case CMD_FORWARD_ACTIVE_SLAVE:
case CMD_FORWARD_DATA:
case CMD_FORWARD_FREE_CONTEXT:
case CMD_FORWARD_CHECK_RESULT: {
ret = IsExpectedParam("persist.hdc.control.fport", "true");
break;
}
default:
ret = true;
}
return ret;
}
bool HdcDaemon::CheckAuthStatus(HSession hSession, const uint32_t channelId, const uint16_t command)
{
if (authEnable && (GetSessionAuthStatus(hSession->sessionId) != AUTH_OK) &&
command != CMD_KERNEL_HANDSHAKE && command != CMD_KERNEL_CHANNEL_CLOSE && command != CMD_SSL_HANDSHAKE) {
string authmsg = GetSessionAuthmsg(hSession->sessionId);
WRITE_LOG(LOG_WARN, "session %s auth failed: %s for command %u",
Hdc::MaskSessionIdToString(hSession->sessionId).c_str(), authmsg.c_str(), command);
if (!authmsg.empty()) {
LogMsg(hSession->sessionId, channelId, MSG_FAIL, authmsg.c_str());
}
uint8_t count = 1;
Send(hSession->sessionId, channelId, CMD_KERNEL_CHANNEL_CLOSE, &count, 1);
return false;
}
return true;
}
static std::map<uint16_t, std::string> DaemonReportMap = {
{HdcCommand::CMD_UNITY_EXECUTE, CMDSTR_SHELL},
{HdcCommand::CMD_UNITY_EXECUTE_EX, CMDSTR_SHELL},
{HdcCommand::CMD_KERNEL_TARGET_CONNECT, CMDSTR_CONNECT_TARGET},
{HdcCommand::CMD_SHELL_INIT, CMDSTR_SHELL},
{HdcCommand::CMD_UNITY_RUNMODE, CMDSTR_TARGET_MODE},
{HdcCommand::CMD_APP_CHECK, CMDSTR_APP_INSTALL},
{HdcCommand::CMD_APP_UNINSTALL, CMDSTR_APP_UNINSTALL},
{HdcCommand::CMD_FORWARD_INIT, CMDSTR_FORWARD_RPORT},
{HdcCommand::CMD_UNITY_HILOG, CMDSTR_HILOG},
{HdcCommand::CMD_JDWP_LIST, CMDSTR_LIST_JDWP},
{HdcCommand::CMD_JDWP_TRACK, CMDSTR_TRACK_JDWP},
{HdcCommand::CMD_UNITY_REMOUNT, CMDSTR_TARGET_MOUNT},
{HdcCommand::CMD_UNITY_REBOOT, CMDSTR_TARGET_REBOOT},
{HdcCommand::CMD_UNITY_BUGREPORT_INIT, CMDSTR_BUGREPORT},
};
#ifdef HDC_SUPPORT_REPORT_COMMAND_EVENT
static std::string GetReportInfo(const uint16_t command, uint8_t *payload, const int payloadSize)
{
std::string info;
info = std::string(reinterpret_cast<char *>(payload), payloadSize);
switch (command) {
case CMD_APP_CHECK: {
std::string bufString(reinterpret_cast<char *>(payload), payloadSize);
HdcTransferBase::TransferConfig transferConfig;
SerialStruct::ParseFromString(transferConfig, bufString);
info = transferConfig.path + transferConfig.optionalName;
break;
}
case CMD_UNITY_EXECUTE_EX: {
TlvBuf tlvbuf(const_cast<uint8_t *>(payload), payloadSize, Base::REGISTERD_TAG_SET);
if (tlvbuf.ContainInvalidTag()) {
break;
}
std::string bundleName = "";
std::string command = "";
if (tlvbuf.FindTlv(TAG_SHELL_BUNDLE, bundleName)) {
info += "-b " + bundleName;
}
if (tlvbuf.FindTlv(TAG_SHELL_CMD, command)) {
info += " " + command;
}
break;
}
}
return info;
}
#endif
static bool ReportCommandEvent(const uint16_t command, uint8_t *payload, const int payloadSize, bool isIntercepted)
{
#ifdef HDC_SUPPORT_REPORT_COMMAND_EVENT
auto it = Hdc::DaemonReportMap.find(command);
if (it == Hdc::DaemonReportMap.end()) {
return true;
}
if (it->second == "") {
return true;
}
std::string reportInfo = GetReportInfo(command, payload, payloadSize);
if (!DelayedSingleton<CommandEventReport>::GetInstance()->ReportCommandEvent(
it->second + " " + reportInfo, Base::GetCaller(), isIntercepted, it->second)) {
WRITE_LOG(LOG_FATAL,
"[E00C002]Execution intercepted due to inaccessibility of reporting command event.");
return false;
}
#endif
return true;
}
static const std::unordered_map<uint16_t, STATISTIC_ITEM> commandToReportItem = {
{CMD_UNITY_EXECUTE, STATISTIC_ITEM::SHELL_COUNT},
{CMD_UNITY_EXECUTE_EX, STATISTIC_ITEM::SHELL_COUNT},
{CMD_SHELL_INIT, STATISTIC_ITEM::INTERACT_SHELL_COUNT},
{CMD_APP_CHECK, STATISTIC_ITEM::INSTALL_COUNT},
{CMD_APP_UNINSTALL, STATISTIC_ITEM::UNINSTALL_COUNT},
{CMD_FILE_CHECK, STATISTIC_ITEM::FILE_SEND_COUNT},
{CMD_FILE_INIT, STATISTIC_ITEM::FILE_RECV_COUNT},
{CMD_FORWARD_CHECK, STATISTIC_ITEM::FPORT_COUNT},
{CMD_FORWARD_INIT, STATISTIC_ITEM::RPORT_COUNT},
{CMD_UNITY_HILOG, STATISTIC_ITEM::HILOG_COUNT},
{CMD_JDWP_LIST, STATISTIC_ITEM::JPID_COUNT},
{CMD_JDWP_TRACK, STATISTIC_ITEM::TRACK_JPID_COUNT}
};
void HdcDaemon::HandleCommandReport(const uint16_t command)
{
auto it = commandToReportItem.find(command);
if (it != commandToReportItem.end()) {
HdcStatisticReporter::GetInstance().IncrCommandInfo(it->second);
}
}
bool HdcDaemon::FetchCommand(HSession hSession, const uint32_t channelId, const uint16_t command, uint8_t *payload,
const int payloadSize)
{
StartTraceScope("HdcDaemon::FetchCommand");
bool isNotIntercepted = CheckControl(command);
if (!ReportCommandEvent(command, payload, payloadSize, !isNotIntercepted)) {
std::string msg = "[E00C002]Execution intercepted due to inaccessibility of reporting command event.";
LogMsg(hSession->sessionId, channelId, MSG_FAIL, msg.c_str());
return false;
}
bool ret = true;
if (!CheckAuthStatus(hSession, channelId, command)) {
return true;
}
if (command != CMD_UNITY_BUGREPORT_DATA && command != CMD_SHELL_DATA &&
command != CMD_FORWARD_DATA && command != CMD_FILE_DATA && command != CMD_APP_DATA) {
WRITE_LOG(LOG_DEBUG, "FetchCommand channelId:%u command:%u", channelId, command);
}
switch (command) {
case CMD_KERNEL_HANDSHAKE: {
ret = DaemonSessionHandshake(hSession, channelId, payload, payloadSize);
break;
}
case CMD_KERNEL_CHANNEL_CLOSE: {
ClearOwnTasks(hSession, channelId);
if (payloadSize >= 1 && *payload != 0) {
--(*payload);
Send(hSession->sessionId, channelId, CMD_KERNEL_CHANNEL_CLOSE, payload, 1);
}
ret = true;
break;
}
case CMD_HEARTBEAT_MSG: {
std::string str = hSession->heartbeat.HandleRecvHeartbeatMsg(payload, payloadSize);
WRITE_LOG(LOG_INFO, "recv %s for session %s", str.c_str(),
Hdc::MaskSessionIdToString(hSession->sessionId).c_str());
break;
}
default:
HandleCommandReport(command);
ret = true;
if (isNotIntercepted) {
ret = DispatchTaskData(hSession, channelId, command, payload, payloadSize);
} else {
LogMsg(hSession->sessionId, channelId, MSG_FAIL, "debugging is not allowed");
uint8_t count = 1;
Send(hSession->sessionId, channelId, CMD_KERNEL_CHANNEL_CLOSE, &count, 1);
}
break;
}
return ret;
}
bool HdcDaemon::RemoveInstanceTask(const uint8_t op, HTaskInfo hTask)
{
bool ret = true;
if (!hTask->taskClass) {
WRITE_LOG(LOG_FATAL, "RemoveInstanceTask taskClass is null channelId:%u", hTask->channelId);
return ret;
}
switch (hTask->taskType) {
case TYPE_UNITY:
ret = DoTaskRemove<HdcDaemonUnity>(hTask, op);
break;
case TYPE_SHELL:
ret = DoTaskRemove<HdcShell>(hTask, op);
break;
case TASK_FILE:
ret = DoTaskRemove<HdcTransferBase>(hTask, op);
break;
case TASK_FORWARD:
ret = DoTaskRemove<HdcDaemonForward>(hTask, op);
break;
case TASK_APP:
ret = DoTaskRemove<HdcDaemonApp>(hTask, op);
break;
default:
ret = false;
break;
}
return ret;
}
bool HdcDaemon::ServerCommand(const uint32_t sessionId, const uint32_t channelId, const uint16_t command,
uint8_t *bufPtr, const int size)
{
return Send(sessionId, channelId, command, reinterpret_cast<uint8_t *>(bufPtr), size) > 0;
}
void HdcDaemon::JdwpNewFileDescriptor(const uint8_t *buf, const int bytesIO)
{
uint8_t spcmd = *const_cast<uint8_t *>(buf);
if (spcmd == SP_JDWP_NEWFD) {
int cnt = sizeof(uint8_t) + sizeof(uint32_t) * 2;
if (bytesIO < cnt) {
WRITE_LOG(LOG_FATAL, "jdwp newfd data insufficient bytesIO:%d", bytesIO);
return;
}
uint32_t pid = *reinterpret_cast<uint32_t *>(const_cast<uint8_t *>(buf + 1));
uint32_t fd = *reinterpret_cast<uint32_t *>(const_cast<uint8_t *>(buf + 5));
((HdcJdwp *)clsJdwp)->SendJdwpNewFD(pid, fd);
} else if (spcmd == SP_ARK_NEWFD) {
int cnt = sizeof(uint8_t) + sizeof(uint32_t);
if (bytesIO < cnt) {
WRITE_LOG(LOG_FATAL, "ark newfd data insufficient bytesIO:%d", bytesIO);
return;
}
int32_t fd = *reinterpret_cast<int32_t *>(const_cast<uint8_t *>(buf + 1));
std::string arkstr = std::string(
reinterpret_cast<char *>(const_cast<uint8_t *>(buf + 5)), bytesIO - 5);
WRITE_LOG(LOG_DEBUG, "JdwpNewFileDescriptor arkstr:%s fd:%d", arkstr.c_str(), fd);
((HdcJdwp *)clsJdwp)->SendArkNewFD(arkstr, fd);
}
}
void HdcDaemon::NotifyInstanceSessionFree(HSession hSession, bool freeOrClear)
{
if (!freeOrClear) {
WRITE_LOG(LOG_WARN, "NotifyInstanceSessionFree freeOrClear false");
return;
}
if (clsUSBServ != nullptr) {
auto clsUsbModule = reinterpret_cast<HdcDaemonUSB *>(clsUSBServ);
clsUsbModule->OnSessionFreeFinally(hSession);
}
}
void HdcDaemon::InitSessionAuthInfo(uint32_t sessionid, string token)
{
HdcDaemonAuthInfo info = {
AUTH_NONE,
token
};
mapAuthStatusMutex.lock();
mapAuthStatus[sessionid] = info;
mapAuthStatusMutex.unlock();
}
void HdcDaemon::UpdateSessionAuthOk(uint32_t sessionid)
{
HdcDaemonAuthInfo info;
mapAuthStatusMutex.lock();
info = mapAuthStatus[sessionid];
info.authtype = AUTH_OK;
info.token = "";
info.pubkey = "";
mapAuthStatus[sessionid] = info;
mapAuthStatusMutex.unlock();
}
void HdcDaemon::UpdateSessionAuthPubkey(uint32_t sessionid, string pubkey)
{
HdcDaemonAuthInfo info;
mapAuthStatusMutex.lock();
info = mapAuthStatus[sessionid];
info.authtype = AUTH_PUBLICKEY;
info.pubkey = pubkey;
mapAuthStatus[sessionid] = info;
mapAuthStatusMutex.unlock();
}
void HdcDaemon::UpdateSessionAuthmsg(uint32_t sessionid, string authmsg)
{
HdcDaemonAuthInfo info;
mapAuthStatusMutex.lock();
info = mapAuthStatus[sessionid];
info.authtype = AUTH_FAIL;
info.authmsg = authmsg;
mapAuthStatus[sessionid] = info;
mapAuthStatusMutex.unlock();
}
void HdcDaemon::DeleteSessionAuthStatus(uint32_t sessionid)
{
mapAuthStatusMutex.lock();
mapAuthStatus.erase(sessionid);
mapAuthStatusMutex.unlock();
}
HdcSessionBase::AuthType HdcDaemon::GetSessionAuthStatus(uint32_t sessionid)
{
HdcDaemonAuthInfo info;
info.authtype = AUTH_NONE;
mapAuthStatusMutex.lock();
if (mapAuthStatus.count(sessionid) > 0) {
info = mapAuthStatus[sessionid];
}
mapAuthStatusMutex.unlock();
return info.authtype;
}
string HdcDaemon::GetSessionAuthToken(uint32_t sessionid)
{
HdcDaemonAuthInfo info;
mapAuthStatusMutex.lock();
if (mapAuthStatus.count(sessionid) > 0) {
info = mapAuthStatus[sessionid];
}
mapAuthStatusMutex.unlock();
return info.token;
}
string HdcDaemon::GetSessionAuthPubkey(uint32_t sessionid)
{
HdcDaemonAuthInfo info;
mapAuthStatusMutex.lock();
if (mapAuthStatus.count(sessionid) > 0) {
info = mapAuthStatus[sessionid];
}
mapAuthStatusMutex.unlock();
return info.pubkey;
}
string HdcDaemon::GetSessionAuthmsg(uint32_t sessionid)
{
HdcDaemonAuthInfo info;
mapAuthStatusMutex.lock();
if (mapAuthStatus.count(sessionid) > 0) {
info = mapAuthStatus[sessionid];
}
mapAuthStatusMutex.unlock();
return info.authmsg;
}
void HdcDaemon::SendAuthOkMsg(SessionHandShake &handshake, uint32_t channelid,
HSession hSession, string msg, string daemonAuthResult)
{
char hostname[BUF_SIZE_MEDIUM] = { 0 };
if (gethostname(hostname, BUF_SIZE_MEDIUM) != 0) {
WRITE_LOG(LOG_FATAL, "get hostname failed %s", strerror(errno));
}
if (handshake.version < "Ver: 3.0.0b") {
if (msg.empty()) {
msg = hostname;
}
handshake.buf = msg;
hSession->handshakeOK = true;
} else {
string emgmsg;
Base::TlvAppend(emgmsg, TAG_EMGMSG, msg);
Base::TlvAppend(emgmsg, TAG_DEVNAME, hostname);
Base::TlvAppend(emgmsg, TAG_DAEOMN_AUTHSTATUS, daemonAuthResult);
int connectValidationStatus = HdcValidation::GetConnectValidationParam();
bool connectstatus = (connectValidationStatus == VALIDATION_HDC_DAEMON
|| connectValidationStatus == VALIDATION_HDC_HOST_AND_DAEMON);
if (!connectstatus || hSession->supportConnValidation) {
AddFeatureTagToEmgmsg(emgmsg);
hSession->handshakeOK = true;
}
handshake.buf = emgmsg;
}
handshake.authType = AUTH_OK;
string bufString = SerialStruct::SerializeToString(handshake);
Send(hSession->sessionId, channelid, CMD_KERNEL_HANDSHAKE,
reinterpret_cast<uint8_t *>(const_cast<char *>(bufString.c_str())), bufString.size());
uint8_t count = 1;
Send(hSession->sessionId, channelid, CMD_KERNEL_CHANNEL_CLOSE, &count, 1);
}
void HdcDaemon::SendAuthSignMsg(SessionHandShake &handshake,
uint32_t channelId, uint32_t sessionid, string pubkey, string token)
{
UpdateSessionAuthPubkey(sessionid, pubkey);
handshake.authType = AUTH_SIGNATURE;
handshake.buf = token;
string bufString = SerialStruct::SerializeToString(handshake);
Send(sessionid, channelId, CMD_KERNEL_HANDSHAKE,
reinterpret_cast<uint8_t *>(const_cast<char *>(bufString.c_str())), bufString.size());
}
void HdcDaemon::SendAuthMsg(SessionHandShake &handshake, const uint32_t channelId,
HSession &hSession, string pubkey)
{
#ifdef HDC_SUPPORT_ENCRYPT_TCP
if (hSession->connType == CONN_TCP && hSession->supportEncrypt) {
SendAuthEncryptPsk(handshake, channelId, hSession, pubkey);
return;
}
#endif
SendAuthSignMsg(handshake, channelId, hSession->sessionId, pubkey, hSession->tokenRSA);
}
#ifdef HDC_SUPPORT_ENCRYPT_TCP
void HdcDaemon::SendAuthEncryptPsk(SessionHandShake &handshake, const uint32_t channelId,
HSession &hSession, string pubkey)
{
UpdateSessionAuthPubkey(hSession->sessionId, pubkey);
handshake.authType = AUTH_SSL_TLS_PSK;
if (!hSession->classSSL) {
SSLInfoPtr hSSLInfo = new (std::nothrow) HdcSSLInfo();
if (!hSSLInfo) {
WRITE_LOG(LOG_FATAL, "SendAuthEncryptPsk new HdcSSLInfo failed");
return;
}
HdcSSLBase::SetSSLInfo(hSSLInfo, hSession);
hSession->classSSL = new (std::nothrow) HdcDaemonSSL(hSSLInfo);
delete hSSLInfo;
if (!hSession->classSSL) {
WRITE_LOG(LOG_FATAL, "SendAuthEncryptPsk new HdcDaemonSSL failed");
return;
}
}
HdcSSLBase *hssl = static_cast<HdcSSLBase *>(hSession->classSSL);
if (!hssl) {
WRITE_LOG(LOG_WARN, "hssl is null");
return;
}
if (!hssl->GenPsk()) {
WRITE_LOG(LOG_WARN, "gen psk failed");
return;
}
std::unique_ptr<unsigned char[]> payload(std::make_unique<unsigned char[]>(BUF_SIZE_DEFAULT2));
int payloadSize = hssl->GetPskEncrypt(payload.get(), BUF_SIZE_DEFAULT2, pubkey);
if (payloadSize <= 0) {
WRITE_LOG(LOG_WARN, "RsaPubkeyEncrpt failed");
return;
}
handshake.buf = string(reinterpret_cast<const char*>(payload.get()), payloadSize);
string bufString = SerialStruct::SerializeToString(handshake);
Send(hSession->sessionId, channelId, CMD_KERNEL_HANDSHAKE,
reinterpret_cast<uint8_t *>(const_cast<char *>(bufString.c_str())), bufString.size());
hssl->InitSSL();
}
#endif
void HdcDaemon::HandleAuthFailed(SessionHandShake &handshake, uint32_t channelid, HSession hSession, string msg)
{
SendAuthOkMsg(handshake, channelid, hSession, msg, DAEOMN_UNAUTHORIZED);
LogMsg(hSession->sessionId, channelid, MSG_FAIL, msg.c_str());
UpdateSessionAuthmsg(hSession->sessionId, msg);
}
void HdcDaemon::AuthRejectLowClient(SessionHandShake &handshake, uint32_t channelid, HSession hSession)
{
string msg = "[E000001]:The sdk hdc.exe version is too low, please upgrade to the latest version.";
HandleAuthFailed(handshake, channelid, hSession, msg);
}
void HdcDaemon::AddFeatureTagToEmgmsg(string &emgmsg)
{
Base::TlvAppend(emgmsg, TAG_FEATURE_SHELL_OPT, "enable");
Base::TlvAppend(emgmsg, TAG_SUPPORT_FEATURE, Base::FeatureToString(Base::GetSupportFeature()));
}
void HdcDaemon::AuthRejectNotSupportConnValidation(SessionHandShake &handshake, uint32_t channelid, HSession hSession)
{
string msg = "[E000006]:The current computer has not obtained the permission to debug the control device.";
HandleAuthFailed(handshake, channelid, hSession, msg);
}
}