* 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 "pkg_upgradefile.h"
#include <cerrno>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <limits>
#include <memory>
#include "dump.h"
#include "log/log.h"
#include "openssl_util.h"
#include "pkg_verify_util.h"
#include "pkg_lz4file.h"
#include "pkg_manager.h"
#include "pkg_pkgfile.h"
#include "pkg_stream.h"
#include "pkg_utils.h"
#include "pkg_zipfile.h"
#include "securec.h"
#include "utils.h"
#include "updater/updater_const.h"
#define TLV_CHECK_AND_RETURN(tlv, tlvType, len, fileLen) \
do { \
if (!((tlv)->length < (fileLen) && (tlv)->length >= (len) && (tlv)->type == (tlvType) && \
((tlv)->length + sizeof(PkgTlv)) < (fileLen))) { \
PKG_LOGE("Invalid tlv type: %d length %u ", tlvType, ((tlv)->length)); \
return PKG_INVALID_FILE; \
} \
} while (0)
using namespace std;
namespace Hpackage {
constexpr int32_t UPGRADE_FILE_HEADER_LEN = 3 * sizeof(PkgTlv) + sizeof(UpgradePkgHeader) + sizeof(UpgradePkgTime);
constexpr int32_t UPGRADE_FILE_BASIC_LEN = 2 * sizeof(PkgTlv) + sizeof(UpgradePkgHeader) + sizeof(UpgradePkgTime);
constexpr int32_t HASH_TLV_SIZE = 6;
constexpr int16_t TLV_TYPE_FOR_HASH_HEADER = 0x0006;
constexpr int16_t TLV_TYPE_FOR_HASH_DATA = 0x0007;
constexpr int16_t TLV_TYPE_FOR_SIGN = 0x0008;
constexpr int32_t UPGRADE_RESERVE_LEN = 16;
constexpr int16_t TLV_TYPE_FOR_SHA256 = 0x0001;
constexpr int16_t TLV_TYPE_FOR_SHA384 = 0x0011;
constexpr size_t BUFFER_SIZE = 4 * 1024 * 1024;
using ChunkListInfoTlv = ChunkTlv<uint16_t, uint32_t, 0x10>;
using ParitionNumChunkTlv = ChunkTlv<uint16_t, uint16_t, 0x16>;
using HashParitionChunkTlv = ChunkTlv<uint16_t, uint16_t, 0x17>;
using ImageHashChunkTlv = ChunkTlv<uint16_t, uint16_t, 0x18>;
using ImageSizeChunkTlv = ChunkTlv<uint16_t, uint16_t, 0x19>;
using ParitionNameChunkTlv = ChunkTlv<uint16_t, uint16_t, 0x20>;
int32_t UpgradeFileEntry::Init(const PkgManager::FileInfoPtr fileInfo, PkgStreamPtr inStream)
{
int32_t ret = PkgEntry::Init(&fileInfo_.fileInfo, fileInfo, inStream);
if (ret != PKG_SUCCESS) {
PKG_LOGE("Fail to check input param");
return PKG_INVALID_PARAM;
}
ComponentInfo *info = (ComponentInfo *)fileInfo;
if (info != nullptr) {
fileInfo_.version = info->version;
fileInfo_.id = info->id;
fileInfo_.resType = info->resType;
fileInfo_.type = info->type;
fileInfo_.compFlags = info->compFlags;
fileInfo_.originalSize = info->originalSize;
if (memcpy_s(fileInfo_.digest, sizeof(fileInfo_.digest), info->digest, sizeof(info->digest)) != EOK) {
PKG_LOGE("UpgradeFileEntry memcpy failed");
return PKG_NONE_MEMORY;
}
}
return PKG_SUCCESS;
}
size_t UpgradePkgFile::GetUpgradeSignatureLen() const
{
return SIGN_SHA256_LEN + SIGN_SHA384_LEN;
}
size_t UpgradePkgFile::GetDigestLen() const
{
return DigestAlgorithm::GetDigestLen(pkgInfo_.pkgInfo.digestMethod);
}
int32_t UpgradePkgFile::GetEntryOffset(size_t &dataOffset, const PkgManager::FileInfoPtr file)
{
if (!CheckState({PKG_FILE_STATE_IDLE, PKG_FILE_STATE_WORKING}, PKG_FILE_STATE_WORKING)) {
PKG_LOGE("error state curr %d ", state_);
return PKG_INVALID_STATE;
}
if (pkgEntryMapId_.size() >= pkgInfo_.pkgInfo.entryCount) {
PKG_LOGE("More entry for and for %s %zu", file->identity.c_str(), pkgEntryMapId_.size());
return PKG_INVALID_PARAM;
}
PKG_LOGI("Add file %s to package", file->identity.c_str());
size_t compDataLen = 0;
for (auto &it : pkgEntryMapId_) {
compDataLen += (*it.second).GetFileInfo()->packedSize;
}
dataOffset = UPGRADE_FILE_HEADER_LEN + pkgInfo_.pkgInfo.entryCount * sizeof(UpgradeCompInfo);
dataOffset += UPGRADE_RESERVE_LEN + GetUpgradeSignatureLen();
dataOffset += compDataLen;
return PKG_SUCCESS;
}
int32_t UpgradePkgFile::AddEntry(const PkgManager::FileInfoPtr file, const PkgStreamPtr inStream)
{
if (file == nullptr || inStream == nullptr) {
PKG_LOGE("Fail to check input param");
return PKG_INVALID_PARAM;
}
size_t dataOffset = 0;
int32_t ret = GetEntryOffset(dataOffset, file);
if (ret != PKG_SUCCESS) {
PKG_LOGE("Fail to GetEntryOffset");
return ret;
}
UpgradeFileEntry *entry = static_cast<UpgradeFileEntry *>(AddPkgEntry(file->identity));
if (entry == nullptr) {
PKG_LOGE("Fail create pkg node for %s", file->identity.c_str());
return PKG_NONE_MEMORY;
}
ret = entry->Init(file, inStream);
if (ret != PKG_SUCCESS) {
PKG_LOGE("Fail init entry for %s", file->identity.c_str());
return ret;
}
size_t encodeLen = 0;
ret = entry->Pack(inStream, dataOffset, encodeLen);
if (ret != PKG_SUCCESS) {
PKG_LOGE("Fail Pack for %s", file->identity.c_str());
return ret;
}
packedFileSize_ += encodeLen;
size_t offset = UPGRADE_FILE_HEADER_LEN + (pkgEntryMapId_.size() - 1) * sizeof(UpgradeCompInfo);
ret = entry->EncodeHeader(inStream, offset, encodeLen);
if (ret != PKG_SUCCESS) {
PKG_LOGE("Fail encode header for %s", file->identity.c_str());
return ret;
}
PKG_LOGI("Header offset:%zu data offset:%zu packedFileSize: %zu", offset, dataOffset, packedFileSize_);
return PKG_SUCCESS;
}
int32_t UpgradePkgFile::CheckPackageHeader(std::vector<uint8_t> &buffer, size_t &offset)
{
if (!CheckState({PKG_FILE_STATE_WORKING}, PKG_FILE_STATE_CLOSE)) {
PKG_LOGE("error state curr %d ", state_);
return PKG_INVALID_STATE;
}
WriteLE16(buffer.data(), GetPackageTlvType());
WriteLE16(buffer.data() + sizeof(uint16_t), sizeof(UpgradePkgHeader));
offset += sizeof(PkgTlv);
UpgradePkgHeader *header = reinterpret_cast<UpgradePkgHeader *>(buffer.data() + offset);
if (header == nullptr) {
PKG_LOGE("Fail to create header");
return PKG_NONE_MEMORY;
}
header->pkgInfoLength = sizeof(PkgTlv) + sizeof(PkgTlv) + sizeof(PkgTlv) + sizeof(UpgradePkgHeader) +
sizeof(UpgradePkgTime) + pkgInfo_.pkgInfo.entryCount * sizeof(UpgradeCompInfo) + UPGRADE_RESERVE_LEN;
WriteLE32(reinterpret_cast<uint8_t *>(&header->updateFileVersion), pkgInfo_.updateFileVersion);
int32_t ret = memcpy_s(header->softwareVersion, sizeof(header->softwareVersion), pkgInfo_.softwareVersion.data(),
pkgInfo_.softwareVersion.size());
if (ret != EOK) {
PKG_LOGE("Fail to memcpy_s %s ret: %d", pkgStream_->GetFileName().c_str(), ret);
return ret;
}
ret = memcpy_s(header->productUpdateId, sizeof(header->productUpdateId), pkgInfo_.productUpdateId.data(),
pkgInfo_.productUpdateId.size());
if (ret != EOK) {
PKG_LOGE("Fail to memcpy_s %s ret: %d", pkgStream_->GetFileName().c_str(), ret);
return ret;
}
offset += sizeof(UpgradePkgHeader);
WriteLE16(buffer.data() + offset, 0x02);
WriteLE16(buffer.data() + offset + sizeof(uint16_t), sizeof(UpgradePkgTime));
offset += sizeof(PkgTlv);
return PKG_SUCCESS;
}
int32_t UpgradePkgFile::WriteBuffer(std::vector<uint8_t> &buffer, size_t &offset, size_t &signOffset)
{
offset += pkgInfo_.pkgInfo.entryCount * sizeof(UpgradeCompInfo);
signOffset = offset + UPGRADE_RESERVE_LEN;
buffer.assign(buffer.capacity(), 0);
size_t nameLen = 0;
int32_t ret = PkgFileImpl::ConvertStringToBuffer(
pkgInfo_.descriptPackageId, {buffer.data(), UPGRADE_RESERVE_LEN}, nameLen);
if (ret != PKG_SUCCESS) {
PKG_LOGE("Fail write descriptPackageId");
return ret;
}
ret = pkgStream_->Write(buffer, GetUpgradeSignatureLen() + UPGRADE_RESERVE_LEN, offset);
if (ret != PKG_SUCCESS) {
PKG_LOGE("Fail write sign for %s", pkgStream_->GetFileName().c_str());
return ret;
}
PKG_LOGI("SavePackage success file length: %zu signOffset %zu", pkgStream_->GetFileLength(), signOffset);
pkgStream_->Flush(offset);
return PKG_SUCCESS;
}
int32_t UpgradePkgFile::SavePackage(size_t &signOffset)
{
PKG_LOGI("SavePackage %s", pkgStream_->GetFileName().c_str());
size_t buffSize = GetUpgradeSignatureLen() + UPGRADE_RESERVE_LEN;
buffSize = ((buffSize < UPGRADE_FILE_HEADER_LEN) ? UPGRADE_FILE_HEADER_LEN : buffSize);
std::vector<uint8_t> buffer(buffSize);
size_t offset = 0;
int32_t ret = CheckPackageHeader(buffer, offset);
if (ret != PKG_SUCCESS) {
PKG_LOGE("Fail to CheckPackageHeader");
return PKG_NONE_MEMORY;
}
UpgradePkgTime *time = reinterpret_cast<UpgradePkgTime *>(buffer.data() + offset);
ret = memcpy_s(time->date, sizeof(time->date), pkgInfo_.date.data(), pkgInfo_.date.size());
if (ret != EOK) {
PKG_LOGE("Fail to memcpy_s %s ret: %d", pkgStream_->GetFileName().c_str(), ret);
return PKG_NONE_MEMORY;
}
ret = memcpy_s(time->time, sizeof(time->time), pkgInfo_.time.data(), pkgInfo_.time.size());
if (ret != EOK) {
PKG_LOGE("Fail to memcpy_s %s ret: %d", pkgStream_->GetFileName().c_str(), ret);
return PKG_NONE_MEMORY;
}
offset += sizeof(UpgradePkgTime);
WriteLE16(buffer.data() + offset, 0x05);
WriteLE16(buffer.data() + offset + sizeof(uint16_t), pkgInfo_.pkgInfo.entryCount * sizeof(UpgradeCompInfo));
offset += sizeof(PkgTlv);
ret = pkgStream_->Write(buffer, UPGRADE_FILE_HEADER_LEN, 0);
if (ret != PKG_SUCCESS) {
PKG_LOGE("Fail write upgrade file header for %s ret: %d", pkgStream_->GetFileName().c_str(), ret);
return ret;
}
ret = WriteBuffer(buffer, offset, signOffset);
if (ret != PKG_SUCCESS) {
PKG_LOGE("Fail WriteBuffer");
return ret;
}
return PKG_SUCCESS;
}
int32_t UpgradePkgFile::ReadSignData(std::vector<uint8_t> &signData,
size_t &parsedLen, DigestAlgorithm::DigestAlgorithmPtr algorithm)
{
Updater::UPDATER_INIT_RECORD;
size_t readBytes = 0;
size_t signLen = parsedLen;
PkgBuffer buffer(HASH_TLV_SIZE);
int32_t ret = pkgStream_->Read(buffer, parsedLen, buffer.length, readBytes);
if (ret != PKG_SUCCESS) {
PKG_LOGE("read sign data fail");
UPDATER_LAST_WORD(ret, parsedLen);
return ret;
}
parsedLen += buffer.length;
uint16_t dataType = ReadLE16(buffer.buffer);
uint32_t dataLen = ReadLE32(buffer.buffer + sizeof(uint16_t));
if (dataType != TLV_TYPE_FOR_SIGN) {
PKG_LOGE("Invalid tlv type: %hu length %u ", dataType, dataLen);
UPDATER_LAST_WORD(ret, dataType);
return PKG_INVALID_FILE;
}
PkgBuffer signBuf(dataLen);
ret = pkgStream_->Read(signBuf, parsedLen, signBuf.length, readBytes);
if (ret != PKG_SUCCESS) {
PKG_LOGE("read hash data fail");
UPDATER_LAST_WORD(ret, parsedLen);
return ret;
}
parsedLen += signBuf.length;
signData.resize(dataLen);
signData.assign(signBuf.data.begin(), signBuf.data.end());
signLen = parsedLen - signLen;
for (auto &it : pkgEntryMapId_) {
if (it.second != nullptr) {
it.second->AddDataOffset(signLen);
}
}
return PKG_SUCCESS;
}
int32_t UpgradePkgFile::ReadImgHashTLV(std::vector<uint8_t> &imgHashBuf, size_t &parsedLen,
DigestAlgorithm::DigestAlgorithmPtr algorithm, uint32_t needType)
{
Updater::UPDATER_INIT_RECORD;
size_t readBytes = 0;
PkgBuffer buffer(HASH_TLV_SIZE);
int32_t ret = pkgStream_->Read(buffer, parsedLen, buffer.length, readBytes);
if (ret != PKG_SUCCESS) {
PKG_LOGE("read image hash header fail");
UPDATER_LAST_WORD(ret, "read image hash header fail");
return ret;
}
parsedLen += buffer.length;
uint16_t type = ReadLE16(buffer.buffer);
uint32_t len = ReadLE32(buffer.buffer + sizeof(uint16_t));
if (type != needType) {
PKG_LOGE("Invalid tlv type: %d length %u ", type, len);
return PKG_INVALID_FILE;
}
algorithm->Update(buffer, buffer.length);
imgHashBuf.insert(imgHashBuf.end(), buffer.data.begin(), buffer.data.end());
PkgBuffer dataBuf(len);
ret = pkgStream_->Read(dataBuf, parsedLen, dataBuf.length, readBytes);
if (ret != PKG_SUCCESS) {
PKG_LOGE("read hash data fail");
UPDATER_LAST_WORD(ret, "read hash data fail");
return ret;
}
parsedLen += dataBuf.length;
algorithm->Update(dataBuf, dataBuf.length);
imgHashBuf.insert(imgHashBuf.end(), dataBuf.data.begin(), dataBuf.data.end());
return PKG_SUCCESS;
}
int32_t UpgradePkgFile::ReadChunkListInfo(size_t &parsedLen, DigestAlgorithm::DigestAlgorithmPtr algorithm)
{
Updater::UPDATER_INIT_RECORD;
PkgBuffer buffer {};
if (ReadChunkTlv<ChunkListInfoTlv>(buffer, parsedLen, algorithm) != PKG_SUCCESS) {
return PKG_INVALID_PKG_FORMAT;
}
chunkInfo_.chunkListCount = ReadLE32(buffer.buffer);
chunkInfo_.chunkListSize = ReadLE64(buffer.buffer + sizeof(uint32_t));
return PKG_SUCCESS;
}
int32_t UpgradePkgFile::ReadPartitionNumChunk(size_t &parsedLen, DigestAlgorithm::DigestAlgorithmPtr algorithm)
{
Updater::UPDATER_INIT_RECORD;
PkgBuffer buffer {};
if (ReadChunkTlv<ParitionNumChunkTlv>(buffer, parsedLen, algorithm) != PKG_SUCCESS) {
return PKG_INVALID_PKG_FORMAT;
}
if (buffer.Size() != sizeof(uint16_t)) {
PKG_LOGE("paritionNum size invalid %zu", buffer.Size());
UPDATER_LAST_WORD("paritionNum size invalid", buffer.Size());
return PKG_INVALID_PKG_FORMAT;
}
chunkInfo_.partitionNum = ReadLE16(buffer.buffer);
return PKG_SUCCESS;
}
int32_t UpgradePkgFile::ReadPartitionNameChunk(size_t &parsedLen,
DigestAlgorithm::DigestAlgorithmPtr algorithm, std::string &paritionName)
{
Updater::UPDATER_INIT_RECORD;
PkgBuffer buffer {};
if (ReadChunkTlv<ParitionNameChunkTlv>(buffer, parsedLen, algorithm) != PKG_SUCCESS) {
return PKG_INVALID_PKG_FORMAT;
}
PkgFileImpl::ConvertBufferToString(paritionName, {buffer.buffer, buffer.length});
return PKG_SUCCESS;
}
int32_t UpgradePkgFile::ReadImageSizeChunk(size_t &parsedLen,
DigestAlgorithm::DigestAlgorithmPtr algorithm, uint64_t &imageSize)
{
Updater::UPDATER_INIT_RECORD;
PkgBuffer buffer {};
if (ReadChunkTlv<ImageSizeChunkTlv>(buffer, parsedLen, algorithm) != PKG_SUCCESS) {
return PKG_INVALID_PKG_FORMAT;
}
if (buffer.Size() != sizeof(uint64_t)) {
PKG_LOGE("imageSize len invalid %zu", buffer.Size());
UPDATER_LAST_WORD("imageSize len invalid", buffer.Size());
return PKG_INVALID_PKG_FORMAT;
}
imageSize = ReadLE64(buffer.buffer);
return PKG_SUCCESS;
}
int32_t UpgradePkgFile::ReadImageHashChunk(size_t &parsedLen,
DigestAlgorithm::DigestAlgorithmPtr algorithm, std::string &imageHash)
{
Updater::UPDATER_INIT_RECORD;
PkgBuffer buffer {};
if (ReadChunkTlv<ImageHashChunkTlv>(buffer, parsedLen, algorithm) != PKG_SUCCESS) {
return PKG_INVALID_PKG_FORMAT;
}
PkgFileImpl::ConvertBufferToString(imageHash, {buffer.buffer, buffer.length});
return PKG_SUCCESS;
}
int32_t UpgradePkgFile::ReadHashPartitionChunk(size_t &parsedLen,
DigestAlgorithm::DigestAlgorithmPtr algorithm, std::string &hashParitionName)
{
Updater::UPDATER_INIT_RECORD;
PkgBuffer buffer {};
if (ReadChunkTlv<HashParitionChunkTlv>(buffer, parsedLen, algorithm) != PKG_SUCCESS) {
return PKG_INVALID_PKG_FORMAT;
}
PkgFileImpl::ConvertBufferToString(hashParitionName, {buffer.buffer, buffer.length});
return PKG_SUCCESS;
}
int32_t UpgradePkgFile::ReadChunkInfo(size_t &parsedLen, DigestAlgorithm::DigestAlgorithmPtr algorithm)
{
Updater::UPDATER_INIT_RECORD;
if (pkgInfo_.updateFileVersion < UPGRADE_FILE_VERSION_V5 || pkgInfo_.updateFileType != UPGRADE_FILE_TYPE_STREAM) {
PKG_LOGI("file version is %d, file type is %d, skip chunk info",
pkgInfo_.updateFileVersion, pkgInfo_.updateFileType);
return PKG_SUCCESS;
}
size_t beginParsedLen = parsedLen;
if (ReadChunkListInfo(parsedLen, algorithm) != PKG_SUCCESS) {
return PKG_INVALID_PKG_FORMAT;
}
if (ReadPartitionNumChunk(parsedLen, algorithm) != PKG_SUCCESS) {
return PKG_INVALID_PKG_FORMAT;
}
for (int i = 0; i < chunkInfo_.partitionNum; ++i) {
std::string paritionName;
uint64_t imageSize = 0;
if (ReadPartitionNameChunk(parsedLen, algorithm, paritionName) != PKG_SUCCESS ||
ReadImageSizeChunk(parsedLen, algorithm, imageSize) != PKG_SUCCESS) {
return PKG_INVALID_PKG_FORMAT;
}
paritionName.insert(0, "/");
PKG_LOGI("image size info image: %s, %llu", paritionName.c_str(), imageSize);
if (!chunkInfo_.imageSizeMap.emplace(paritionName, imageSize).second) {
PKG_LOGE("image size map emplace failed %s %llu", paritionName.c_str(), imageSize);
return PKG_INVALID_PKG_FORMAT;
}
}
for (int i = 0; i < chunkInfo_.partitionNum; ++i) {
std::string hashParitionName;
std::string imageHash;
if (ReadHashPartitionChunk(parsedLen, algorithm, hashParitionName) != PKG_SUCCESS ||
ReadImageHashChunk(parsedLen, algorithm, imageHash) != PKG_SUCCESS) {
return PKG_INVALID_PKG_FORMAT;
}
hashParitionName.insert(0, "/");
if (!chunkInfo_.imageHashMap.emplace(hashParitionName, imageHash).second) {
PKG_LOGE("image size map emplace failed %s %s", hashParitionName.c_str(), imageHash.c_str());
return PKG_INVALID_PKG_FORMAT;
}
}
for (auto &it : pkgEntryMapId_) {
it.second->AddDataOffset(parsedLen - beginParsedLen);
}
return PKG_SUCCESS;
}
int32_t UpgradePkgFile::ReadImgHashData(size_t &parsedLen, DigestAlgorithm::DigestAlgorithmPtr algorithm)
{
Updater::UPDATER_INIT_RECORD;
#ifndef DIFF_PATCH_SDK
if ((!Updater::Utils::CheckUpdateMode(Updater::SDCARD_MODE) &&
!Updater::Utils::CheckUpdateMode(Updater::USB_MODE) &&
!Updater::Utils::CheckUpdateMode(Updater::SDCARD_INTRAL_MODE)) ||
pkgInfo_.updateFileVersion < UPGRADE_FILE_VERSION_V2 ||
Updater::Utils::CheckUpdateMode(Updater::TOB_PKG_TAG)) {
PKG_LOGI("ignore image hash check");
return PKG_SUCCESS;
}
#endif
std::vector<uint8_t> imgHashBuf;
int32_t ret = ReadImgHashTLV(imgHashBuf, parsedLen, algorithm, TLV_TYPE_FOR_HASH_HEADER);
if (ret != PKG_SUCCESS) {
PKG_LOGE("read image hash info fail");
UPDATER_LAST_WORD(ret, "read image hash info fail");
return ret;
}
ret = ReadImgHashTLV(imgHashBuf, parsedLen, algorithm, TLV_TYPE_FOR_HASH_DATA);
if (ret != PKG_SUCCESS) {
PKG_LOGE("read image hash data fail");
UPDATER_LAST_WORD(ret, "read image hash data fail");
return ret;
}
for (auto &it : pkgEntryMapId_) {
it.second->AddDataOffset(imgHashBuf.size());
}
#ifndef DIFF_PATCH_SDK
if (pkgInfo_.updateFileVersion >= UPGRADE_FILE_VERSION_V3) {
hashCheck_ = LoadImgHashDataNew(imgHashBuf.data(), imgHashBuf.size());
} else {
hashCheck_ = LoadImgHashData(imgHashBuf.data(), imgHashBuf.size());
}
if (hashCheck_ == nullptr) {
PKG_LOGE("pause hash data fail");
return PKG_INVALID_FILE;
}
#endif
return PKG_SUCCESS;
}
int32_t UpgradePkgFile::ReadPackageInfo(std::vector<uint8_t> &signData, size_t &parsedLen,
DigestAlgorithm::DigestAlgorithmPtr algorithm)
{
Updater::UPDATER_INIT_RECORD;
PkgBuffer buffer(GetUpgradeSignatureLen() + UPGRADE_RESERVE_LEN);
size_t readBytes = 0;
int32_t ret = pkgStream_->Read(buffer, parsedLen, buffer.length, readBytes);
if (ret != PKG_SUCCESS) {
PKG_LOGE("read sign data fail");
UPDATER_LAST_WORD(ret, "read sign data fail");
return ret;
}
PkgFileImpl::ConvertBufferToString(pkgInfo_.descriptPackageId, {buffer.buffer, UPGRADE_RESERVE_LEN});
if (pkgInfo_.pkgInfo.digestMethod == PKG_DIGEST_TYPE_SHA384) {
signData.resize(SIGN_SHA384_LEN);
ret = memcpy_s(signData.data(), signData.size(),
buffer.buffer + UPGRADE_RESERVE_LEN + SIGN_SHA256_LEN, SIGN_SHA384_LEN);
} else {
signData.resize(SIGN_SHA256_LEN);
ret = memcpy_s(signData.data(), signData.size(), buffer.buffer + UPGRADE_RESERVE_LEN, SIGN_SHA256_LEN);
}
if (ret != EOK) {
PKG_LOGE("memcpy sign data fail");
UPDATER_LAST_WORD(PKG_NONE_MEMORY, "memcpy sign data fail");
return PKG_NONE_MEMORY;
}
for (auto &it : pkgEntryMapId_) {
if (it.second != nullptr) {
it.second->AddDataOffset(GetUpgradeSignatureLen());
}
}
ret = memset_s(buffer.buffer + UPGRADE_RESERVE_LEN, buffer.length - UPGRADE_RESERVE_LEN,
0, GetUpgradeSignatureLen());
if (ret != EOK) {
PKG_LOGE("memset buff fail");
UPDATER_LAST_WORD(PKG_NONE_MEMORY, "memset buff fail");
return PKG_NONE_MEMORY;
}
algorithm->Update(buffer, UPGRADE_RESERVE_LEN + GetUpgradeSignatureLen());
parsedLen += UPGRADE_RESERVE_LEN + GetUpgradeSignatureLen();
return PKG_SUCCESS;
}
int32_t UpgradePkgFile::LoadPackage(std::vector<std::string> &fileNames, VerifyFunction verifier)
{
Updater::UPDATER_INIT_RECORD;
if (verifier == nullptr) {
PKG_LOGE("Check verifier nullptr");
UPDATER_LAST_WORD(PKG_INVALID_SIGNATURE, "Check verifier nullptr");
return PKG_INVALID_SIGNATURE;
}
if (!CheckState({PKG_FILE_STATE_IDLE}, PKG_FILE_STATE_WORKING)) {
PKG_LOGE("error state curr %d ", state_);
UPDATER_LAST_WORD(PKG_INVALID_STATE, "error state curr");
return PKG_INVALID_STATE;
}
PKG_LOGI("LoadPackage %s ", pkgStream_->GetFileName().c_str());
size_t fileLen = pkgStream_->GetFileLength();
size_t buffSize = UPGRADE_FILE_HEADER_LEN + sizeof(UpgradeCompInfo) +
GetUpgradeSignatureLen() + UPGRADE_RESERVE_LEN;
if (fileLen < buffSize) {
PKG_LOGE("Invalid file %s fileLen:%zu ", pkgStream_->GetFileName().c_str(), fileLen);
UPDATER_LAST_WORD(PKG_INVALID_STATE, "Invalid file " + pkgStream_->GetFileName(), fileLen);
return PKG_INVALID_FILE;
}
DigestAlgorithm::DigestAlgorithmPtr algorithm = nullptr;
size_t parsedLen = 0;
int32_t ret = ReadUpgradePkgHeader(parsedLen, algorithm);
if (ret != PKG_SUCCESS) {
PKG_LOGE("Decode header fail %d", ret);
UPDATER_LAST_WORD(ret, "Decode header fail");
return ret;
}
ret = ReadComponents(parsedLen, algorithm, fileNames);
if (ret != PKG_SUCCESS) {
PKG_LOGE("Decode components fail %d", ret);
UPDATER_LAST_WORD(ret, "Decode components fail");
return ret;
}
ret = ReadChunkInfo(parsedLen, algorithm);
if (ret != PKG_SUCCESS) {
PKG_LOGE("read chunkinfo fail %d", ret);
UPDATER_LAST_WORD(ret, "read chunkinfo fail");
return ret;
}
ret = VerifyFile(parsedLen, algorithm, verifier);
pkgInfo_.pkgInfo.updateFileHeadLen = parsedLen;
return ret;
}
int32_t UpgradePkgFile::VerifyFile(size_t &parsedLen, DigestAlgorithm::DigestAlgorithmPtr algorithm,
VerifyFunction verifier)
{
if (pkgInfo_.updateFileVersion >= UPGRADE_FILE_VERSION_V2) {
return VerifyFileV2(parsedLen, algorithm, verifier);
}
return VerifyFileV1(parsedLen, algorithm, verifier);
}
int32_t UpgradePkgFile::VerifyFileV1(size_t &parsedLen, DigestAlgorithm::DigestAlgorithmPtr algorithm,
VerifyFunction verifier)
{
std::vector<uint8_t> signData;
int32_t ret = ReadPackageInfo(signData, parsedLen, algorithm);
if (ret != PKG_SUCCESS) {
PKG_LOGE("ReadPackageInfo fail %d", ret);
return ret;
}
return Verify(parsedLen, algorithm, verifier, signData);
}
int32_t UpgradePkgFile::VerifyFileV2(size_t &parsedLen, DigestAlgorithm::DigestAlgorithmPtr algorithm,
VerifyFunction verifier)
{
int32_t ret = ReadReserveData(parsedLen, algorithm);
if (ret != PKG_SUCCESS) {
PKG_LOGE("ReadReserveData fail %d", ret);
return ret;
}
ret = ReadImgHashData(parsedLen, algorithm);
if (ret != PKG_SUCCESS) {
PKG_LOGW("LoadImgHashData fail %d, ignore image hash check", ret);
return ret;
}
std::vector<uint8_t> signData;
ret = ReadSignData(signData, parsedLen, algorithm);
if (ret != PKG_SUCCESS) {
PKG_LOGE("ReadSignData fail %d", ret);
return ret;
}
return VerifyHeader(algorithm, verifier, signData);
}
int32_t UpgradePkgFile::Verify(size_t start, DigestAlgorithm::DigestAlgorithmPtr algorithm,
VerifyFunction verifier, const std::vector<uint8_t> &signData)
{
Updater::UPDATER_INIT_RECORD;
int ret = 0;
size_t buffSize = BUFFER_SIZE;
size_t offset = start;
size_t readBytes = 0;
PkgBuffer buffer(buffSize);
while (offset + readBytes < pkgStream_->GetFileLength()) {
offset += readBytes;
readBytes = 0;
size_t remainBytes = pkgStream_->GetFileLength() - offset;
remainBytes = ((remainBytes > buffSize) ? buffSize : remainBytes);
ret = pkgStream_->Read(buffer, offset, remainBytes, readBytes);
if (ret != PKG_SUCCESS) {
PKG_LOGE("Fail to read data ");
UPDATER_LAST_WORD(ret, "Fail to read data ");
return ret;
}
algorithm->Update(buffer, readBytes);
pkgManager_->PostDecodeProgress(POST_TYPE_VERIFY_PKG, remainBytes, nullptr);
}
PkgBuffer digest(GetDigestLen());
algorithm->Final(digest);
ret = verifier(&pkgInfo_.pkgInfo, digest.data, signData);
if (ret != 0) {
PKG_LOGE("Fail to verifier signature");
UPDATER_LAST_WORD(PKG_INVALID_SIGNATURE, "Fail to verifier signature");
return PKG_INVALID_SIGNATURE;
}
return 0;
}
int32_t UpgradePkgFile::VerifyHeader(DigestAlgorithm::DigestAlgorithmPtr algorithm,
VerifyFunction verifier, const std::vector<uint8_t> &signData)
{
Updater::UPDATER_INIT_RECORD;
PkgBuffer digest(GetDigestLen());
algorithm->Final(digest);
int ret = 0;
if (pkgInfo_.updateFileVersion >= UPGRADE_FILE_VERSION_V4) {
auto signature = signData;
PkgVerifyUtil pkgVerifyUtil;
ret = pkgVerifyUtil.VerifySign(signature, digest.data);
} else {
ret = verifier(&pkgInfo_.pkgInfo, digest.data, signData);
}
if (ret != 0) {
PKG_LOGE("Fail to verifier signature");
UPDATER_LAST_WORD(PKG_INVALID_SIGNATURE);
return PKG_INVALID_SIGNATURE;
}
return 0;
}
int32_t UpgradePkgFile::SetUpradeEntryStream(UpgradeFileEntry *entry)
{
if (entry == nullptr || pkgStream_ == nullptr) {
PKG_LOGE("entry or stream is null");
return PKG_INVALID_PARAM;
}
entry->SetEntryPkgStream(pkgStream_);
return PKG_SUCCESS;
}
int32_t UpgradePkgFile::SaveEntry(const PkgBuffer &buffer, size_t &parsedLen, UpgradeParam &info,
DigestAlgorithm::DigestAlgorithmPtr algorithm, std::vector<std::string> &fileNames)
{
UpgradeFileEntry *entry = new (std::nothrow) UpgradeFileEntry(this, nodeId_++);
if (entry == nullptr) {
PKG_LOGE("Fail create upgrade node for %s", pkgStream_->GetFileName().c_str());
return PKG_NONE_MEMORY;
}
size_t decodeLen = 0;
PkgBuffer headerBuff(buffer.buffer + info.currLen, info.readLen - info.currLen);
const size_t headerOffset = parsedLen + info.srcOffset;
const size_t dataOffset = info.dataOffset;
int32_t ret = entry->DecodeHeader(headerBuff, headerOffset, dataOffset, decodeLen);
if (ret != PKG_SUCCESS) {
delete entry;
PKG_LOGE("Fail to decode header");
return ret;
}
if (SetUpradeEntryStream(entry) != PKG_SUCCESS) {
delete entry;
PKG_LOGE("Fail to set entry stream");
return PKG_INVALID_PARAM;
}
pkgEntryMapId_.insert(pair<uint32_t, PkgEntryPtr>(entry->GetNodeId(), entry));
pkgEntryMapFileName_.insert(std::pair<std::string, PkgEntryPtr>(entry->GetFileName(), entry));
fileNames.push_back(entry->GetFileName());
components_.push_back(entry->GetFileName());
PkgBuffer signBuffer(buffer.buffer + info.currLen, decodeLen);
algorithm->Update(signBuffer, decodeLen);
info.currLen += decodeLen;
info.srcOffset += decodeLen;
if (entry->GetFileInfo() == nullptr) {
delete entry;
PKG_LOGE("Failed to get file info");
return PKG_INVALID_FILE;
}
info.dataOffset += entry->GetFileInfo()->packedSize;
pkgInfo_.pkgInfo.entryCount++;
PKG_LOGSEN(Updater::INFO) << "Component offset: " << headerOffset << " " << dataOffset << " packed "
<< entry->GetFileInfo()->packedSize << " unpacked " << entry->GetFileInfo()->unpackedSize
<< " " << entry->GetFileInfo()->identity.c_str();
return PKG_SUCCESS;
}
int32_t UpgradePkgFile::ReadComponents(size_t &parsedLen,
DigestAlgorithm::DigestAlgorithmPtr algorithm, std::vector<std::string> &fileNames)
{
Updater::UPDATER_INIT_RECORD;
UpgradeParam info;
size_t fileLen = pkgStream_->GetFileLength();
info.readLen = 0;
PkgBuffer buffer(sizeof(PkgTlv));
int32_t ret = pkgStream_->Read(buffer, parsedLen, buffer.length, info.readLen);
if (ret != PKG_SUCCESS) {
PKG_LOGE("Read component fail");
UPDATER_LAST_WORD(ret, "Read component fail");
return ret;
}
PkgTlv tlv;
tlv.type = ReadLE16(buffer.buffer);
tlv.length = ReadLE16(buffer.buffer + sizeof(uint16_t));
TLV_CHECK_AND_RETURN(&tlv, 5, sizeof(UpgradeCompInfo), fileLen);
algorithm->Update(buffer, sizeof(PkgTlv));
parsedLen += sizeof(PkgTlv);
info.dataOffset = parsedLen + tlv.length + UPGRADE_RESERVE_LEN;
info.srcOffset = 0;
info.currLen = sizeof(PkgTlv);
PkgBuffer compBuffer(sizeof(UpgradeCompInfo));
while (info.srcOffset < tlv.length) {
if (info.currLen + sizeof(UpgradeCompInfo) > info.readLen) {
info.readLen = 0;
ret = pkgStream_->Read(compBuffer, parsedLen + info.srcOffset, compBuffer.length, info.readLen);
if (ret != PKG_SUCCESS) {
PKG_LOGE("Fail to read data");
UPDATER_LAST_WORD(ret, "Fail to read data");
return ret;
}
info.currLen = 0;
}
ret = SaveEntry(compBuffer, parsedLen, info, algorithm, fileNames);
if (ret != PKG_SUCCESS) {
PKG_LOGE("SaveEntry");
UPDATER_LAST_WORD(ret, "SaveEntry");
return ret;
}
}
parsedLen += info.srcOffset;
return PKG_SUCCESS;
}
void UpgradePkgFile::ParsePkgHeaderToTlv(const PkgBuffer &buffer, size_t &currLen, PkgTlv &tlv)
{
pkgInfo_.pkgInfo.pkgType = PkgFile::PKG_TYPE_UPGRADE;
pkgInfo_.pkgInfo.signMethod = PKG_SIGN_METHOD_RSA;
pkgInfo_.pkgInfo.digestMethod = PKG_DIGEST_TYPE_SHA256;
tlv.type = ReadLE16(buffer.buffer);
tlv.length = ReadLE16(buffer.buffer + sizeof(uint16_t));
if (tlv.type == TLV_TYPE_FOR_SHA384) {
pkgInfo_.pkgInfo.digestMethod = PKG_DIGEST_TYPE_SHA384;
}
currLen = sizeof(PkgTlv);
UpgradePkgHeader *header = reinterpret_cast<UpgradePkgHeader *>(buffer.buffer + currLen);
pkgInfo_.updateFileVersion = ReadLE16(buffer.buffer + currLen + offsetof(UpgradePkgHeader, updateFileVersion));
pkgInfo_.updateFileType = ReadLE16(buffer.buffer + currLen + offsetof(UpgradePkgHeader, updateFileType));
PkgFileImpl::ConvertBufferToString(pkgInfo_.softwareVersion, {header->softwareVersion,
sizeof(header->softwareVersion)});
PkgFileImpl::ConvertBufferToString(pkgInfo_.productUpdateId, {header->productUpdateId,
sizeof(header->productUpdateId)});
}
int32_t UpgradePkgFile::ReadReserveData(size_t &parsedLen, DigestAlgorithm::DigestAlgorithmPtr &algorithm)
{
Updater::UPDATER_INIT_RECORD;
size_t readBytes = 0;
PkgBuffer reserve_buf(UPGRADE_RESERVE_LEN);
int32_t ret = pkgStream_->Read(reserve_buf, parsedLen, reserve_buf.length, readBytes);
if (ret != PKG_SUCCESS) {
PKG_LOGE("read reserve data fail");
UPDATER_LAST_WORD(ret);
return ret;
}
PkgFileImpl::ConvertBufferToString(pkgInfo_.descriptPackageId, {reserve_buf.buffer, UPGRADE_RESERVE_LEN});
algorithm->Update(reserve_buf, reserve_buf.length);
parsedLen += reserve_buf.length;
return PKG_SUCCESS;
}
int32_t UpgradePkgFile::ReadUpgradePkgHeader(size_t &realLen, DigestAlgorithm::DigestAlgorithmPtr &algorithm)
{
Updater::UPDATER_INIT_RECORD;
size_t fileLen = pkgStream_->GetFileLength();
size_t readLen = 0;
size_t currLen = 0;
PkgTlv tlv;
PkgBuffer buffer(UPGRADE_FILE_BASIC_LEN);
int32_t ret = pkgStream_->Read(buffer, 0, buffer.length, readLen);
if (ret != PKG_SUCCESS) {
PKG_LOGE("Fail to read header");
UPDATER_LAST_WORD(ret, "Fail to read header");
return ret;
}
ParsePkgHeaderToTlv(buffer, currLen, tlv);
algorithm = PkgAlgorithmFactory::GetDigestAlgorithm(pkgInfo_.pkgInfo.digestMethod);
if (algorithm == nullptr) {
PKG_LOGE("Invalid file %s", pkgStream_->GetFileName().c_str());
UPDATER_LAST_WORD(PKG_NOT_EXIST_ALGORITHM, "invalid file " + pkgStream_->GetFileName());
return PKG_NOT_EXIST_ALGORITHM;
}
algorithm->Init();
if (currLen + tlv.length >= readLen) {
realLen = currLen + tlv.length;
algorithm->Update(buffer, realLen);
ret = pkgStream_->Read(buffer, realLen, buffer.length, readLen);
if (ret != PKG_SUCCESS) {
PKG_LOGE("Fail to read header");
UPDATER_LAST_WORD(ret, "Fail to read TLV");
return ret;
}
currLen = 0;
} else {
currLen += tlv.length;
}
tlv.type = ReadLE16(buffer.buffer + currLen);
tlv.length = ReadLE16(buffer.buffer + currLen + sizeof(uint16_t));
TLV_CHECK_AND_RETURN(&tlv, sizeof(uint16_t), sizeof(UpgradePkgTime), fileLen);
currLen += sizeof(PkgTlv);
UpgradePkgTime *time = reinterpret_cast<UpgradePkgTime *>(buffer.buffer + currLen);
PkgFileImpl::ConvertBufferToString(pkgInfo_.date, {time->date, sizeof(time->date)});
PkgFileImpl::ConvertBufferToString(pkgInfo_.time, {time->time, sizeof(time->time)});
currLen += tlv.length;
realLen += currLen;
algorithm->Update(buffer, currLen);
return PKG_SUCCESS;
}
int32_t UpgradeFileEntry::GetUpGradeCompInfo(UpgradeCompInfo &comp)
{
if (memset_s(&comp, sizeof(comp), 0, sizeof(comp)) != EOK) {
PKG_LOGE("UpgradeFileEntry memset_s failed");
return PKG_NONE_MEMORY;
}
size_t len = 0;
int32_t ret = PkgFileImpl::ConvertStringToBuffer(
fileInfo_.fileInfo.identity, {comp.address, sizeof(comp.address)}, len);
if (ret != PKG_SUCCESS) {
PKG_LOGE("outStream or inStream null for %s", fileName_.c_str());
return PKG_INVALID_PARAM;
}
ret = PkgFileImpl::ConvertStringToBuffer(fileInfo_.version, {comp.version, sizeof(comp.version)}, len);
if (ret != PKG_SUCCESS) {
PKG_LOGE("outStream or inStream null for %s", fileName_.c_str());
return PKG_INVALID_PARAM;
}
ret = memcpy_s(comp.digest, sizeof(comp.digest), fileInfo_.digest, sizeof(fileInfo_.digest));
if (ret != EOK) {
PKG_LOGE("Fail to memcpy_s ret: %d", ret);
return ret;
}
return PKG_SUCCESS;
}
int32_t UpgradeFileEntry::EncodeHeader(PkgStreamPtr inStream, size_t startOffset, size_t &encodeLen)
{
PkgStreamPtr outStream = pkgFile_->GetPkgStream();
if (outStream == nullptr || inStream == nullptr) {
PKG_LOGE("outStream or inStream null for %s", fileName_.c_str());
return PKG_INVALID_PARAM;
}
UpgradeCompInfo comp;
int ret = GetUpGradeCompInfo(comp);
if (ret != PKG_SUCCESS) {
PKG_LOGE("GetUpGradeCompInfo failed");
return ret;
}
WriteLE32(reinterpret_cast<uint8_t *>(&comp.size), fileInfo_.fileInfo.unpackedSize);
WriteLE16(reinterpret_cast<uint8_t *>(&comp.id), fileInfo_.id);
WriteLE32(reinterpret_cast<uint8_t *>(&comp.originalSize), fileInfo_.originalSize);
comp.resType = fileInfo_.resType;
comp.flags = fileInfo_.compFlags;
comp.type = fileInfo_.type;
headerOffset_ = startOffset;
PkgBuffer buffer(reinterpret_cast<uint8_t *>(&comp), sizeof(comp));
ret = outStream->Write(buffer, sizeof(comp), startOffset);
if (ret != PKG_SUCCESS) {
PKG_LOGE("Fail write header for %s", fileName_.c_str());
return ret;
}
encodeLen = sizeof(UpgradeCompInfo);
PKG_LOGI("EncodeHeader startOffset: %zu %zu packedSize:%zu %zu ", headerOffset_, dataOffset_,
fileInfo_.fileInfo.packedSize, fileInfo_.fileInfo.unpackedSize);
return PKG_SUCCESS;
}
int32_t UpgradeFileEntry::Pack(PkgStreamPtr inStream, size_t startOffset, size_t &encodeLen)
{
PkgAlgorithm::PkgAlgorithmPtr algorithm = PkgAlgorithmFactory::GetAlgorithm(&fileInfo_.fileInfo);
PkgStreamPtr outStream = pkgFile_->GetPkgStream();
if (algorithm == nullptr || outStream == nullptr || inStream == nullptr) {
PKG_LOGE("outStream or inStream null for %s", fileName_.c_str());
return PKG_INVALID_PARAM;
}
PkgAlgorithmContext context = {
{0, startOffset},
{fileInfo_.fileInfo.packedSize, fileInfo_.fileInfo.unpackedSize},
0, fileInfo_.fileInfo.digestMethod
};
if (memcpy_s(context.digest, sizeof(context.digest), fileInfo_.digest, sizeof(fileInfo_.digest)) != EOK) {
PKG_LOGE("UpgradeFileEntry pack memcpy failed");
return PKG_NONE_MEMORY;
}
int32_t ret = algorithm->Pack(inStream, outStream, context);
if (ret != PKG_SUCCESS) {
PKG_LOGE("Fail Compress for %s", fileName_.c_str());
return ret;
}
if (memcpy_s(fileInfo_.digest, sizeof(fileInfo_.digest), context.digest, sizeof(context.digest)) != EOK) {
PKG_LOGE("UpgradeFileEntry pack memcpy failed");
return PKG_NONE_MEMORY;
}
fileInfo_.fileInfo.packedSize = context.packedSize;
dataOffset_ = startOffset;
encodeLen = fileInfo_.fileInfo.packedSize;
PKG_LOGI("Pack start:%zu unpackSize:%zu packSize:%zu", startOffset, fileInfo_.fileInfo.unpackedSize,
fileInfo_.fileInfo.packedSize);
return PKG_SUCCESS;
}
int32_t UpgradeFileEntry::DecodeHeader(PkgBuffer &buffer, size_t headerOffset, size_t dataOffset,
size_t &decodeLen)
{
UpgradePkgFile *pkgFile = static_cast<UpgradePkgFile*>(GetPkgFile());
if (pkgFile == nullptr) {
PKG_LOGE("Get pkg file ptr fail");
return PKG_INVALID_PARAM;
}
PkgStreamPtr inStream = pkgFile->GetPkgStream();
if (inStream == nullptr) {
PKG_LOGE("outStream or inStream null for %s", fileName_.c_str());
return PKG_INVALID_PARAM;
}
if (buffer.length < sizeof(UpgradeCompInfo)) {
PKG_LOGE("Fail to check buffer %zu", buffer.length);
return PKG_INVALID_PKG_FORMAT;
}
UpgradeCompInfo *info = reinterpret_cast<UpgradeCompInfo *>(buffer.buffer);
if (pkgFile->GetUpgradeFileVer() >= UPGRADE_FILE_VERSION_V3) {
fileInfo_.fileInfo.packedSize = ReadLE64(buffer.buffer + offsetof(UpgradeCompInfo, size));
} else {
fileInfo_.fileInfo.packedSize = ReadLE32(buffer.buffer + offsetof(UpgradeCompInfo, size));
fileInfo_.originalSize = ReadLE32(buffer.buffer + offsetof(UpgradeCompInfo, originalSize));
}
fileInfo_.fileInfo.unpackedSize = fileInfo_.fileInfo.packedSize;
fileInfo_.fileInfo.packMethod = PKG_COMPRESS_METHOD_NONE;
fileInfo_.fileInfo.digestMethod = PKG_DIGEST_TYPE_NONE;
fileInfo_.fileInfo.resType = info->resType;
PkgFileImpl::ConvertBufferToString(fileInfo_.fileInfo.identity, {info->address, sizeof(info->address)});
PkgFileImpl::ConvertBufferToString(fileInfo_.version, {info->version, sizeof(info->version)});
fileName_ = fileInfo_.fileInfo.identity;
int32_t ret = memcpy_s(fileInfo_.digest, sizeof(fileInfo_.digest), info->digest, sizeof(info->digest));
if (ret != EOK) {
PKG_LOGE("Fail to memcpy_s ret: %d Component offset: %zu %zu packedSize:%zu %zu %s", ret, headerOffset,
dataOffset, fileInfo_.fileInfo.packedSize, fileInfo_.fileInfo.unpackedSize, fileName_.c_str());
return ret;
}
fileInfo_.id = ReadLE16(buffer.buffer + offsetof(UpgradeCompInfo, id));
fileInfo_.resType = info->resType;
fileInfo_.compFlags = info->flags;
fileInfo_.type = info->type;
fileInfo_.fileInfo.type = info->type;
headerOffset_ = headerOffset;
dataOffset_ = dataOffset;
decodeLen = sizeof(UpgradeCompInfo);
return PKG_SUCCESS;
}
int32_t UpgradeFileEntry::Unpack(PkgStreamPtr outStream)
{
PkgAlgorithm::PkgAlgorithmPtr algorithm = PkgAlgorithmFactory::GetAlgorithm(&fileInfo_.fileInfo);
if (algorithm == nullptr) {
PKG_LOGE("can not algorithm for %s", fileName_.c_str());
return PKG_INVALID_PARAM;
}
PkgStreamPtr inStream = pkgFile_->GetPkgEntryStream();
if (outStream == nullptr || inStream == nullptr) {
PKG_LOGE("outStream or inStream null for %s", fileName_.c_str());
return PKG_INVALID_PARAM;
}
PkgAlgorithmContext context = {
{this->dataOffset_, 0},
{fileInfo_.fileInfo.packedSize, fileInfo_.fileInfo.unpackedSize},
0, fileInfo_.fileInfo.digestMethod
};
int32_t ret = memcpy_s(context.digest, sizeof(context.digest), fileInfo_.digest, sizeof(fileInfo_.digest));
if (ret != EOK) {
PKG_LOGE("Fail to memcpy_s ret: %d", ret);
return ret;
}
ret = algorithm->UnpackWithVerify(inStream, outStream, context,
[this](PkgBuffer &buffer, size_t len, size_t offset) ->int32_t {
return Verify(buffer, len, offset);
});
if (ret != PKG_SUCCESS) {
PKG_LOGSEN(Updater::INFO) << "Fail Decompress for " << fileName_.c_str();
return ret;
}
PKG_LOGSEN(Updater::INFO) << "Unpack " << fileName_.c_str() << " data offset:" << dataOffset_
<< " packedSize:" << fileInfo_.fileInfo.packedSize << " unpackedSize:" << fileInfo_.fileInfo.unpackedSize;
outStream->Flush(fileInfo_.fileInfo.unpackedSize);
return PKG_SUCCESS;
}
std::pair<size_t, size_t> UpgradeFileEntry::GetEntryRange(void)
{
return {this->dataOffset_ + readOffset_, this->dataOffset_ + fileInfo_.fileInfo.packedSize};
}
size_t UpgradeFileEntry::GetOriginalSize() const
{
UpgradePkgFile *pkgFile = static_cast<UpgradePkgFile*>(GetPkgFile());
if (pkgFile == nullptr) {
PKG_LOGE("pkg file is null");
return 0;
}
const auto &chunkInfo = pkgFile->GetUpgradeChunkInfo();
auto it = chunkInfo.imageSizeMap.find(fileName_);
if (it != chunkInfo.imageSizeMap.end()) {
PKG_LOGI("%s found in chunk info, return image size %zu", fileName_.c_str(), it->second);
return it->second;
}
PKG_LOGI("%s not found in chunk info, return unpacked size %zu", fileName_.c_str(),
fileInfo_.fileInfo.unpackedSize);
return fileInfo_.fileInfo.unpackedSize;
}
int32_t UpgradeFileEntry::Verify(PkgBuffer &buffer, size_t len, size_t offset)
{
UpgradePkgFile *pkgFile = static_cast<UpgradePkgFile*>(GetPkgFile());
if (pkgFile == nullptr) {
PKG_LOGE("Get pkg file ptr fail: %s", fileName_.c_str());
return PKG_INVALID_PARAM;
}
if (pkgFile->GetImgHashData() == nullptr) {
return PKG_SUCCESS;
}
PkgManager::StreamPtr stream = nullptr;
int32_t ret = pkgFile->GetPkgMgr()->CreatePkgStream(stream, fileName_, buffer);
if (stream == nullptr || ret != PKG_SUCCESS) {
PKG_LOGE("Failed to create stream");
return PKG_INVALID_PARAM;
}
std::vector<uint8_t> hashVal;
ret = CalcSha256Digest(PkgStreamImpl::ConvertPkgStream(stream), len, hashVal);
if (ret != 0) {
PKG_LOGE("cal digest for pkg stream, buffer.length: %zu", buffer.length);
return PKG_INVALID_PARAM;
}
#ifndef DIFF_PATCH_SDK
size_t end = offset + len - 1;
bool checkRet = false;
if (pkgFile->GetUpgradeFileVer() >= UPGRADE_FILE_VERSION_V3) {
checkRet = CheckDataHashNew(pkgFile->GetImgHashData(), fileName_.c_str(),
offset, end, hashVal.data(), hashVal.size());
} else {
std::string imgName = fileName_ + (fileNum_ == 0 ? "" : std::to_string(fileNum_));
checkRet = check_data_hash(pkgFile->GetImgHashData(), imgName.c_str(),
offset, end, hashVal.data(), hashVal.size());
}
if (!checkRet) {
PKG_LOGE("check image hash value fail, name: %s, offset: %zu, end: %u", fileName_.c_str(), offset, end);
return PKG_INVALID_PARAM;
}
#endif
return PKG_SUCCESS;
}
int16_t UpgradePkgFile::GetPackageTlvType()
{
static int16_t packageTlvType[PKG_DIGEST_TYPE_MAX] = {
TLV_TYPE_FOR_SHA256, TLV_TYPE_FOR_SHA256, TLV_TYPE_FOR_SHA256, TLV_TYPE_FOR_SHA384
};
if (pkgInfo_.pkgInfo.digestMethod < PKG_DIGEST_TYPE_MAX) {
return packageTlvType[pkgInfo_.pkgInfo.digestMethod];
}
return TLV_TYPE_FOR_SHA256;
}
}