1 /*
2 * Copyright (c) 2024-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 "verify_code_signature.h"
16 #include "elf_sign_block.h"
17 #include "constant.h"
18
19 namespace OHOS {
20 namespace SignatureTools {
VerifyHap(std::string file, int64_t offset, int64_t length, std::string fileFormat, std::string profileContent)21 bool VerifyCodeSignature::VerifyHap(std::string file, int64_t offset, int64_t length,
22 std::string fileFormat, std::string profileContent)
23 {
24 std::string fileFromatTmp = fileFormat;
25 std::transform(fileFromatTmp.begin(), fileFromatTmp.end(), fileFromatTmp.begin(), ::tolower);
26 if (std::find(CodeSigning::SUPPORT_FILE_FORM.begin(), CodeSigning::SUPPORT_FILE_FORM.end(),
27 fileFromatTmp) == CodeSigning::SUPPORT_FILE_FORM.end()) {
28 SIGNATURE_TOOLS_LOGI("Not hap, hsp or hqf file, skip code signing verify, file type: %s",
29 fileFromatTmp.c_str());
30 return true;
31 }
32 // 1) generate CodeSignBlock
33 std::pair<std::string, std::string> pairResult = HapUtils::ParseAppIdentifier(profileContent);
34 CodeSignBlock csb;
35 bool generateFlag = GenerateCodeSignBlock(file, offset, length, csb);
36 if (!generateFlag) {
37 SIGNATURE_TOOLS_LOGE("VerifyHap GenerateCodeSignBlock failed, file: %s", file.c_str());
38 return false;
39 }
40 // 2) verify hap
41 bool verifyFlag = VerifyCodeSign(file, pairResult, csb);
42 if (!verifyFlag) {
43 SIGNATURE_TOOLS_LOGE("VerifyHap VerifyCodeSign failed");
44 return false;
45 }
46 return true;
47 }
48
VerifyElf(std::string file, int64_t offset, int64_t length, std::string fileFormat, std::string profileContent)49 bool VerifyCodeSignature::VerifyElf(std::string file, int64_t offset, int64_t length,
50 std::string fileFormat, std::string profileContent)
51 {
52 std::transform(fileFormat.begin(), fileFormat.end(), fileFormat.begin(), ::tolower);
53 if (ELF != fileFormat) {
54 SIGNATURE_TOOLS_LOGI("Not elf file, skip code signing verify, file type: %s", fileFormat.c_str());
55 return true;
56 }
57 // 1) parse sign block to ElfSignBlock object
58 std::ifstream signedElf(file, std::ios::binary);
59 if (!signedElf.is_open()) {
60 PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "open file: " + file + "failed");
61 return false;
62 }
63 signedElf.seekg(offset, std::ios::beg);
64 std::vector<char> codeSignBlockBytes(length);
65 signedElf.read(codeSignBlockBytes.data(), codeSignBlockBytes.size());
66 signedElf.close();
67 ElfSignBlock elfSignBlock;
68 bool arrFlag = ElfSignBlock::FromByteArray(*(std::vector<int8_t> *) & codeSignBlockBytes, elfSignBlock);
69 if (!arrFlag) {
70 SIGNATURE_TOOLS_LOGE("parse sign block to ElfCodeSignBlock object failed");
71 return false;
72 }
73 // 2) verify file data
74 int32_t paddingSize = ElfSignBlock::ComputeMerkleTreePaddingLength(offset);
75 std::vector<int8_t> &merkleTreeWithPadding = elfSignBlock.GetMerkleTreeWithPadding();
76 std::vector<int8_t> merkleTree;
77 merkleTree.insert(merkleTree.end(), merkleTreeWithPadding.begin() + paddingSize, merkleTreeWithPadding.end());
78 std::ifstream elf(file, std::ios::binary);
79 bool verifySingleFileFlag = VerifySingleFile(elf, elfSignBlock.GetDataSize(), elfSignBlock.GetSignature(),
80 elfSignBlock.GetTreeOffset(), merkleTree);
81 if (!verifySingleFileFlag) {
82 SIGNATURE_TOOLS_LOGE("verify elf file data failed");
83 elf.close();
84 return false;
85 }
86 elf.close();
87 // 3) check ownerID
88 if (!profileContent.empty()) {
89 std::pair<std::string, std::string> pairResult = HapUtils::ParseAppIdentifier(profileContent);
90 std::vector<int8_t>& signature = elfSignBlock.GetSignature();
91 std::string signatureStr(signature.begin(), signature.end());
92 bool checkOwnerIDFlag = CmsUtils::CheckOwnerID(signatureStr, pairResult.first, pairResult.second);
93 if (!checkOwnerIDFlag) {
94 SIGNATURE_TOOLS_LOGE("elf check owner id failed");
95 return false;
96 }
97 }
98 return true;
99 }
100
VerifyNativeLib(CodeSignBlock& csb, std::string& file, unzFile& zFile, std::pair<std::string, std::string>& pairResult)101 bool VerifyCodeSignature::VerifyNativeLib(CodeSignBlock& csb, std::string& file, unzFile& zFile,
102 std::pair<std::string, std::string>& pairResult)
103 {
104 UnzipHandleParam param(csb, pairResult, false);
105 CodeSigning codeSigning;
106 bool nativeFlag = codeSigning.GetNativeEntriesFromHap(file, param);
107 if (!nativeFlag) {
108 SIGNATURE_TOOLS_LOGE("verify native libs failed, file: %s", file.c_str());
109 return false;
110 }
111 return true;
112 }
113
VerifyCodeSign(std::string file, std::pair<std::string, std::string>& pairResult, CodeSignBlock& csb)114 bool VerifyCodeSignature::VerifyCodeSign(std::string file, std::pair<std::string, std::string>& pairResult,
115 CodeSignBlock& csb)
116 {
117 // 1) verify hap
118 std::ifstream hap(file, std::ios::binary);
119 if (!hap.is_open()) {
120 PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "open file: " + file + "failed");
121 return false;
122 }
123 int64_t dataSize = csb.GetHapInfoSegment().GetSignInfo().GetDataSize();
124 std::vector<int8_t> signature = csb.GetHapInfoSegment().GetSignInfo().GetSignature();
125 Extension* ext = csb.GetHapInfoSegment().GetSignInfo()
126 .GetExtensionByType(MerkleTreeExtension::MERKLE_TREE_INLINED);
127 MerkleTreeExtension* mte = new MerkleTreeExtension(0, 0, std::vector<int8_t>());
128 if (mte == nullptr) {
129 PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "system failed to allocate memory for MerkleTreeExtension");
130 return false;
131 }
132 if (ext != nullptr) {
133 delete mte;
134 mte = (MerkleTreeExtension*)(ext);
135 } else {
136 std::shared_ptr<MerkleTreeExtension> merkleTreeExt(mte);
137 }
138 // temporary: merkle tree offset set to zero, change to merkleTreeOffset
139 bool verifyFlag = VerifySingleFile(hap, dataSize, signature, mte->GetMerkleTreeOffset(),
140 csb.GetOneMerkleTreeByFileName(CodeSigning::HAP_SIGNATURE_ENTRY_NAME));
141 if (!verifyFlag) {
142 return false;
143 }
144 hap.close();
145 std::string signature_(signature.begin(), signature.end());
146 bool checkOwnerIDFlag = CmsUtils::CheckOwnerID(signature_, pairResult.first, pairResult.second);
147 if (!checkOwnerIDFlag) {
148 return false;
149 }
150 // 2) verify native libs
151 unzFile zFile = unzOpen(file.c_str());
152 if (zFile == NULL) {
153 PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "unzOpen file: " + file + "failed");
154 return false;
155 }
156 bool verifyNativeLibFlag = VerifyNativeLib(csb, file, zFile, pairResult);
157 if (!verifyNativeLibFlag) {
158 return false;
159 }
160 unzClose(zFile);
161 return true;
162 }
163
VerifySingleFile(std::istream& input, int64_t length, std::vector<int8_t> signature, int64_t merkleTreeOffset, std::vector<int8_t> inMerkleTreeBytes)164 bool VerifyCodeSignature::VerifySingleFile(std::istream& input, int64_t length,
165 std::vector<int8_t> signature,
166 int64_t merkleTreeOffset,
167 std::vector<int8_t> inMerkleTreeBytes)
168 {
169 std::pair<std::vector<int8_t>, std::vector<int8_t>> pairResult
170 = GenerateFsVerityDigest(input, length, merkleTreeOffset);
171 std::vector<int8_t> generatedMerkleTreeBytes = pairResult.second;
172 // For native libs, inMerkleTreeBytes is null, skip check here
173 bool verifyFlag = (!inMerkleTreeBytes.empty()) && !AreVectorsEqual(inMerkleTreeBytes, generatedMerkleTreeBytes);
174 if (verifyFlag) {
175 PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "verify merkle tree bytes failed");
176 return false;
177 }
178 return CmsUtils::VerifySignDataWithUnsignedDataDigest(pairResult.first, signature);
179 }
180
GenerateCodeSignBlock(const std::string& file, int64_t offset, int64_t length, CodeSignBlock& csb)181 bool VerifyCodeSignature::GenerateCodeSignBlock(const std::string& file, int64_t offset,
182 int64_t length, CodeSignBlock& csb)
183 {
184 // 1) parse sign block to CodeSignBlock object
185 std::ifstream signedHap(file, std::ios::binary);
186 if (!signedHap.is_open()) {
187 PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "open file: " + file + "failed");
188 return false;
189 }
190 int32_t fileReadOffset = 0;
191 // 1.1) skip data part, but fileReadOffset remains at start(0)
192 signedHap.seekg(offset, std::ios::beg);
193 // 1.2) parse codeSignBlockHeader
194 std::vector<char> codeSignBlockHeaderByteArray(CodeSignBlockHeader::Size());
195 signedHap.read(codeSignBlockHeaderByteArray.data(), codeSignBlockHeaderByteArray.size());
196 fileReadOffset += signedHap.gcount();
197 CodeSignBlockHeader* pCodeSignBlockHeader =
198 CodeSignBlockHeader::FromByteArray(*(std::vector<int8_t>*) &codeSignBlockHeaderByteArray);
199 if (pCodeSignBlockHeader == nullptr) {
200 SIGNATURE_TOOLS_LOGE("Invalid code Sign block header");
201 signedHap.close();
202 return false;
203 }
204 std::shared_ptr<CodeSignBlockHeader> codeSignBlockHeader(pCodeSignBlockHeader);
205 csb.SetCodeSignBlockHeader(*codeSignBlockHeader);
206 int64_t headerBlockSize = csb.GetCodeSignBlockHeader().GetBlockSize();
207 if (headerBlockSize != length) {
208 PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR,
209 "Invalid code Sign block size of setCodeSignBlockHeader");
210 signedHap.close();
211 return false;
212 }
213 // 2) parse segment headers
214 for (int i = 0; i < csb.GetCodeSignBlockHeader().GetSegmentNum(); i++) {
215 std::vector<char> segmentHeaderByteArray(SegmentHeader::SEGMENT_HEADER_LENGTH);
216 signedHap.read(segmentHeaderByteArray.data(), segmentHeaderByteArray.size());
217 fileReadOffset += signedHap.gcount();
218 csb.AddToSegmentList(*SegmentHeader::FromByteArray(*(std::vector<int8_t> *) &segmentHeaderByteArray));
219 }
220 // compute merkle tree offset by alignment, based on file start
221 int64_t computedTreeOffset = GetAlignmentAddr(CodeSignBlock::PAGE_SIZE_4K, fileReadOffset + offset);
222 // skip zero padding before merkle tree, adds zero padding length to fileReadOffset
223 signedHap.seekg(computedTreeOffset - offset - fileReadOffset, std::ios::cur);
224 fileReadOffset += computedTreeOffset - offset - fileReadOffset;
225 bool parseMerkleTreeFlag = ParseMerkleTree(csb, fileReadOffset, signedHap, computedTreeOffset);
226 if (!parseMerkleTreeFlag) {
227 SIGNATURE_TOOLS_LOGE("GenerateCodeSignBlock parse merkle tree failed.");
228 return false;
229 }
230 signedHap.close();
231 return true;
232 }
233
ParseSegmentHead(CodeSignBlock& csb, std::ifstream& signedHap, std::vector<char> &merkleTreeBytes, int32_t &fileReadOffset)234 bool VerifyCodeSignature::ParseSegmentHead(CodeSignBlock& csb, std::ifstream& signedHap,
235 std::vector<char> &merkleTreeBytes, int32_t &fileReadOffset)
236 {
237 for (auto& segmentHeader : csb.GetSegmentHeaderList()) {
238 if (fileReadOffset > segmentHeader.GetSegmentOffset()) {
239 PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "Invaild offset of merkle tree and segment header");
240 return false;
241 }
242 // get merkle tree bytes
243 if (fileReadOffset < segmentHeader.GetSegmentOffset()) {
244 merkleTreeBytes.resize(segmentHeader.GetSegmentOffset() - fileReadOffset);
245 signedHap.read(merkleTreeBytes.data(), merkleTreeBytes.size());
246 fileReadOffset += signedHap.gcount();
247 }
248 std::vector<char> sh(segmentHeader.GetSegmentSize(), 0);
249 signedHap.read(sh.data(), sh.size());
250 fileReadOffset += signedHap.gcount();
251 int32_t type = segmentHeader.GetType();
252 if (type == SegmentHeader::CSB_FSVERITY_INFO_SEG) {
253 // 3) parse fs-verity info segment
254 FsVerityInfoSegment fsVerityInfoSegment =
255 FsVerityInfoSegment::FromByteArray(*(std::vector<int8_t> *) & sh);
256 csb.SetFsVerityInfoSegment(fsVerityInfoSegment);
257 } else if (type == SegmentHeader::CSB_HAP_META_SEG) {
258 // 4) parse hap info segment
259 HapInfoSegment hapInfoSegment = HapInfoSegment::FromByteArray(*(std::vector<int8_t> *) & sh);
260 csb.SetHapInfoSegment(hapInfoSegment);
261 } else if (type == SegmentHeader::CSB_NATIVE_LIB_INFO_SEG) {
262 // 5) parse so info segment
263 NativeLibInfoSegment nativeLibInfoSegment =
264 NativeLibInfoSegment::FromByteArray(*(std::vector<int8_t> *) & sh);
265 csb.SetSoInfoSegment(nativeLibInfoSegment);
266 }
267 }
268
269 return true;
270 }
271
ParseMerkleTree(CodeSignBlock& csb, int32_t readOffset, std::ifstream& signedHap, int64_t computedTreeOffset)272 bool VerifyCodeSignature::ParseMerkleTree(CodeSignBlock& csb, int32_t readOffset, std::ifstream& signedHap,
273 int64_t computedTreeOffset)
274 {
275 std::vector<char> merkleTreeBytes;
276 int32_t fileReadOffset = readOffset;
277 bool parseFlag = ParseSegmentHead(csb, signedHap, merkleTreeBytes, fileReadOffset);
278 if (!parseFlag) {
279 SIGNATURE_TOOLS_LOGE("ParsesegmentHead failed");
280 return false;
281 }
282 int32_t blockSize = csb.GetCodeSignBlockHeader().GetBlockSize();
283 if (fileReadOffset != blockSize) {
284 PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR,
285 "Invalid blockSize of getCodeSignBlockHeader");
286 return false;
287 }
288 // parse merkle tree
289 Extension* extension = csb.GetHapInfoSegment().GetSignInfo().
290 GetExtensionByType(MerkleTreeExtension::MERKLE_TREE_INLINED);
291 if (!extension) {
292 SIGNATURE_TOOLS_LOGE("Missing merkleTreeExtension in verifycation");
293 return false;
294 }
295 MerkleTreeExtension* mte = (MerkleTreeExtension*)(extension);
296 if (mte) {
297 bool merkleTreeFlag = computedTreeOffset != mte->GetMerkleTreeOffset() ||
298 merkleTreeBytes.size() != mte->GetMerkleTreeSize();
299 if (merkleTreeFlag) {
300 PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "Invalid merkle tree offset or tree size");
301 return false;
302 }
303 csb.AddOneMerkleTree(CodeSigning::HAP_SIGNATURE_ENTRY_NAME, *(std::vector<int8_t> *) &merkleTreeBytes);
304 }
305 return true;
306 }
307
GetAlignmentAddr(int64_t alignment, int64_t input)308 int64_t VerifyCodeSignature::GetAlignmentAddr(int64_t alignment, int64_t input)
309 {
310 if (alignment == 0) {
311 return input;
312 }
313 int64_t residual = input % alignment;
314 if (residual == 0) {
315 return input;
316 } else {
317 return input + (alignment - residual);
318 }
319 }
320
GenerateFsVerityDigest( std::istream& inputStream, int64_t size, int64_t merkleTreeOffset)321 std::pair<std::vector<int8_t>, std::vector<int8_t>> VerifyCodeSignature::GenerateFsVerityDigest(
322 std::istream& inputStream, int64_t size, int64_t merkleTreeOffset)
323 {
324 std::unique_ptr<FsVerityGenerator> fsVerityGenerator = std::make_unique<FsVerityGenerator>();
325 fsVerityGenerator->GenerateFsVerityDigest(inputStream, size, merkleTreeOffset);
326 return std::make_pair(fsVerityGenerator->GetFsVerityDigest(), fsVerityGenerator->GetTreeBytes());
327 }
328
AreVectorsEqual(const std::vector<int8_t>& vec1, const std::vector<int8_t>& vec2)329 bool VerifyCodeSignature::AreVectorsEqual(const std::vector<int8_t>& vec1, const std::vector<int8_t>& vec2)
330 {
331 if (vec1.size() != vec2.size()) {
332 return false;
333 }
334 for (int64_t i = 0; i < vec1.size(); i++) {
335 if (vec1[i] != vec2[i]) {
336 return false;
337 }
338 }
339 return true;
340 }
341 } // namespace SignatureTools
342 } // namespace OHOS