1/*
2 * Copyright (c) 2023 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
16#ifndef CODE_SIGN_BLOCK_H
17#define CODE_SIGN_BLOCK_H
18
19#include <cstdint>
20#include <cstdlib>
21#include <string>
22#include <vector>
23#include <unordered_map>
24#include <mutex>
25#include <linux/fsverity.h>
26#include "code_sign_utils.h"
27#include "interfaces/hap_verify.h"
28#include "interfaces/hap_verify_result.h"
29
30namespace OHOS {
31namespace Security {
32namespace CodeSign {
33
34#pragma pack(push, 1)
35typedef struct {
36    uint32_t type;
37    uint32_t size;
38    uint32_t offset;
39} PropertyBlobHeader;
40
41typedef struct {
42    uint64_t magic;
43    uint32_t version;
44    uint32_t blockSize;
45    uint32_t segmentNum;
46    uint32_t flags;
47    uint8_t  reserved[8];
48} CodeSignBlockHeader;
49
50typedef struct {
51    uint32_t type;
52    uint32_t offset;
53    uint32_t size;
54} SegmentHeader;
55
56typedef struct {
57    uint32_t magic;
58    uint8_t  version;
59    uint8_t  hashAlgorithm;
60    uint8_t  logBlockSize;
61    uint8_t  reserved[1];
62} FsVerityInfo;
63
64typedef struct {
65    uint32_t type;
66    uint32_t size;
67} ExtensionHeader;
68
69typedef struct {
70    uint64_t treeSize;
71    uint64_t treeOffset;
72    uint8_t  rootHash[64];
73} MerkleTreeExtension;
74
75typedef struct {
76    uint64_t mapOffset;
77    uint64_t mapSize;
78    uint8_t  unitSize;
79    uint8_t  reversed[3];
80    uint32_t sign_size;
81    uint8_t  signature[0];
82} PageInfoExtension;
83
84typedef struct {
85    uint32_t saltSize;
86    uint32_t signSize;
87    uint32_t flags;
88    uint64_t dataSize;
89    uint8_t  salt[32];
90    uint32_t extensionNum;
91    uint32_t extensionOffset;
92    uint8_t  signature[0];
93} SignInfo;
94
95typedef struct {
96    uint32_t magic;
97    SignInfo signInfo;
98} HapSignInfo;
99
100typedef struct {
101    uint32_t fileNameOffset;
102    uint32_t fileNameSize;
103    uint32_t signOffset;
104    uint32_t signSize;
105} EntryInfo;
106
107typedef struct {
108    uint32_t  magic;
109    uint32_t  length;
110    uint32_t  sectionNum;
111    EntryInfo info[0];
112} NativeLibSignInfo;
113#pragma pack(pop)
114
115using SignMap = std::unordered_map<std::string, uintptr_t>;
116using ReadBuffer = const char *;
117#define CONST_STATIC_CAST(type, ptr) static_cast<const type *>(static_cast<const void *>(ptr))
118
119class CodeSignBlock {
120public:
121    CodeSignBlock();
122    ~CodeSignBlock();
123
124    static constexpr uint64_t CSB_BLOCK_HEADER_MAGIC = 0xE046C8C65389FCCD;
125    static constexpr uint32_t CSB_FSVERITY_MAGIC = 0x1E3831AB;
126    static constexpr uint32_t CSB_HAP_HEADER_MAGIC = 0xC1B5CC66;
127    static constexpr uint32_t CSB_SO_HEADER_MAGIC = 0xED2E720;
128    static constexpr uint32_t CSB_SIGN_INFO_MERKLE_TREE = 0x1;
129    static constexpr uint32_t CSB_SIGN_INFO_RUNTIME_PAGE = 0x2;
130    static constexpr uint32_t CSB_EXTENSION_TYPE_MERKLE_TREE = 1;
131    static constexpr uint32_t CSB_EXTENSION_TYPE_PAGE_INFO = 2;
132    static constexpr uint32_t CSB_SIGN_INFO_MAX_PAGEINFO_UNITSIZE = 7;
133    static constexpr uint32_t CSB_EXTENSION_TYPE_PAGE_INFO_VERSION = 2;
134
135    int32_t ParseCodeSignBlock(const std::string &realPath, const EntryMap &entryMap, FileType fileType);
136    int32_t GetOneFileAndCodeSignInfo(std::string &targetFile, struct code_sign_enable_arg &arg);
137    int32_t ProcessExtension(uintptr_t &extensionAddr, const uintptr_t blockAddrEnd, struct code_sign_enable_arg &arg);
138
139private:
140    int32_t ParseNativeLibSignInfo(const EntryMap &entryMap);
141    int32_t ParseHapSignInfo(const std::string &path);
142    int32_t ParseCodeSignBlockBaseInfo(ReadBuffer codeSignBlock, uint32_t &blockSize);
143    int32_t GetCodeSignBlockBuffer(const std::string &path, ReadBuffer &signBuffer, uint32_t &size);
144
145    static constexpr uint32_t CSB_HEADER_VERSION = 1;
146    static constexpr uint32_t CSB_HEADER_FLAG_MERKLE_TREE = 0x1;
147    static constexpr uint32_t CSB_HEADER_FLAG_SO = 0x2;
148    static constexpr uint32_t CSB_FSVERITY_INFO_SEG = 0x1;
149    static constexpr uint32_t CSB_HAP_META_SEG = 0x2;
150    static constexpr uint32_t CSB_NATIVE_LIB_INFO_SEG = 0x3;
151    static constexpr uint32_t CSB_SEGMENT_MAX = 3;
152    static constexpr uint32_t CSB_FSVERITY_BLOCK_SIZE = 12;
153
154    const CodeSignBlockHeader *GetCodeSignBlockHeader(void)
155    {
156        return blockHeader_;
157    }
158    const FsVerityInfo *GetFsVerityInfo(void)
159    {
160        return fsVerityInfo_;
161    }
162    const HapSignInfo *GetHapSignInfo(void)
163    {
164        return hapSignInfo_;
165    }
166    const NativeLibSignInfo *GetNativeLibSignInfo(void)
167    {
168        return nativeLibSignInfo_;
169    }
170
171    int32_t SetCodeSignBlockHeader(const CodeSignBlockHeader *header, uint32_t &blockSize)
172    {
173        if (header->magic != CSB_BLOCK_HEADER_MAGIC) {
174            return CS_ERR_BLOCK_MAGIC;
175        }
176        if (header->version != CSB_HEADER_VERSION) {
177            return CS_ERR_BLOCK_VERSION;
178        }
179        if ((header->segmentNum > CSB_SEGMENT_MAX) || (header->segmentNum == 0)) {
180            return CS_ERR_BLOCK_SEG_NUM;
181        }
182        if (header->blockSize != blockSize) {
183            return CS_ERR_BLOCK_SIZE;
184        }
185        blockHeader_ = header;
186        return CS_SUCCESS;
187    }
188
189    int32_t SetFsVerityInfo(const FsVerityInfo *info)
190    {
191        if (info->magic != CSB_FSVERITY_MAGIC) {
192            return CS_ERR_FSVERITY_MAGIC;
193        }
194        if (info->version != 1) {
195            return CS_ERR_FSVERITY_VERSION;
196        }
197        if (info->logBlockSize != CSB_FSVERITY_BLOCK_SIZE) {
198            return CS_ERR_FSVERITY_BLOCK_SIZE;
199        }
200        fsVerityInfo_ = info;
201        return CS_SUCCESS;
202    }
203
204    int32_t SetHapSignInfo(const HapSignInfo *info)
205    {
206        if (info->magic != CSB_HAP_HEADER_MAGIC) {
207            return CS_ERR_HAP_MAGIC;
208        }
209        const auto signInfo = &info->signInfo;
210        if (blockHeader_->flags & CSB_HEADER_FLAG_MERKLE_TREE) {
211            if (signInfo->extensionOffset >= blockHeader_->blockSize) {
212                return CS_ERR_HAP_EXTERNSION;
213            }
214        }
215        hapSignInfo_ = info;
216        return CS_SUCCESS;
217    }
218
219    int32_t SetNativeLibSignInfo(const NativeLibSignInfo *info)
220    {
221        if (info->magic != CSB_SO_HEADER_MAGIC) {
222            return CS_ERR_SO_MAGIC;
223        }
224        if ((blockHeader_->flags & CSB_HEADER_FLAG_SO) && !info->sectionNum) {
225            return CS_ERR_SO_SECTION_NUM;
226        }
227        nativeLibSignInfo_ = info;
228        return CS_SUCCESS;
229    }
230
231    int32_t GetOneMapNodeFromSignMap(std::string &fileName, uintptr_t &signInfo)
232    {
233        std::lock_guard<std::mutex> guard(signMapMutex_);
234        if (signMap_.empty()) {
235            return CS_SUCCESS_END;
236        }
237
238        auto info = signMap_.begin();
239        fileName = info->first;
240        signInfo = info->second;
241        signMap_.erase(fileName);
242        return CS_SUCCESS;
243    }
244
245    Verify::SignatureInfo signatureInfo_;
246    const CodeSignBlockHeader *blockHeader_ = nullptr;
247    const FsVerityInfo *fsVerityInfo_ = nullptr;
248    const HapSignInfo *hapSignInfo_ = nullptr;
249    const NativeLibSignInfo *nativeLibSignInfo_ = nullptr;
250    std::mutex signMapMutex_;
251    SignMap signMap_;
252};
253} // CodeSign namespace
254} // Security namespace
255} // OHOS namespace
256#endif
257