• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 #include "elf_code_sign_block_v1.h"
17 #include <filesystem>
18 #include <fstream>
19 #include <securec.h>
20 
21 #include "constants.h"
22 #include "directory_ex.h"
23 #include "log.h"
24 
25 namespace OHOS {
26 namespace Security {
27 namespace CodeSign {
28 
ElfCodeSignBlockV1()29 ElfCodeSignBlockV1::ElfCodeSignBlockV1()
30 {
31 }
32 
~ElfCodeSignBlockV1()33 ElfCodeSignBlockV1::~ElfCodeSignBlockV1()
34 {
35 }
36 
EnforceCodeSign(const std::string & realPath,CallbackFunc & func)37 int32_t ElfCodeSignBlockV1::EnforceCodeSign(const std::string &realPath, CallbackFunc &func)
38 {
39     int32_t ret = ParseSignBlock(realPath);
40     if (ret != CS_SUCCESS) {
41         return ret;
42     }
43     auto signInfo = signInfoSeg_;
44     struct code_sign_enable_arg arg = {0};
45     arg.version = 1;
46     arg.cs_version = signInfo->csVersion;
47     arg.hash_algorithm = signInfo->hashAlgorithm;
48     arg.block_size = 1 << signInfo->logBlockSize;
49     arg.salt_ptr = reinterpret_cast<uintptr_t>(signInfo->salt);
50     arg.salt_size = signInfo->saltSize;
51     arg.sig_size = signInfo->signSize;
52     arg.sig_ptr = reinterpret_cast<uintptr_t>(signInfo->signature);
53     arg.data_size = signInfo->dataSize;
54     arg.tree_offset = signInfo->treeOffset;
55     arg.root_hash_ptr = reinterpret_cast<uintptr_t>(signInfo->rootHash);
56     arg.flags |= signInfo->flags;
57     return func(realPath, arg);
58 }
59 
ParseSignBlock(const std::string & realPath)60 int32_t ElfCodeSignBlockV1::ParseSignBlock(const std::string &realPath)
61 {
62     LOG_INFO("Start to parse sign block v1");
63     // open file
64     std::ifstream fileStream(realPath, std::ios::in | std::ios::binary);
65     if (!fileStream.is_open()) {
66         LOG_ERROR("open file failed,code = %{public}d, path = %{public}s", fileStream.rdstate(), realPath.c_str());
67         fileStream.close();
68         return CS_ERR_FILE_READ;
69     }
70     uint32_t elfMagicLen = sizeof(ELF_HEADER_MAGIC) / sizeof(uint8_t);
71     std::unique_ptr<uint8_t[]> fileHeaderMagic = std::make_unique<uint8_t[]>(elfMagicLen);
72     fileStream.read(reinterpret_cast<char *>(fileHeaderMagic.get()), elfMagicLen);
73     if (std::memcmp(fileHeaderMagic.get(), ELF_HEADER_MAGIC, elfMagicLen) != 0) {
74         fileStream.close();
75         return CS_ERR_FILE_INVALID;
76     }
77     auto fileSize = std::filesystem::file_size(realPath);
78     if (fileSize < SIGN_BLOCK_HEADER_SIZE) {
79         LOG_ERROR("file size is too small");
80         fileStream.close();
81         return CS_CODE_SIGN_NOT_EXISTS;
82     }
83     int32_t ret = ReadFile(fileStream, fileSize);
84     fileStream.close();
85     LOG_DEBUG("ifstream close");
86     if (ret != CS_SUCCESS) {
87         return ret;
88     }
89     ret = ParseSignData();
90     return ret;
91 }
92 
ReadFile(std::ifstream & fileStream,uintmax_t fileSize)93 int32_t ElfCodeSignBlockV1::ReadFile(std::ifstream &fileStream, uintmax_t fileSize)
94 {
95     // parse sign header
96     fileStream.clear();
97     fileStream.seekg(-SIGN_BLOCK_HEADER_SIZE, std::ios::end);
98     signHeaderBuffer_ = std::make_unique<uint8_t[]>(SIGN_BLOCK_HEADER_SIZE);
99     fileStream.read(reinterpret_cast<char *>(signHeaderBuffer_.get()), SIGN_BLOCK_HEADER_SIZE);
100     long readCount = fileStream.gcount();
101     if (readCount != SIGN_BLOCK_HEADER_SIZE) {
102         LOG_ERROR("read sign block header failed : %{public}ld", readCount);
103         return CS_ERR_FILE_READ;
104     }
105     auto signHeader = reinterpret_cast<const ElfSignHeader *>(signHeaderBuffer_.get());
106     if (std::memcmp(signHeader->magic, SIGN_HEADER_MAGIC, sizeof(SIGN_HEADER_MAGIC) / sizeof(uint8_t)) != 0) {
107         return CS_ERR_BLOCK_MAGIC;
108     }
109     if (std::memcmp(signHeader->version, SIGN_HEADER_VERSION, sizeof(SIGN_HEADER_VERSION) / sizeof(uint8_t)) != 0) {
110         return CS_ERR_BLOCK_VERSION;
111     }
112     if (signHeader->blockNum < 1 || signHeader->blockNum > SIGN_BLOCK_NUM_MAX) {
113         return CS_ERR_BLOCK_SEG_NUM;
114     }
115     if (fileSize - SIGN_BLOCK_HEADER_SIZE < signHeader->blockSize) {
116         return CS_ERR_BLOCK_SIZE;
117     }
118     if (signHeader->blockNum * sizeof(ElfBlockHeader) > signHeader->blockSize) {
119         return CS_ERR_BLOCK_SIZE;
120     }
121     fileStream.clear();
122     int len = SIGN_BLOCK_HEADER_SIZE + signHeader->blockSize;
123     fileStream.seekg(-len, std::ios::end);
124     signBlockBuffer_ = std::make_unique<uint8_t[]>(signHeader->blockSize);
125     fileStream.read(reinterpret_cast<char *>(signBlockBuffer_.get()), signHeader->blockSize);
126     readCount = fileStream.gcount();
127     if (static_cast<uint32_t>(readCount) != signHeader->blockSize) {
128         LOG_ERROR("read sign block failed : %{public}ld", readCount);
129         return CS_ERR_FILE_READ;
130     }
131     signHeader_ = signHeader;
132     return CS_SUCCESS;
133 }
134 
ParseSignData()135 int32_t ElfCodeSignBlockV1::ParseSignData()
136 {
137     // parse block header
138     uint32_t off = 0;
139     for (uint32_t i = 0; i < signHeader_->blockNum; i++) {
140         uint32_t pos = i * sizeof(ElfBlockHeader);
141         auto blockHeader = reinterpret_cast<const ElfBlockHeader *>(signBlockBuffer_.get() + pos);
142         if (blockHeader->type == CSB_HEADER_TYPE) {
143             off = blockHeader->offset;
144             break;
145         }
146     }
147     if (off == 0 || off >= signHeader_->blockSize) {
148         return CS_ERR_SIGN_INFO_OFFSET;
149     }
150     // parse merkle tree segment
151     auto merkleTreeSeg = reinterpret_cast<const ElfMerkleTreeSegment *>(signBlockBuffer_.get() + off);
152     if (merkleTreeSeg->type != CSB_MERKLE_TREE_TYPE) {
153         return CS_ERR_MERKLE_TREE_TYPE;
154     }
155     if (merkleTreeSeg->length > (signHeader_->blockSize - off)) {
156         return CS_ERR_MERKLE_TREE_SIZE;
157     }
158     // parse sign info segment
159     off += sizeof(ElfMerkleTreeSegment) + merkleTreeSeg->length;
160     auto signInfo = reinterpret_cast<const ElfSignInfoSegment *>(signBlockBuffer_.get() + off);
161     if (signInfo->type != CSB_FS_VERITY_DESCRIPTOR_TYPE) {
162         return CS_ERR_SEGMENT_FSVERITY_TYPE;
163     }
164     if (signInfo->length > (signHeader_->blockSize - off)) {
165         return CS_ERR_SIGN_INFO_SIZE;
166     }
167     if (signInfo->version != 1) {
168         return CS_ERR_FSVERITY_VERSION;
169     }
170     if (signInfo->logBlockSize != CSB_FSVERITY_BLOCK_SIZE) {
171         return CS_ERR_FSVERITY_BLOCK_SIZE;
172     }
173     if (signInfo->signSize >= signInfo->length) {
174         return CS_ERR_SIGN_SIZE;
175     }
176     signInfoSeg_ = signInfo;
177     return CS_SUCCESS;
178 }
179 } // CodeSign namespace
180 } // Security namespace
181 } // OHOS namespace
182