1/*
2 * Copyright (c) 2023-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15#include "fsverity_utils_helper.h"
16#include <common_defs.h>
17#include <fcntl.h>
18#include <fsverity_uapi.h>
19#include <sys/types.h>
20#include <unistd.h>
21#include "errcode.h"
22#include "file_helper.h"
23#include "log.h"
24
25namespace OHOS {
26namespace Security {
27namespace CodeSign {
28static constexpr int MAX_DIGEST_SIZE = 64; // size of sha512
29static constexpr int FSVERITY_HASH_PAGE_SIZE = 4096;
30static const char *FSVERITY_DIGEST_MAGIC = "FSVerity";
31static constexpr uint32_t FSVERITY_DIGEST_MAGIC_LENGTH = 8;
32
33FsverityUtilsHelper &FsverityUtilsHelper::GetInstance()
34{
35    static FsverityUtilsHelper singleFsverityUtilsHelper;
36    return singleFsverityUtilsHelper;
37}
38
39FsverityUtilsHelper::FsverityUtilsHelper()
40{
41    Init();
42}
43
44FsverityUtilsHelper::~FsverityUtilsHelper() {}
45
46void FsverityUtilsHelper::Init()
47{
48    libfsverity_set_error_callback(ErrorMsgLogCallback);
49}
50
51void FsverityUtilsHelper::ErrorMsgLogCallback(const char *msg)
52{
53    LOG_ERROR("fsverity_utils error = %{public}s", msg);
54}
55
56bool FsverityUtilsHelper::FormatDigest(libfsverity_digest *digest, uint8_t *buffer)
57{
58    struct fsverity_formatted_digest *ret = reinterpret_cast<struct fsverity_formatted_digest *>(buffer);
59    if (memcpy_s(ret->magic, FSVERITY_DIGEST_MAGIC_LENGTH, FSVERITY_DIGEST_MAGIC,
60        FSVERITY_DIGEST_MAGIC_LENGTH) != EOK) {
61        return false;
62    }
63    ret->digest_algorithm = cpu_to_le16(digest->digest_algorithm);
64    ret->digest_size = cpu_to_le16(digest->digest_size);
65    if (memcpy_s(ret->digest, MAX_DIGEST_SIZE, digest->digest, digest->digest_size) != EOK) {
66        return false;
67    }
68    return true;
69}
70
71bool FsverityUtilsHelper::ComputeDigest(const char *path, struct libfsverity_digest **digest)
72{
73    struct libfsverity_merkle_tree_params tree_params = {
74        .version = 1,
75        .hash_algorithm = FS_VERITY_HASH_ALG_SHA256,
76        .block_size = FSVERITY_HASH_PAGE_SIZE
77    };
78
79    FileReader reader;
80    if (!reader.Open(path)) {
81        return false;
82    }
83    if (!reader.GetFileSize(&tree_params.file_size)) {
84        return false;
85    }
86    // compute digest by fsverity-utils and use callback to read data in file
87    if (libfsverity_compute_digest(&reader, FileReader::ReadFileCallback, &tree_params, digest)) {
88        LOG_ERROR("Compute digest failed.");
89        return false;
90    }
91    return true;
92}
93
94bool FsverityUtilsHelper::GenerateFormattedDigest(const char *path, ByteBuffer &digestBuffer)
95{
96    LOG_INFO("GenerateFormattedDigest called.");
97    struct libfsverity_digest *digest = nullptr;
98    if (!ComputeDigest(path, &digest)) {
99        return false;
100    }
101    uint32_t digestLen = sizeof(struct fsverity_formatted_digest) + digest->digest_size;
102    if (!digestBuffer.Resize(digestLen)) {
103        free(digest);
104        return false;
105    }
106    bool ret = FormatDigest(digest, digestBuffer.GetBuffer());
107    free(digest);
108    return ret;
109}
110}
111}
112}