154aa6d63Sopenharmony_ci/*
254aa6d63Sopenharmony_ci * Copyright (c) 2024-2024 Huawei Device Co., Ltd.
354aa6d63Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
454aa6d63Sopenharmony_ci * you may not use this file except in compliance with the License.
554aa6d63Sopenharmony_ci * You may obtain a copy of the License at
654aa6d63Sopenharmony_ci *
754aa6d63Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
854aa6d63Sopenharmony_ci *
954aa6d63Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
1054aa6d63Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
1154aa6d63Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1254aa6d63Sopenharmony_ci * See the License for the specific language governing permissions and
1354aa6d63Sopenharmony_ci * limitations under the License.
1454aa6d63Sopenharmony_ci */
1554aa6d63Sopenharmony_ci
1654aa6d63Sopenharmony_ci#include <cinttypes>
1754aa6d63Sopenharmony_ci
1854aa6d63Sopenharmony_ci#include "securec.h"
1954aa6d63Sopenharmony_ci#include "signature_info.h"
2054aa6d63Sopenharmony_ci#include "signature_tools_log.h"
2154aa6d63Sopenharmony_ci#include "digest_common.h"
2254aa6d63Sopenharmony_ci//#include "verify_hap_openssl_utils.h"
2354aa6d63Sopenharmony_ci#include "random_access_file.h"
2454aa6d63Sopenharmony_ci
2554aa6d63Sopenharmony_cinamespace OHOS {
2654aa6d63Sopenharmony_cinamespace SignatureTools {
2754aa6d63Sopenharmony_ciint32_t RandomAccessFile::memoryPageSize = sysconf(_SC_PAGESIZE);
2854aa6d63Sopenharmony_ci
2954aa6d63Sopenharmony_ciRandomAccessFile::RandomAccessFile()
3054aa6d63Sopenharmony_ci    : fd(-1), fileLength(0)
3154aa6d63Sopenharmony_ci{
3254aa6d63Sopenharmony_ci}
3354aa6d63Sopenharmony_ci
3454aa6d63Sopenharmony_ciRandomAccessFile::~RandomAccessFile()
3554aa6d63Sopenharmony_ci{
3654aa6d63Sopenharmony_ci    if (fd != -1) {
3754aa6d63Sopenharmony_ci        close(fd);
3854aa6d63Sopenharmony_ci    }
3954aa6d63Sopenharmony_ci}
4054aa6d63Sopenharmony_ci
4154aa6d63Sopenharmony_cibool RandomAccessFile::Init(const std::string& filePath)
4254aa6d63Sopenharmony_ci{
4354aa6d63Sopenharmony_ci    fd = open(filePath.c_str(), O_RDWR);
4454aa6d63Sopenharmony_ci    if (fd == -1) {
4554aa6d63Sopenharmony_ci        PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "open file: " + filePath + " failed");
4654aa6d63Sopenharmony_ci        return false;
4754aa6d63Sopenharmony_ci    }
4854aa6d63Sopenharmony_ci
4954aa6d63Sopenharmony_ci    if (memoryPageSize <= 0) {
5054aa6d63Sopenharmony_ci        PrintErrorNumberMsg("IO_ERROR", IO_ERROR,
5154aa6d63Sopenharmony_ci                            "getting pagesize failed. memoryPageSize: " + std::to_string(memoryPageSize));
5254aa6d63Sopenharmony_ci        return false;
5354aa6d63Sopenharmony_ci    }
5454aa6d63Sopenharmony_ci
5554aa6d63Sopenharmony_ci    struct stat file_stat;
5654aa6d63Sopenharmony_ci    if (fstat(fd, &file_stat) == -1) {
5754aa6d63Sopenharmony_ci        PrintErrorNumberMsg("IO_ERROR", IO_ERROR,
5854aa6d63Sopenharmony_ci                            filePath + "get status failed");
5954aa6d63Sopenharmony_ci        return false;
6054aa6d63Sopenharmony_ci    }
6154aa6d63Sopenharmony_ci    fileLength = file_stat.st_size;
6254aa6d63Sopenharmony_ci
6354aa6d63Sopenharmony_ci    return true;
6454aa6d63Sopenharmony_ci}
6554aa6d63Sopenharmony_ci
6654aa6d63Sopenharmony_ciint64_t RandomAccessFile::GetLength() const
6754aa6d63Sopenharmony_ci{
6854aa6d63Sopenharmony_ci    return fileLength;
6954aa6d63Sopenharmony_ci}
7054aa6d63Sopenharmony_ci
7154aa6d63Sopenharmony_cibool RandomAccessFile::CheckLittleEndian()
7254aa6d63Sopenharmony_ci{
7354aa6d63Sopenharmony_ci    union LittleEndian {
7454aa6d63Sopenharmony_ci        int32_t number;
7554aa6d63Sopenharmony_ci        char ch;
7654aa6d63Sopenharmony_ci    } t;
7754aa6d63Sopenharmony_ci    t.number = 1;
7854aa6d63Sopenharmony_ci    return (t.ch == 1);
7954aa6d63Sopenharmony_ci}
8054aa6d63Sopenharmony_ci
8154aa6d63Sopenharmony_ciint32_t RandomAccessFile::DoMMap(int32_t bufCapacity, int64_t offset, MmapInfo& mmapInfo)
8254aa6d63Sopenharmony_ci{
8354aa6d63Sopenharmony_ci    if (!CheckLittleEndian()) {
8454aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("CheckLittleEndian: failed");
8554aa6d63Sopenharmony_ci        return MMAP_FAILED;
8654aa6d63Sopenharmony_ci    }
8754aa6d63Sopenharmony_ci
8854aa6d63Sopenharmony_ci    // Starting address for memory mapping
8954aa6d63Sopenharmony_ci    mmapInfo.mapAddr = reinterpret_cast<char*>(MAP_FAILED);
9054aa6d63Sopenharmony_ci    if (fd == -1) {
9154aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("random access file's fd is -1, the file is closed");
9254aa6d63Sopenharmony_ci        return FILE_IS_CLOSE;
9354aa6d63Sopenharmony_ci    }
9454aa6d63Sopenharmony_ci    if (offset < 0 || offset > fileLength - bufCapacity) {
9554aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("offset is less than 0 OR read offset is out of range. offset: %" PRId64
9654aa6d63Sopenharmony_ci                             ", range: %" PRId64, offset, fileLength - bufCapacity);
9754aa6d63Sopenharmony_ci        return READ_OFFSET_OUT_OF_RANGE;
9854aa6d63Sopenharmony_ci    }
9954aa6d63Sopenharmony_ci    // Memory mapped file offset, 0 OR an integer multiple of 4K
10054aa6d63Sopenharmony_ci    mmapInfo.mmapPosition = (offset / memoryPageSize) * memoryPageSize;
10154aa6d63Sopenharmony_ci    // How many more bytes can be read from the current mapped memory page to find
10254aa6d63Sopenharmony_ci    mmapInfo.readMoreLen = static_cast<int>(offset - mmapInfo.mmapPosition);
10354aa6d63Sopenharmony_ci    mmapInfo.mmapSize = bufCapacity + mmapInfo.readMoreLen;
10454aa6d63Sopenharmony_ci    mmapInfo.mapAddr = reinterpret_cast<char*>(mmap(nullptr, mmapInfo.mmapSize, PROT_READ | PROT_WRITE,
10554aa6d63Sopenharmony_ci                                                    MAP_SHARED | MAP_POPULATE, fd, mmapInfo.mmapPosition));
10654aa6d63Sopenharmony_ci    if (mmapInfo.mapAddr == MAP_FAILED) {
10754aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("mmap failed");
10854aa6d63Sopenharmony_ci        return MMAP_FAILED;
10954aa6d63Sopenharmony_ci    }
11054aa6d63Sopenharmony_ci    return 0;
11154aa6d63Sopenharmony_ci}
11254aa6d63Sopenharmony_ci
11354aa6d63Sopenharmony_ciint32_t RandomAccessFile::ReadFileFullyFromOffset(char buf[], int64_t offset, int64_t bufCapacity)
11454aa6d63Sopenharmony_ci{
11554aa6d63Sopenharmony_ci    if (buf == nullptr) {
11654aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("The dest buffer is null");
11754aa6d63Sopenharmony_ci        return DEST_BUFFER_IS_NULL;
11854aa6d63Sopenharmony_ci    }
11954aa6d63Sopenharmony_ci
12054aa6d63Sopenharmony_ci    MmapInfo mmapInfo;
12154aa6d63Sopenharmony_ci    int32_t ret = DoMMap(bufCapacity, offset, mmapInfo);
12254aa6d63Sopenharmony_ci    if (ret < 0) {
12354aa6d63Sopenharmony_ci        return ret;
12454aa6d63Sopenharmony_ci    }
12554aa6d63Sopenharmony_ci
12654aa6d63Sopenharmony_ci    if (memcpy_s(buf, bufCapacity, mmapInfo.mapAddr + mmapInfo.readMoreLen,
12754aa6d63Sopenharmony_ci                 mmapInfo.mmapSize - mmapInfo.readMoreLen) != EOK) {
12854aa6d63Sopenharmony_ci        munmap(mmapInfo.mapAddr, mmapInfo.mmapSize);
12954aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("memcpy_s error, errno: %d", IO_ERROR);
13054aa6d63Sopenharmony_ci        return MMAP_COPY_FAILED;
13154aa6d63Sopenharmony_ci    }
13254aa6d63Sopenharmony_ci    munmap(mmapInfo.mapAddr, mmapInfo.mmapSize);
13354aa6d63Sopenharmony_ci    return bufCapacity;
13454aa6d63Sopenharmony_ci}
13554aa6d63Sopenharmony_ci
13654aa6d63Sopenharmony_ciint32_t RandomAccessFile::ReadFileFullyFromOffset(ByteBuffer& buffer, int64_t offset)
13754aa6d63Sopenharmony_ci{
13854aa6d63Sopenharmony_ci    if (!buffer.HasRemaining()) {
13954aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("The dest buffer has not remaining");
14054aa6d63Sopenharmony_ci        return DEST_BUFFER_IS_NULL;
14154aa6d63Sopenharmony_ci    }
14254aa6d63Sopenharmony_ci
14354aa6d63Sopenharmony_ci    MmapInfo mmapInfo;
14454aa6d63Sopenharmony_ci    int32_t bufCapacity = buffer.GetCapacity();
14554aa6d63Sopenharmony_ci    int64_t ret = DoMMap(bufCapacity, offset, mmapInfo);
14654aa6d63Sopenharmony_ci    if (ret < 0) {
14754aa6d63Sopenharmony_ci        return ret;
14854aa6d63Sopenharmony_ci    }
14954aa6d63Sopenharmony_ci
15054aa6d63Sopenharmony_ci    buffer.PutData(0, mmapInfo.mapAddr + mmapInfo.readMoreLen, bufCapacity);
15154aa6d63Sopenharmony_ci    munmap(mmapInfo.mapAddr, mmapInfo.mmapSize);
15254aa6d63Sopenharmony_ci    return bufCapacity;
15354aa6d63Sopenharmony_ci}
15454aa6d63Sopenharmony_ci
15554aa6d63Sopenharmony_ciint32_t RandomAccessFile::WriteToFile(ByteBuffer& buffer, int64_t position, int64_t length)
15654aa6d63Sopenharmony_ci{
15754aa6d63Sopenharmony_ci    // write file, file length may change
15854aa6d63Sopenharmony_ci    int64_t remainLength = fileLength - position;
15954aa6d63Sopenharmony_ci    fileLength = (length <= remainLength) ? fileLength : (fileLength + (length - remainLength));
16054aa6d63Sopenharmony_ci    // update file length
16154aa6d63Sopenharmony_ci    if (ftruncate(fd, fileLength) == -1) {
16254aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("RandomAccessFile ftruncate error: %s", strerror(errno));
16354aa6d63Sopenharmony_ci        return IO_ERROR;
16454aa6d63Sopenharmony_ci    }
16554aa6d63Sopenharmony_ci
16654aa6d63Sopenharmony_ci    int32_t bufCapacity = buffer.GetCapacity();
16754aa6d63Sopenharmony_ci    if (bufCapacity == 0) {
16854aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("The dest buffer capacity is 0");
16954aa6d63Sopenharmony_ci        return DEST_BUFFER_IS_NULL;
17054aa6d63Sopenharmony_ci    }
17154aa6d63Sopenharmony_ci
17254aa6d63Sopenharmony_ci    MmapInfo mmapInfo;
17354aa6d63Sopenharmony_ci
17454aa6d63Sopenharmony_ci    int32_t ret = DoMMap(bufCapacity, position, mmapInfo);
17554aa6d63Sopenharmony_ci    if (ret < 0) {
17654aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("DoMMap failed: %d", ret);
17754aa6d63Sopenharmony_ci        return ret;
17854aa6d63Sopenharmony_ci    }
17954aa6d63Sopenharmony_ci
18054aa6d63Sopenharmony_ci    if (memcpy_s(mmapInfo.mapAddr + mmapInfo.readMoreLen,
18154aa6d63Sopenharmony_ci                 mmapInfo.mmapSize - mmapInfo.readMoreLen,
18254aa6d63Sopenharmony_ci        buffer.GetBufferPtr(), bufCapacity) != RET_OK) {
18354aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("memcpy_s error, errno: %d", IO_ERROR);
18454aa6d63Sopenharmony_ci        return MMAP_COPY_FAILED;
18554aa6d63Sopenharmony_ci    }
18654aa6d63Sopenharmony_ci    munmap(mmapInfo.mapAddr, mmapInfo.mmapSize);
18754aa6d63Sopenharmony_ci    return bufCapacity;
18854aa6d63Sopenharmony_ci}
18954aa6d63Sopenharmony_ci
19054aa6d63Sopenharmony_cibool RandomAccessFile::ReadFileFromOffsetAndDigestUpdate(const DigestParameter& digestParam,
19154aa6d63Sopenharmony_ci                                                         int32_t chunkSize, int64_t offset)
19254aa6d63Sopenharmony_ci{
19354aa6d63Sopenharmony_ci    MmapInfo mmapInfo;
19454aa6d63Sopenharmony_ci    int32_t ret = DoMMap(chunkSize, offset, mmapInfo);
19554aa6d63Sopenharmony_ci    if (ret < 0) {
19654aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("DoMMap failed: %d", ret);
19754aa6d63Sopenharmony_ci        return false;
19854aa6d63Sopenharmony_ci    }
19954aa6d63Sopenharmony_ci    unsigned char* content = reinterpret_cast<unsigned char*>(mmapInfo.mapAddr + mmapInfo.readMoreLen);
20054aa6d63Sopenharmony_ci    bool res = DigestCommon::DigestUpdate(digestParam, content, chunkSize);
20154aa6d63Sopenharmony_ci    munmap(mmapInfo.mapAddr, mmapInfo.mmapSize);
20254aa6d63Sopenharmony_ci    return res;
20354aa6d63Sopenharmony_ci}
20454aa6d63Sopenharmony_ci}
20554aa6d63Sopenharmony_ci}