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